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