1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace JMS\Serializer\Metadata\Driver; |
6
|
|
|
|
7
|
|
|
use JMS\Serializer\Annotation\ExclusionPolicy; |
8
|
|
|
use JMS\Serializer\Exception\InvalidMetadataException; |
9
|
|
|
use JMS\Serializer\Expression\CompilableExpressionEvaluatorInterface; |
10
|
|
|
use JMS\Serializer\Metadata\ClassMetadata; |
11
|
|
|
use JMS\Serializer\Metadata\ExpressionPropertyMetadata; |
12
|
|
|
use JMS\Serializer\Metadata\PropertyMetadata; |
13
|
|
|
use JMS\Serializer\Metadata\VirtualPropertyMetadata; |
14
|
|
|
use JMS\Serializer\Naming\PropertyNamingStrategyInterface; |
15
|
|
|
use JMS\Serializer\Type\Parser; |
16
|
|
|
use JMS\Serializer\Type\ParserInterface; |
17
|
|
|
use Metadata\ClassMetadata as BaseClassMetadata; |
18
|
|
|
use Metadata\Driver\AbstractFileDriver; |
19
|
|
|
use Metadata\Driver\AdvancedFileLocatorInterface; |
20
|
|
|
use Metadata\Driver\FileLocatorInterface; |
21
|
|
|
use Metadata\MethodMetadata; |
22
|
|
|
use ReflectionClass; |
23
|
|
|
use RuntimeException; |
24
|
|
|
use Symfony\Component\Yaml\Yaml; |
25
|
|
|
|
26
|
|
|
class YamlDriver extends AbstractFileDriver |
27
|
|
|
{ |
28
|
|
|
use ExpressionMetadataTrait; |
29
|
32 |
|
|
30
|
|
|
/** |
31
|
32 |
|
* @var ParserInterface |
32
|
32 |
|
*/ |
33
|
32 |
|
private $typeParser; |
34
|
32 |
|
/** |
35
|
|
|
* @var PropertyNamingStrategyInterface |
36
|
32 |
|
*/ |
37
|
|
|
private $namingStrategy; |
38
|
32 |
|
/** |
39
|
|
|
* @var FileLocatorInterface |
40
|
32 |
|
*/ |
41
|
|
|
private $locator; |
42
|
|
|
|
43
|
|
|
public function __construct(FileLocatorInterface $locator, PropertyNamingStrategyInterface $namingStrategy, ?ParserInterface $typeParser = null, ?CompilableExpressionEvaluatorInterface $expressionEvaluator = null) |
44
|
32 |
|
{ |
45
|
32 |
|
$this->locator = $locator; |
46
|
32 |
|
$this->typeParser = $typeParser ?? new Parser(); |
47
|
32 |
|
$this->namingStrategy = $namingStrategy; |
48
|
32 |
|
$this->expressionEvaluator = $expressionEvaluator; |
49
|
32 |
|
} |
50
|
32 |
|
|
51
|
32 |
|
public function loadMetadataForClass(ReflectionClass $class): ?BaseClassMetadata |
52
|
32 |
|
{ |
53
|
|
|
$path = null; |
54
|
32 |
|
foreach ($this->getExtensions() as $extension) { |
55
|
32 |
|
$path = $this->locator->findFileForClass($class, $extension); |
56
|
5 |
|
if (null !== $path) { |
57
|
5 |
|
break; |
58
|
2 |
|
} |
59
|
2 |
|
} |
60
|
|
|
|
61
|
|
|
if (null === $path) { |
62
|
4 |
|
return null; |
63
|
|
|
} |
64
|
|
|
|
65
|
4 |
|
return $this->loadMetadataFromFile($class, $path); |
66
|
|
|
} |
67
|
|
|
|
68
|
5 |
|
/** |
69
|
|
|
* {@inheritDoc} |
70
|
5 |
|
*/ |
71
|
5 |
|
public function getAllClassNames(): array |
72
|
|
|
{ |
73
|
|
|
if (!$this->locator instanceof AdvancedFileLocatorInterface) { |
74
|
|
|
throw new RuntimeException( |
75
|
32 |
|
sprintf( |
76
|
32 |
|
'Locator "%s" must be an instance of "AdvancedFileLocatorInterface".', |
77
|
27 |
|
get_class($this->locator), |
78
|
4 |
|
), |
79
|
|
|
); |
80
|
|
|
} |
81
|
26 |
|
|
82
|
26 |
|
$classes = []; |
83
|
|
|
foreach ($this->getExtensions() as $extension) { |
84
|
|
|
foreach ($this->locator->findAllClasses($extension) as $class) { |
85
|
32 |
|
$classes[$class] = $class; |
86
|
28 |
|
} |
87
|
28 |
|
} |
88
|
27 |
|
|
89
|
28 |
|
return array_values($classes); |
90
|
|
|
} |
91
|
28 |
|
|
92
|
25 |
|
protected function loadMetadataFromFile(ReflectionClass $class, string $file): ?BaseClassMetadata |
93
|
|
|
{ |
94
|
25 |
|
$config = Yaml::parseFile($file, Yaml::PARSE_CONSTANT); |
95
|
2 |
|
|
96
|
|
|
if (!isset($config[$name = $class->name])) { |
97
|
|
|
throw new InvalidMetadataException( |
98
|
25 |
|
sprintf('Expected metadata for class %s to be defined in %s.', $class->name, $file), |
99
|
2 |
|
); |
100
|
|
|
} |
101
|
|
|
|
102
|
23 |
|
$config = $config[$name]; |
103
|
3 |
|
$metadata = new ClassMetadata($name); |
104
|
|
|
$metadata->fileResources[] = $file; |
105
|
|
|
$fileResource = $class->getFilename(); |
106
|
23 |
|
if (false !== $fileResource) { |
107
|
1 |
|
$metadata->fileResources[] = $fileResource; |
108
|
|
|
} |
109
|
|
|
|
110
|
23 |
|
$exclusionPolicy = isset($config['exclusion_policy']) ? strtoupper($config['exclusion_policy']) : 'NONE'; |
111
|
|
|
$excludeAll = isset($config['exclude']) ? (bool) $config['exclude'] : false; |
112
|
|
|
|
113
|
|
|
if (isset($config['exclude_if'])) { |
114
|
23 |
|
$metadata->excludeIf = $this->parseExpression((string) $config['exclude_if']); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
$classAccessType = $config['access_type'] ?? PropertyMetadata::ACCESS_TYPE_PROPERTY; |
118
|
23 |
|
$readOnlyClass = isset($config['read_only']) ? (bool) $config['read_only'] : false; |
119
|
1 |
|
$this->addClassProperties($metadata, $config); |
120
|
|
|
|
121
|
|
|
$propertiesMetadata = []; |
122
|
23 |
|
$propertiesData = []; |
123
|
1 |
|
if (array_key_exists('virtual_properties', $config)) { |
124
|
|
|
foreach ($config['virtual_properties'] as $methodName => $propertySettings) { |
125
|
|
|
if (isset($propertySettings['exp'])) { |
126
|
23 |
|
$virtualPropertyMetadata = new ExpressionPropertyMetadata( |
127
|
6 |
|
$name, |
128
|
|
|
$methodName, |
129
|
|
|
$this->parseExpression($propertySettings['exp']), |
130
|
23 |
|
); |
131
|
17 |
|
unset($propertySettings['exp']); |
132
|
|
|
} else { |
133
|
|
|
if (!$class->hasMethod($methodName)) { |
134
|
23 |
|
throw new InvalidMetadataException( |
135
|
1 |
|
'The method ' . $methodName . ' not found in class ' . $class->name, |
136
|
|
|
); |
137
|
|
|
} |
138
|
23 |
|
|
139
|
2 |
|
$virtualPropertyMetadata = new VirtualPropertyMetadata($name, $methodName); |
140
|
|
|
} |
141
|
2 |
|
|
142
|
2 |
|
$propertiesMetadata[] = $virtualPropertyMetadata; |
143
|
2 |
|
$propertiesData[] = $propertySettings; |
144
|
|
|
} |
145
|
|
|
} |
146
|
2 |
|
|
147
|
1 |
|
if (!$excludeAll) { |
148
|
|
|
foreach ($class->getProperties() as $property) { |
149
|
|
|
if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) { |
150
|
2 |
|
continue; |
151
|
1 |
|
} |
152
|
|
|
|
153
|
2 |
|
$pName = $property->getName(); |
154
|
|
|
$propertiesMetadata[] = new PropertyMetadata($name, $pName); |
155
|
|
|
$propertiesData[] = !empty($config['properties']) && true === array_key_exists($pName, $config['properties']) |
156
|
2 |
|
? (array) $config['properties'][$pName] |
157
|
|
|
: null; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
foreach ($propertiesMetadata as $propertyKey => $pMetadata) { |
161
|
23 |
|
$isExclude = false; |
162
|
|
|
$isExpose = $pMetadata instanceof VirtualPropertyMetadata |
163
|
|
|
|| $pMetadata instanceof ExpressionPropertyMetadata |
164
|
|
|
|| isset($propertiesData[$propertyKey]); |
165
|
|
|
|
166
|
|
|
$pConfig = $propertiesData[$propertyKey]; |
167
|
|
|
if (!empty($pConfig)) { |
168
|
|
|
if (isset($pConfig['exclude'])) { |
169
|
|
|
$isExclude = (bool) $pConfig['exclude']; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
if ($isExclude) { |
173
|
|
|
continue; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
if (isset($pConfig['expose'])) { |
177
|
|
|
$isExpose = (bool) $pConfig['expose']; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
if (isset($pConfig['skip_when_empty'])) { |
181
|
|
|
$pMetadata->skipWhenEmpty = (bool) $pConfig['skip_when_empty']; |
182
|
23 |
|
} |
183
|
4 |
|
|
184
|
4 |
|
if (isset($pConfig['since_version'])) { |
185
|
2 |
|
$pMetadata->sinceVersion = (string) $pConfig['since_version']; |
186
|
|
|
} |
187
|
|
|
|
188
|
4 |
|
if (isset($pConfig['until_version'])) { |
189
|
3 |
|
$pMetadata->untilVersion = (string) $pConfig['until_version']; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
if (isset($pConfig['exclude_if'])) { |
193
|
23 |
|
$pMetadata->excludeIf = $this->parseExpression((string) $pConfig['exclude_if']); |
194
|
4 |
|
} |
195
|
|
|
|
196
|
|
|
if (isset($pConfig['expose_if'])) { |
197
|
23 |
|
$pMetadata->excludeIf = $this->parseExpression('!(' . $pConfig['expose_if'] . ')'); |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
if (isset($pConfig['serialized_name'])) { |
201
|
23 |
|
$pMetadata->serializedName = (string) $pConfig['serialized_name']; |
202
|
2 |
|
} |
203
|
|
|
|
204
|
|
|
if (isset($pConfig['type'])) { |
205
|
23 |
|
$pMetadata->setType($this->typeParser->parse((string) $pConfig['type'])); |
206
|
1 |
|
} |
207
|
|
|
|
208
|
|
|
if (isset($pConfig['groups'])) { |
209
|
|
|
$pMetadata->groups = $pConfig['groups']; |
210
|
23 |
|
} |
211
|
1 |
|
|
212
|
|
|
if (isset($pConfig['xml_list'])) { |
213
|
22 |
|
$pMetadata->xmlCollection = true; |
214
|
|
|
|
215
|
|
|
$colConfig = $pConfig['xml_list']; |
216
|
23 |
|
if (isset($colConfig['inline'])) { |
217
|
23 |
|
$pMetadata->xmlCollectionInline = (bool) $colConfig['inline']; |
218
|
23 |
|
} |
219
|
23 |
|
|
220
|
|
|
if (isset($colConfig['entry_name'])) { |
221
|
|
|
$pMetadata->xmlEntryName = (string) $colConfig['entry_name']; |
222
|
23 |
|
} |
223
|
2 |
|
|
224
|
|
|
if (isset($colConfig['skip_when_empty'])) { |
225
|
|
|
$pMetadata->xmlCollectionSkipWhenEmpty = (bool) $colConfig['skip_when_empty']; |
226
|
23 |
|
} else { |
227
|
1 |
|
$pMetadata->xmlCollectionSkipWhenEmpty = true; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
if (isset($colConfig['namespace'])) { |
231
|
28 |
|
$pMetadata->xmlEntryNamespace = (string) $colConfig['namespace']; |
232
|
28 |
|
} |
233
|
|
|
} |
234
|
|
|
|
235
|
28 |
|
if (isset($pConfig['xml_map'])) { |
236
|
2 |
|
$pMetadata->xmlCollection = true; |
237
|
2 |
|
|
238
|
|
|
$colConfig = $pConfig['xml_map']; |
239
|
|
|
if (isset($colConfig['inline'])) { |
240
|
28 |
|
$pMetadata->xmlCollectionInline = (bool) $colConfig['inline']; |
241
|
23 |
|
} |
242
|
|
|
|
243
|
23 |
|
if (isset($colConfig['entry_name'])) { |
244
|
1 |
|
$pMetadata->xmlEntryName = (string) $colConfig['entry_name']; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
if (isset($colConfig['namespace'])) { |
248
|
28 |
|
$pMetadata->xmlEntryNamespace = (string) $colConfig['namespace']; |
249
|
28 |
|
} |
250
|
|
|
|
251
|
28 |
|
if (isset($colConfig['key_attribute_name'])) { |
252
|
|
|
$pMetadata->xmlKeyAttribute = $colConfig['key_attribute_name']; |
253
|
|
|
} |
254
|
|
|
} |
255
|
|
|
|
256
|
32 |
|
if (isset($pConfig['xml_element'])) { |
257
|
|
|
$colConfig = $pConfig['xml_element']; |
258
|
|
|
if (isset($colConfig['cdata'])) { |
259
|
|
|
$pMetadata->xmlElementCData = (bool) $colConfig['cdata']; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
if (isset($colConfig['namespace'])) { |
263
|
|
|
$pMetadata->xmlNamespace = (string) $colConfig['namespace']; |
264
|
|
|
} |
265
|
|
|
} |
266
|
|
|
|
267
|
|
|
if (isset($pConfig['xml_attribute'])) { |
268
|
|
|
$pMetadata->xmlAttribute = (bool) $pConfig['xml_attribute']; |
269
|
|
|
} |
270
|
32 |
|
|
271
|
|
|
if (isset($pConfig['xml_attribute_map'])) { |
272
|
|
|
$pMetadata->xmlAttributeMap = (bool) $pConfig['xml_attribute_map']; |
273
|
32 |
|
} |
274
|
|
|
|
275
|
32 |
|
if (isset($pConfig['xml_value'])) { |
276
|
|
|
$pMetadata->xmlValue = (bool) $pConfig['xml_value']; |
277
|
|
|
} |
278
|
32 |
|
|
279
|
|
|
if (isset($pConfig['xml_key_value_pairs'])) { |
280
|
32 |
|
$pMetadata->xmlKeyValuePairs = (bool) $pConfig['xml_key_value_pairs']; |
281
|
1 |
|
} |
282
|
|
|
|
283
|
|
|
//we need read_only before setter and getter set, because that method depends on flag being set |
284
|
32 |
|
if (isset($pConfig['read_only'])) { |
285
|
1 |
|
$pMetadata->readOnly = (bool) $pConfig['read_only']; |
286
|
|
|
} else { |
287
|
|
|
$pMetadata->readOnly = $pMetadata->readOnly || $readOnlyClass; |
288
|
32 |
|
} |
289
|
9 |
|
|
290
|
|
|
$pMetadata->setAccessor( |
291
|
|
|
$pConfig['access_type'] ?? $classAccessType, |
292
|
32 |
|
$pConfig['accessor']['getter'] ?? null, |
293
|
1 |
|
$pConfig['accessor']['setter'] ?? null, |
294
|
|
|
); |
295
|
|
|
|
296
|
32 |
|
if (isset($pConfig['inline'])) { |
297
|
1 |
|
$pMetadata->inline = (bool) $pConfig['inline']; |
298
|
|
|
} |
299
|
|
|
|
300
|
32 |
|
if (isset($pConfig['max_depth'])) { |
301
|
|
|
$pMetadata->maxDepth = (int) $pConfig['max_depth']; |
302
|
3 |
|
} |
303
|
3 |
|
|
304
|
|
|
if (isset($pConfig['union_discriminator'])) { |
305
|
|
|
$pMetadata->setType([ |
306
|
|
|
'name' => 'union', |
307
|
32 |
|
'params' => [null, $pConfig['union_discriminator']['field'], $pConfig['union_discriminator']['map']], |
308
|
5 |
|
]); |
309
|
|
|
} |
310
|
|
|
} |
311
|
5 |
|
|
312
|
|
|
if (!$pMetadata->serializedName) { |
313
|
|
|
$pMetadata->serializedName = $this->namingStrategy->translateName($pMetadata); |
314
|
|
|
} |
315
|
5 |
|
|
316
|
|
|
if ($pMetadata->inline) { |
317
|
|
|
$metadata->isList = $metadata->isList || PropertyMetadata::isCollectionList($pMetadata->type); |
318
|
5 |
|
$metadata->isMap = $metadata->isMap || PropertyMetadata::isCollectionMap($pMetadata->type); |
319
|
5 |
|
} |
320
|
|
|
|
321
|
5 |
|
if (!empty($pConfig) && !empty($pConfig['name'])) { |
322
|
2 |
|
$pMetadata->name = (string) $pConfig['name']; |
323
|
|
|
} |
324
|
5 |
|
|
325
|
3 |
|
if ( |
326
|
1 |
|
(ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude) |
327
|
|
|
|| (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose) |
328
|
3 |
|
) { |
329
|
2 |
|
$metadata->addPropertyMetadata($pMetadata); |
330
|
|
|
} |
331
|
|
|
} |
332
|
|
|
} |
333
|
|
|
|
334
|
32 |
|
if (isset($config['callback_methods'])) { |
335
|
|
|
$cConfig = $config['callback_methods']; |
336
|
|
|
|
337
|
|
|
if (isset($cConfig['pre_serialize'])) { |
338
|
|
|
$metadata->preSerializeMethods = $this->getCallbackMetadata($class, $cConfig['pre_serialize']); |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
if (isset($cConfig['post_serialize'])) { |
342
|
|
|
$metadata->postSerializeMethods = $this->getCallbackMetadata($class, $cConfig['post_serialize']); |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
if (isset($cConfig['post_deserialize'])) { |
346
|
|
|
$metadata->postDeserializeMethods = $this->getCallbackMetadata($class, $cConfig['post_deserialize']); |
347
|
|
|
} |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
return $metadata; |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
/** |
354
|
|
|
* @return string[] |
355
|
|
|
*/ |
356
|
|
|
protected function getExtensions(): array |
357
|
|
|
{ |
358
|
|
|
return array_unique([$this->getExtension(), 'yaml', 'yml']); |
|
|
|
|
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* @deprecated use getExtensions instead. |
363
|
|
|
*/ |
364
|
|
|
protected function getExtension(): string |
365
|
|
|
{ |
366
|
|
|
return 'yml'; |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
private function addClassProperties(ClassMetadata $metadata, array $config): void |
370
|
|
|
{ |
371
|
|
|
if (isset($config['custom_accessor_order']) && !isset($config['accessor_order'])) { |
372
|
|
|
$config['accessor_order'] = 'custom'; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
if (isset($config['accessor_order'])) { |
376
|
|
|
$metadata->setAccessorOrder($config['accessor_order'], $config['custom_accessor_order'] ?? []); |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
if (isset($config['xml_root_name'])) { |
380
|
|
|
$metadata->xmlRootName = (string) $config['xml_root_name']; |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
if (isset($config['xml_root_prefix'])) { |
384
|
|
|
$metadata->xmlRootPrefix = (string) $config['xml_root_prefix']; |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
if (isset($config['xml_root_namespace'])) { |
388
|
|
|
$metadata->xmlRootNamespace = (string) $config['xml_root_namespace']; |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
if (array_key_exists('xml_namespaces', $config)) { |
392
|
|
|
foreach ($config['xml_namespaces'] as $prefix => $uri) { |
393
|
|
|
$metadata->registerNamespace($uri, $prefix); |
394
|
|
|
} |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
if (isset($config['discriminator'])) { |
398
|
|
|
if (isset($config['discriminator']['disabled']) && true === $config['discriminator']['disabled']) { |
399
|
|
|
$metadata->discriminatorDisabled = true; |
400
|
|
|
} else { |
401
|
|
|
if (!isset($config['discriminator']['field_name'])) { |
402
|
|
|
throw new InvalidMetadataException('The "field_name" attribute must be set for discriminators.'); |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
if (!isset($config['discriminator']['map']) || !is_array($config['discriminator']['map'])) { |
406
|
|
|
throw new InvalidMetadataException( |
407
|
|
|
'The "map" attribute must be set, and be an array for discriminators.', |
408
|
|
|
); |
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
$groups = $config['discriminator']['groups'] ?? []; |
412
|
|
|
$metadata->setDiscriminator( |
413
|
|
|
$config['discriminator']['field_name'], |
414
|
|
|
$config['discriminator']['map'], |
415
|
|
|
$groups, |
416
|
|
|
); |
417
|
|
|
|
418
|
|
|
if (isset($config['discriminator']['xml_attribute'])) { |
419
|
|
|
$metadata->xmlDiscriminatorAttribute = (bool) $config['discriminator']['xml_attribute']; |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
if (isset($config['discriminator']['xml_element'])) { |
423
|
|
|
if (isset($config['discriminator']['xml_element']['cdata'])) { |
424
|
|
|
$metadata->xmlDiscriminatorCData = (bool) $config['discriminator']['xml_element']['cdata']; |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
if (isset($config['discriminator']['xml_element']['namespace'])) { |
428
|
|
|
$metadata->xmlDiscriminatorNamespace = (string) $config['discriminator']['xml_element']['namespace']; |
429
|
|
|
} |
430
|
|
|
} |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
} |
434
|
|
|
|
435
|
|
|
/** |
436
|
|
|
* @param string|string[] $config |
437
|
|
|
*/ |
438
|
|
|
private function getCallbackMetadata(ReflectionClass $class, $config): array |
439
|
|
|
{ |
440
|
|
|
if (is_string($config)) { |
441
|
|
|
$config = [$config]; |
442
|
|
|
} elseif (!is_array($config)) { |
|
|
|
|
443
|
|
|
throw new InvalidMetadataException( |
444
|
|
|
sprintf( |
445
|
|
|
'callback methods expects a string, or an array of strings that represent method names, but got %s.', |
446
|
|
|
json_encode($config['pre_serialize']), |
447
|
|
|
), |
448
|
|
|
); |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
$methods = []; |
452
|
|
|
foreach ($config as $name) { |
453
|
|
|
if (!$class->hasMethod($name)) { |
454
|
|
|
throw new InvalidMetadataException( |
455
|
|
|
sprintf('The method %s does not exist in class %s.', $name, $class->name), |
456
|
|
|
); |
457
|
|
|
} |
458
|
|
|
|
459
|
|
|
$methods[] = new MethodMetadata($class->name, $name); |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
return $methods; |
463
|
|
|
} |
464
|
|
|
} |
465
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.