1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace DoctrineModule\Form\Element; |
6
|
|
|
|
7
|
|
|
use Doctrine\Common\Collections\Collection; |
8
|
|
|
use Doctrine\Common\Inflector\Inflector; |
9
|
|
|
use Doctrine\Persistence\ObjectManager; |
10
|
|
|
use DoctrineModule\Persistence\ObjectManagerAwareInterface; |
11
|
|
|
use Laminas\Stdlib\Guard\ArrayOrTraversableGuardTrait; |
12
|
|
|
use ReflectionMethod; |
13
|
|
|
use RuntimeException; |
14
|
|
|
use Traversable; |
15
|
|
|
use function array_change_key_case; |
16
|
|
|
use function array_key_exists; |
17
|
|
|
use function array_shift; |
18
|
|
|
use function call_user_func; |
19
|
|
|
use function count; |
20
|
|
|
use function current; |
21
|
|
|
use function get_class; |
22
|
|
|
use function gettype; |
23
|
|
|
use function interface_exists; |
24
|
|
|
use function is_callable; |
25
|
|
|
use function is_object; |
26
|
|
|
use function is_string; |
27
|
|
|
use function method_exists; |
28
|
|
|
use function sprintf; |
29
|
|
|
use function strtolower; |
30
|
|
|
use function trim; |
31
|
|
|
|
32
|
|
|
class Proxy implements ObjectManagerAwareInterface |
33
|
|
|
{ |
34
|
|
|
use ArrayOrTraversableGuardTrait; |
35
|
|
|
|
36
|
|
|
/** @var mixed[]|Traversable */ |
37
|
|
|
protected $objects; |
38
|
|
|
|
39
|
|
|
/** @var string */ |
40
|
|
|
protected $targetClass; |
41
|
|
|
|
42
|
|
|
/** @var mixed[] */ |
43
|
|
|
protected $valueOptions = []; |
44
|
|
|
|
45
|
|
|
/** @var mixed[] */ |
46
|
|
|
protected $findMethod = []; |
47
|
|
|
|
48
|
|
|
/** @var mixed */ |
49
|
|
|
protected $property; |
50
|
|
|
|
51
|
|
|
/** @var mixed[] */ |
52
|
|
|
protected $optionAttributes = []; |
53
|
|
|
|
54
|
|
|
/** @var callable $labelGenerator A callable used to create a label based on an item in the collection an Entity */ |
55
|
|
|
protected $labelGenerator; |
56
|
|
|
|
57
|
|
|
/** @var bool|null */ |
58
|
|
|
protected $isMethod; |
59
|
|
|
|
60
|
|
|
/** @var ObjectManager */ |
61
|
|
|
protected $objectManager; |
62
|
|
|
|
63
|
|
|
/** @var bool */ |
64
|
|
|
protected $displayEmptyItem = false; |
65
|
|
|
|
66
|
|
|
/** @var string */ |
67
|
|
|
protected $emptyItemLabel = ''; |
68
|
|
|
|
69
|
|
|
/** @var string|null */ |
70
|
|
|
protected $optgroupIdentifier; |
71
|
|
|
|
72
|
|
|
/** @var string|null */ |
73
|
|
|
protected $optgroupDefault; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @param mixed[] $options |
77
|
|
|
*/ |
78
|
23 |
|
public function setOptions(array $options) : void |
79
|
|
|
{ |
80
|
23 |
|
if (isset($options['object_manager'])) { |
81
|
22 |
|
$this->setObjectManager($options['object_manager']); |
82
|
|
|
} |
83
|
|
|
|
84
|
23 |
|
if (isset($options['target_class'])) { |
85
|
22 |
|
$this->setTargetClass($options['target_class']); |
86
|
|
|
} |
87
|
|
|
|
88
|
23 |
|
if (isset($options['property'])) { |
89
|
3 |
|
$this->setProperty($options['property']); |
90
|
|
|
} |
91
|
|
|
|
92
|
23 |
|
if (isset($options['label_generator'])) { |
93
|
2 |
|
$this->setLabelGenerator($options['label_generator']); |
|
|
|
|
94
|
|
|
} |
95
|
|
|
|
96
|
23 |
|
if (isset($options['find_method'])) { |
97
|
4 |
|
$this->setFindMethod($options['find_method']); |
98
|
|
|
} |
99
|
|
|
|
100
|
23 |
|
if (isset($options['is_method'])) { |
101
|
1 |
|
$this->setIsMethod($options['is_method']); |
102
|
|
|
} |
103
|
|
|
|
104
|
23 |
|
if (isset($options['display_empty_item'])) { |
105
|
1 |
|
$this->setDisplayEmptyItem($options['display_empty_item']); |
106
|
|
|
} |
107
|
|
|
|
108
|
23 |
|
if (isset($options['empty_item_label'])) { |
109
|
1 |
|
$this->setEmptyItemLabel($options['empty_item_label']); |
110
|
|
|
} |
111
|
|
|
|
112
|
23 |
|
if (isset($options['option_attributes'])) { |
113
|
3 |
|
$this->setOptionAttributes($options['option_attributes']); |
114
|
|
|
} |
115
|
|
|
|
116
|
23 |
|
if (isset($options['optgroup_identifier'])) { |
117
|
4 |
|
$this->setOptgroupIdentifier($options['optgroup_identifier']); |
118
|
|
|
} |
119
|
|
|
|
120
|
23 |
|
if (! isset($options['optgroup_default'])) { |
121
|
23 |
|
return; |
122
|
|
|
} |
123
|
|
|
|
124
|
1 |
|
$this->setOptgroupDefault($options['optgroup_default']); |
125
|
1 |
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @return mixed |
129
|
|
|
*/ |
130
|
22 |
|
public function getValueOptions() |
131
|
|
|
{ |
132
|
22 |
|
if (empty($this->valueOptions)) { |
133
|
22 |
|
$this->loadValueOptions(); |
134
|
|
|
} |
135
|
|
|
|
136
|
14 |
|
return $this->valueOptions; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* @return mixed |
141
|
|
|
*/ |
142
|
20 |
|
public function getObjects() |
143
|
|
|
{ |
144
|
20 |
|
$this->loadObjects(); |
145
|
|
|
|
146
|
16 |
|
return $this->objects; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Set the label for the empty option |
151
|
|
|
*/ |
152
|
1 |
|
public function setEmptyItemLabel(string $emptyItemLabel) : Proxy |
153
|
|
|
{ |
154
|
1 |
|
$this->emptyItemLabel = $emptyItemLabel; |
155
|
|
|
|
156
|
1 |
|
return $this; |
157
|
|
|
} |
158
|
|
|
|
159
|
1 |
|
public function getEmptyItemLabel() : string |
160
|
|
|
{ |
161
|
1 |
|
return $this->emptyItemLabel; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* @return mixed[] |
166
|
|
|
*/ |
167
|
14 |
|
public function getOptionAttributes() : array |
168
|
|
|
{ |
169
|
14 |
|
return $this->optionAttributes; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* @param mixed[] $optionAttributes |
174
|
|
|
*/ |
175
|
3 |
|
public function setOptionAttributes(array $optionAttributes) : void |
176
|
|
|
{ |
177
|
3 |
|
$this->optionAttributes = $optionAttributes; |
178
|
3 |
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Set a flag, whether to include the empty option at the beginning or not |
182
|
|
|
*/ |
183
|
1 |
|
public function setDisplayEmptyItem(bool $displayEmptyItem) : Proxy |
184
|
|
|
{ |
185
|
1 |
|
$this->displayEmptyItem = $displayEmptyItem; |
186
|
|
|
|
187
|
1 |
|
return $this; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
public function getDisplayEmptyItem() : bool |
191
|
|
|
{ |
192
|
|
|
return $this->displayEmptyItem; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Set the object manager |
197
|
|
|
*/ |
198
|
22 |
|
public function setObjectManager(ObjectManager $objectManager) : void |
199
|
|
|
{ |
200
|
22 |
|
$this->objectManager = $objectManager; |
201
|
22 |
|
} |
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* Get the object manager |
205
|
|
|
*/ |
206
|
20 |
|
public function getObjectManager() : ObjectManager |
207
|
|
|
{ |
208
|
20 |
|
return $this->objectManager; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Set the FQCN of the target object |
213
|
|
|
*/ |
214
|
22 |
|
public function setTargetClass(string $targetClass) : Proxy |
215
|
|
|
{ |
216
|
22 |
|
$this->targetClass = $targetClass; |
217
|
|
|
|
218
|
22 |
|
return $this; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* Get the target class |
223
|
|
|
*/ |
224
|
20 |
|
public function getTargetClass() : string |
225
|
|
|
{ |
226
|
20 |
|
return $this->targetClass; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Set the property to use as the label in the options |
231
|
|
|
*/ |
232
|
3 |
|
public function setProperty(string $property) : Proxy |
233
|
|
|
{ |
234
|
3 |
|
$this->property = $property; |
235
|
|
|
|
236
|
3 |
|
return $this; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* @return mixed |
241
|
|
|
*/ |
242
|
|
|
public function getProperty() |
243
|
|
|
{ |
244
|
|
|
return $this->property; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* Set the label generator callable that is responsible for generating labels for the items in the collection |
249
|
|
|
* |
250
|
|
|
* @param callable $callable A callable used to create a label based off of an Entity |
251
|
|
|
*/ |
252
|
1 |
|
public function setLabelGenerator(callable $callable) : void |
253
|
|
|
{ |
254
|
1 |
|
$this->labelGenerator = $callable; |
255
|
1 |
|
} |
256
|
|
|
|
257
|
14 |
|
public function getLabelGenerator() : ?callable |
258
|
|
|
{ |
259
|
14 |
|
return $this->labelGenerator; |
260
|
|
|
} |
261
|
|
|
|
262
|
13 |
|
public function getOptgroupIdentifier() : ?string |
263
|
|
|
{ |
264
|
13 |
|
return $this->optgroupIdentifier; |
265
|
|
|
} |
266
|
|
|
|
267
|
4 |
|
public function setOptgroupIdentifier(string $optgroupIdentifier) : void |
268
|
|
|
{ |
269
|
4 |
|
$this->optgroupIdentifier = (string) $optgroupIdentifier; |
270
|
4 |
|
} |
271
|
|
|
|
272
|
2 |
|
public function getOptgroupDefault() : ?string |
273
|
|
|
{ |
274
|
2 |
|
return $this->optgroupDefault; |
275
|
|
|
} |
276
|
|
|
|
277
|
1 |
|
public function setOptgroupDefault(string $optgroupDefault) : void |
278
|
|
|
{ |
279
|
1 |
|
$this->optgroupDefault = (string) $optgroupDefault; |
280
|
1 |
|
} |
281
|
|
|
|
282
|
|
|
/** |
283
|
|
|
* Set if the property is a method to use as the label in the options |
284
|
|
|
*/ |
285
|
1 |
|
public function setIsMethod(bool $method) : Proxy |
286
|
|
|
{ |
287
|
1 |
|
$this->isMethod = (bool) $method; |
288
|
|
|
|
289
|
1 |
|
return $this; |
290
|
|
|
} |
291
|
|
|
|
292
|
3 |
|
public function getIsMethod() : ?bool |
293
|
|
|
{ |
294
|
3 |
|
return $this->isMethod; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
/** Set the findMethod property to specify the method to use on repository |
298
|
|
|
* |
299
|
|
|
* @param mixed[] $findMethod |
300
|
|
|
*/ |
301
|
4 |
|
public function setFindMethod(array $findMethod) : Proxy |
302
|
|
|
{ |
303
|
4 |
|
$this->findMethod = $findMethod; |
304
|
|
|
|
305
|
4 |
|
return $this; |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* Get findMethod definition |
310
|
|
|
* |
311
|
|
|
* @return mixed[] |
312
|
|
|
*/ |
313
|
20 |
|
public function getFindMethod() : array |
314
|
|
|
{ |
315
|
20 |
|
return $this->findMethod; |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* @param mixed $targetEntity |
320
|
|
|
*/ |
321
|
14 |
|
protected function generateLabel($targetEntity) : ?string |
322
|
|
|
{ |
323
|
14 |
|
if ($this->getLabelGenerator() === null) { |
324
|
13 |
|
return null; |
325
|
|
|
} |
326
|
|
|
|
327
|
1 |
|
return call_user_func($this->getLabelGenerator(), $targetEntity); |
328
|
|
|
} |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* @param mixed $value |
332
|
|
|
* |
333
|
|
|
* @return mixed[]|mixed|object |
334
|
|
|
* |
335
|
|
|
* @throws RuntimeException |
336
|
|
|
*/ |
337
|
|
|
public function getValue($value) |
338
|
|
|
{ |
339
|
|
|
if (! $this->getObjectManager()) { |
340
|
|
|
throw new RuntimeException('No object manager was set'); |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
if (! $this->getTargetClass()) { |
344
|
|
|
throw new RuntimeException('No target class was set'); |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
$metadata = $this->getObjectManager()->getClassMetadata($this->getTargetClass()); |
348
|
|
|
|
349
|
|
|
if (is_object($value)) { |
350
|
|
|
if ($value instanceof Collection) { |
351
|
|
|
$data = []; |
352
|
|
|
|
353
|
|
|
foreach ($value as $object) { |
354
|
|
|
$values = $metadata->getIdentifierValues($object); |
355
|
|
|
$data[] = array_shift($values); |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
$value = $data; |
359
|
|
|
} else { |
360
|
|
|
$metadata = $this->getObjectManager()->getClassMetadata(get_class($value)); |
361
|
|
|
$identifier = $metadata->getIdentifierFieldNames(); |
362
|
|
|
|
363
|
|
|
// TODO: handle composite (multiple) identifiers |
364
|
|
|
if ($identifier !== null && count($identifier) > 1) { |
365
|
|
|
//$value = $key; |
366
|
|
|
$todo = true; |
|
|
|
|
367
|
|
|
} else { |
368
|
|
|
$value = current($metadata->getIdentifierValues($value)); |
369
|
|
|
} |
370
|
|
|
} |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
return $value; |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
/** |
377
|
|
|
* Load objects |
378
|
|
|
* |
379
|
|
|
* @throws RuntimeException |
380
|
|
|
* @throws Exception\InvalidRepositoryResultException |
381
|
|
|
*/ |
382
|
20 |
|
protected function loadObjects() : void |
383
|
|
|
{ |
384
|
20 |
|
if (! empty($this->objects)) { |
385
|
|
|
return; |
386
|
|
|
} |
387
|
|
|
|
388
|
20 |
|
$findMethod = (array) $this->getFindMethod(); |
389
|
|
|
|
390
|
20 |
|
if (! $findMethod) { |
|
|
|
|
391
|
16 |
|
$findMethodName = 'findAll'; |
392
|
16 |
|
$repository = $this->objectManager->getRepository($this->targetClass); |
393
|
16 |
|
$objects = $repository->findAll(); |
394
|
|
|
} else { |
395
|
4 |
|
if (! isset($findMethod['name'])) { |
396
|
1 |
|
throw new RuntimeException('No method name was set'); |
397
|
|
|
} |
398
|
|
|
|
399
|
3 |
|
$findMethodName = $findMethod['name']; |
400
|
3 |
|
$findMethodParams = isset($findMethod['params']) ? array_change_key_case($findMethod['params']) : []; |
401
|
3 |
|
$repository = $this->objectManager->getRepository($this->targetClass); |
402
|
|
|
|
403
|
3 |
|
if (! method_exists($repository, $findMethodName)) { |
404
|
1 |
|
throw new RuntimeException( |
405
|
1 |
|
sprintf( |
406
|
1 |
|
'Method "%s" could not be found in repository "%s"', |
407
|
1 |
|
$findMethodName, |
408
|
1 |
|
get_class($repository) |
409
|
|
|
) |
410
|
|
|
); |
411
|
|
|
} |
412
|
|
|
|
413
|
2 |
|
$r = new ReflectionMethod($repository, $findMethodName); |
414
|
2 |
|
$args = []; |
415
|
|
|
|
416
|
2 |
|
foreach ($r->getParameters() as $param) { |
417
|
2 |
|
if (array_key_exists(strtolower($param->getName()), $findMethodParams)) { |
|
|
|
|
418
|
1 |
|
$args[] = $findMethodParams[strtolower($param->getName())]; |
|
|
|
|
419
|
2 |
|
} elseif ($param->isDefaultValueAvailable()) { |
420
|
1 |
|
$args[] = $param->getDefaultValue(); |
421
|
1 |
|
} elseif (! $param->isOptional()) { |
422
|
1 |
|
throw new RuntimeException( |
423
|
1 |
|
sprintf( |
424
|
|
|
'Required parameter "%s" with no default value for method "%s" in repository "%s"' |
425
|
1 |
|
. ' was not provided', |
426
|
1 |
|
$param->getName(), |
|
|
|
|
427
|
1 |
|
$findMethodName, |
428
|
1 |
|
get_class($repository) |
429
|
|
|
) |
430
|
|
|
); |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
|
434
|
1 |
|
$objects = $r->invokeArgs($repository, $args); |
435
|
|
|
} |
436
|
|
|
|
437
|
17 |
|
$this->guardForArrayOrTraversable( |
438
|
17 |
|
$objects, |
439
|
17 |
|
sprintf('%s::%s() return value', get_class($repository), $findMethodName), |
440
|
17 |
|
'DoctrineModule\Form\Element\Exception\InvalidRepositoryResultException' |
441
|
|
|
); |
442
|
|
|
|
443
|
16 |
|
$this->objects = $objects; |
444
|
16 |
|
} |
445
|
|
|
|
446
|
|
|
/** |
447
|
|
|
* Load value options |
448
|
|
|
* |
449
|
|
|
* @throws RuntimeException |
450
|
|
|
*/ |
451
|
22 |
|
protected function loadValueOptions() : void |
452
|
|
|
{ |
453
|
22 |
|
if (! $this->objectManager) { |
454
|
1 |
|
throw new RuntimeException('No object manager was set'); |
455
|
|
|
} |
456
|
|
|
|
457
|
21 |
|
if (! $this->targetClass) { |
458
|
1 |
|
throw new RuntimeException('No target class was set'); |
459
|
|
|
} |
460
|
|
|
|
461
|
20 |
|
$metadata = $this->getObjectManager()->getClassMetadata($this->getTargetClass()); |
462
|
20 |
|
$identifier = $metadata->getIdentifierFieldNames(); |
463
|
20 |
|
$objects = $this->getObjects(); |
464
|
16 |
|
$options = []; |
465
|
16 |
|
$optionAttributes = []; |
466
|
|
|
|
467
|
16 |
|
if ($this->displayEmptyItem) { |
468
|
1 |
|
$options[''] = $this->getEmptyItemLabel(); |
469
|
|
|
} |
470
|
|
|
|
471
|
16 |
|
foreach ($objects as $key => $object) { |
472
|
14 |
|
$generatedLabel = $this->generateLabel($object); |
473
|
14 |
|
if ($generatedLabel !== null) { |
474
|
1 |
|
$label = $generatedLabel; |
475
|
13 |
|
} elseif ($this->property) { |
476
|
3 |
|
$property = $this->property; |
477
|
3 |
|
if (($this->getIsMethod() === false || $this->getIsMethod() === null) |
478
|
3 |
|
&& ! $metadata->hasField($property) |
479
|
|
|
) { |
480
|
|
|
throw new RuntimeException( |
481
|
|
|
sprintf( |
482
|
|
|
'Property "%s" could not be found in object "%s"', |
483
|
|
|
$property, |
484
|
|
|
$this->getTargetClass() |
485
|
|
|
) |
486
|
|
|
); |
487
|
|
|
} |
488
|
|
|
|
489
|
3 |
|
$getter = 'get' . Inflector::classify($property); |
490
|
|
|
|
491
|
3 |
|
if (! is_callable([$object, $getter])) { |
492
|
|
|
throw new RuntimeException( |
493
|
|
|
sprintf('Method "%s::%s" is not callable', $this->targetClass, $getter) |
494
|
|
|
); |
495
|
|
|
} |
496
|
|
|
|
497
|
3 |
|
$label = $object->{$getter}(); |
498
|
|
|
} else { |
499
|
10 |
|
if (! is_callable([$object, '__toString'])) { |
500
|
|
|
throw new RuntimeException( |
501
|
|
|
sprintf( |
502
|
|
|
'%s must have a "__toString()" method defined if you have not set a property' |
503
|
|
|
. ' or method to use.', |
504
|
|
|
$this->getTargetClass() |
505
|
|
|
) |
506
|
|
|
); |
507
|
|
|
} |
508
|
|
|
|
509
|
10 |
|
$label = (string) $object; |
510
|
|
|
} |
511
|
|
|
|
512
|
14 |
|
if ($identifier !== null && count($identifier) > 1) { |
513
|
|
|
$value = $key; |
514
|
|
|
} else { |
515
|
14 |
|
$value = current($metadata->getIdentifierValues($object)); |
516
|
|
|
} |
517
|
|
|
|
518
|
14 |
|
foreach ($this->getOptionAttributes() as $optionKey => $optionValue) { |
519
|
3 |
|
if (is_string($optionValue)) { |
520
|
1 |
|
$optionAttributes[$optionKey] = $optionValue; |
521
|
|
|
|
522
|
1 |
|
continue; |
523
|
|
|
} |
524
|
|
|
|
525
|
2 |
|
if (is_callable($optionValue)) { |
526
|
1 |
|
$callableValue = call_user_func($optionValue, $object); |
527
|
1 |
|
$optionAttributes[$optionKey] = (string) $callableValue; |
528
|
|
|
|
529
|
1 |
|
continue; |
530
|
|
|
} |
531
|
|
|
|
532
|
1 |
|
throw new RuntimeException( |
533
|
1 |
|
sprintf( |
534
|
|
|
'Parameter "option_attributes" expects an array of key => value where value is of type' |
535
|
1 |
|
. '"string" or "callable". Value of type "%s" found.', |
536
|
1 |
|
gettype($optionValue) |
537
|
|
|
) |
538
|
|
|
); |
539
|
|
|
} |
540
|
|
|
|
541
|
|
|
// If no optgroup_identifier has been configured, apply default handling and continue |
542
|
13 |
|
if ($this->getOptgroupIdentifier() === null) { |
543
|
9 |
|
$options[] = ['label' => $label, 'value' => $value, 'attributes' => $optionAttributes]; |
544
|
|
|
|
545
|
9 |
|
continue; |
546
|
|
|
} |
547
|
|
|
|
548
|
|
|
// optgroup_identifier found, handle grouping |
549
|
4 |
|
$optgroupGetter = 'get' . Inflector::classify($this->getOptgroupIdentifier()); |
550
|
|
|
|
551
|
4 |
|
if (! is_callable([$object, $optgroupGetter])) { |
552
|
1 |
|
throw new RuntimeException( |
553
|
1 |
|
sprintf('Method "%s::%s" is not callable', $this->targetClass, $optgroupGetter) |
554
|
|
|
); |
555
|
|
|
} |
556
|
|
|
|
557
|
3 |
|
$optgroup = $object->{$optgroupGetter}(); |
558
|
|
|
|
559
|
|
|
// optgroup_identifier contains a valid group-name. Handle default grouping. |
560
|
3 |
|
if ($optgroup !== null && trim($optgroup) !== '') { |
561
|
2 |
|
$options[$optgroup]['label'] = $optgroup; |
562
|
2 |
|
$options[$optgroup]['options'][] = [ |
563
|
2 |
|
'label' => $label, |
564
|
2 |
|
'value' => $value, |
565
|
2 |
|
'attributes' => $optionAttributes, |
566
|
|
|
]; |
567
|
|
|
|
568
|
2 |
|
continue; |
569
|
|
|
} |
570
|
|
|
|
571
|
2 |
|
$optgroupDefault = $this->getOptgroupDefault(); |
572
|
|
|
|
573
|
|
|
// No optgroup_default has been provided. Line up without a group |
574
|
2 |
|
if ($optgroupDefault === null) { |
575
|
1 |
|
$options[] = ['label' => $label, 'value' => $value, 'attributes' => $optionAttributes]; |
576
|
|
|
|
577
|
1 |
|
continue; |
578
|
|
|
} |
579
|
|
|
|
580
|
|
|
// Line up entry with optgroup_default |
581
|
1 |
|
$options[$optgroupDefault]['label'] = $optgroupDefault; |
582
|
1 |
|
$options[$optgroupDefault]['options'][] = [ |
583
|
1 |
|
'label' => $label, |
584
|
1 |
|
'value' => $value, |
585
|
1 |
|
'attributes' => $optionAttributes, |
586
|
|
|
]; |
587
|
|
|
} |
588
|
|
|
|
589
|
14 |
|
$this->valueOptions = $options; |
590
|
14 |
|
} |
591
|
|
|
} |
592
|
|
|
|
593
|
|
|
interface_exists(ObjectManager::class); |
594
|
|
|
|
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: