Skip to content

Commit 364200a

Browse files
committed
Pass the label fields to the label_callback
Contao hands the prepared label fields to a label_callback as a fourth argument, and its own callbacks declare them as required - "tl_member::addIcon()" is one of several. We passed three, so every table carrying such a callback was fatal: picking from tl_member or tl_calendar_events ended in an ArgumentCountError instead of a list. Callbacks declaring only three parameters are unaffected; PHP passes the surplus argument and they never look at it. An array return value is now taken over whatever the list is grouped by. It was tied to the table mode before, so everywhere else the callback ran and its result was dropped. Matching those returned fields by position stays limited to the table mode, where both sides describe the same columns. Anywhere else they do not: a picker shows the one property it was configured with, while a Contao callback counts along its own "label/fields" - tl_member reserves the first of those for the icon and would push that markup into the picker's only column, replacing the very value one is meant to pick.
1 parent 9d18f2e commit 364200a

1 file changed

Lines changed: 36 additions & 16 deletions

File tree

src/Contao/Callback/ModelLabelCallbackListener.php

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ public function getArgs($event)
4545
$event->getModel()->getPropertiesAsArray(),
4646
$event->getLabel(),
4747
new DcCompat($event->getEnvironment(), $event->getModel()),
48+
// Contao hands the prepared label fields over as a fourth argument, and its own
49+
// callbacks declare them as required - "tl_member::addIcon()" is one of several.
50+
// Without it, every table carrying such a callback was fatal here. Callbacks that
51+
// declare only three parameters stay unaffected; PHP passes the surplus argument
52+
// and they never look at it.
53+
$event->getArgs(),
4854
];
4955
}
5056

@@ -53,17 +59,20 @@ public function getArgs($event)
5359
*/
5460
public function update($event, $value)
5561
{
56-
$groupingInformation = ViewHelpers::getGroupingMode($event->getEnvironment());
57-
if (
58-
isset($groupingInformation['mode'])
59-
&& ($groupingInformation['mode'] === GroupAndSortingInformationInterface::GROUP_NONE)
60-
) {
61-
if (!\is_array($value)) {
62-
return;
63-
}
62+
if (\is_array($value)) {
6463
/** @var list<string> $value */
6564

66-
$this->updateTableMode($event, $value);
65+
// An array means the callback handed the label fields back - regardless of how the
66+
// list happens to be grouped. Tying this to the table mode dropped the return value
67+
// everywhere else, which is why a Contao callback left the label empty.
68+
$groupingInformation = ViewHelpers::getGroupingMode($event->getEnvironment());
69+
$isTableMode =
70+
isset($groupingInformation['mode'])
71+
&& ($groupingInformation['mode'] === GroupAndSortingInformationInterface::GROUP_NONE);
72+
73+
$this->updateArguments($event, $value, $isTableMode);
74+
75+
return;
6776
}
6877

6978
if (!\is_string($value)) {
@@ -100,31 +109,42 @@ private function updateNonTableMode(ModelToLabelEvent $event, ?string $value): v
100109
}
101110

102111
/**
103-
* Set the value in the event.
112+
* Take the label fields a callback returned over into the event.
104113
*
105-
* @param ModelToLabelEvent $event The event being emitted.
106-
* @param string|list<string> $arguments The label arguments.
114+
* @param ModelToLabelEvent $event The event being emitted.
115+
* @param string|list<string> $arguments The label arguments.
116+
* @param bool $byPosition Whether numeric keys may be matched by position.
107117
*
108118
* @return void
109119
*/
110-
private function updateTableMode(ModelToLabelEvent $event, array|string $arguments): void
120+
private function updateArguments(ModelToLabelEvent $event, array|string $arguments, bool $byPosition): void
111121
{
112122
if (empty($arguments)) {
113123
return;
114124
}
115125

116126
$updateArguments = $event->getArgs();
117127

118-
// Step 1 update arguments by index as propertyName
119-
foreach ($event->getFormatter()->getPropertyNames() as $index => $propertyName) {
128+
// By name - this always means the same field on both sides.
129+
foreach ($event->getFormatter()->getPropertyNames() as $propertyName) {
120130
if (!isset($arguments[$propertyName])) {
121131
continue;
122132
}
123133

124134
$updateArguments[$propertyName] = $arguments[$propertyName];
125135
}
126136

127-
// Step 2 update arguments by index as integer
137+
// By position - only where both sides describe the same list of columns, which is the
138+
// table mode. Anywhere else the two have nothing to do with each other: a picker shows
139+
// the one property it was configured with, while a Contao callback counts along its own
140+
// "label/fields" - "tl_member" reserves the first of those for the icon and would push
141+
// that markup into the picker's only column, replacing the value one is meant to pick.
142+
if (!$byPosition) {
143+
$event->setArgs($updateArguments);
144+
145+
return;
146+
}
147+
128148
foreach ($event->getFormatter()->getPropertyNames() as $index => $propertyName) {
129149
if (!isset($arguments[$index])) {
130150
continue;

0 commit comments

Comments
 (0)