3c7f681d808cf2ddad9f794ac64f7dab2af2b035
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Reflection / ClassSchema.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Reflection;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Doctrine\Common\Annotations\AnnotationReader;
18 use TYPO3\CMS\Core\SingletonInterface;
19 use TYPO3\CMS\Core\Utility\ClassNamingUtility;
20 use TYPO3\CMS\Extbase\Annotation\IgnoreValidation;
21 use TYPO3\CMS\Extbase\Annotation\Inject;
22 use TYPO3\CMS\Extbase\Annotation\ORM\Cascade;
23 use TYPO3\CMS\Extbase\Annotation\ORM\Lazy;
24 use TYPO3\CMS\Extbase\Annotation\ORM\Transient;
25 use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
26 use TYPO3\CMS\Extbase\DomainObject\AbstractValueObject;
27 use TYPO3\CMS\Extbase\Utility\TypeHandlingUtility;
28
29 /**
30 * A class schema
31 *
32 * @internal
33 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
34 */
35 class ClassSchema
36 {
37 /**
38 * Available model types
39 */
40 const MODELTYPE_ENTITY = 1;
41 const MODELTYPE_VALUEOBJECT = 2;
42
43 /**
44 * Name of the class this schema is referring to
45 *
46 * @var string
47 */
48 protected $className;
49
50 /**
51 * Model type of the class this schema is referring to
52 *
53 * @var int
54 */
55 protected $modelType = self::MODELTYPE_ENTITY;
56
57 /**
58 * Whether a repository exists for the class this schema is referring to
59 *
60 * @var bool
61 */
62 protected $aggregateRoot = false;
63
64 /**
65 * The name of the property holding the uuid of an entity, if any.
66 *
67 * @var string
68 */
69 protected $uuidPropertyName;
70
71 /**
72 * Properties of the class which need to be persisted
73 *
74 * @var array
75 */
76 protected $properties = [];
77
78 /**
79 * The properties forming the identity of an object
80 *
81 * @var array
82 */
83 protected $identityProperties = [];
84
85 /**
86 * Indicates if the class is a singleton or not.
87 *
88 * @var bool
89 */
90 private $isSingleton;
91
92 /**
93 * @var array
94 */
95 private $methods;
96
97 /**
98 * @var array
99 */
100 private $tags = [];
101
102 /**
103 * @var array
104 */
105 private $injectProperties = [];
106
107 /**
108 * @var array
109 */
110 private $injectMethods = [];
111
112 /**
113 * Constructs this class schema
114 *
115 * @param string $className Name of the class this schema is referring to
116 * @throws \TYPO3\CMS\Extbase\Reflection\Exception\UnknownClassException
117 * @throws \ReflectionException
118 */
119 public function __construct($className)
120 {
121 $this->className = $className;
122
123 $reflectionClass = new \ReflectionClass($className);
124
125 $this->isSingleton = $reflectionClass->implementsInterface(SingletonInterface::class);
126
127 if ($reflectionClass->isSubclassOf(AbstractEntity::class)) {
128 $this->modelType = static::MODELTYPE_ENTITY;
129
130 $possibleRepositoryClassName = ClassNamingUtility::translateModelNameToRepositoryName($className);
131 if (class_exists($possibleRepositoryClassName)) {
132 $this->setAggregateRoot(true);
133 }
134 }
135
136 if ($reflectionClass->isSubclassOf(AbstractValueObject::class)) {
137 $this->modelType = static::MODELTYPE_VALUEOBJECT;
138 }
139
140 $docCommentParser = new DocCommentParser(true);
141 $docCommentParser->parseDocComment($reflectionClass->getDocComment());
142 $this->tags = $docCommentParser->getTagsValues();
143
144 $this->reflectProperties($reflectionClass);
145 $this->reflectMethods($reflectionClass);
146 }
147
148 /**
149 * @param \ReflectionClass $reflectionClass
150 */
151 protected function reflectProperties(\ReflectionClass $reflectionClass)
152 {
153 $annotationReader = new AnnotationReader();
154
155 foreach ($reflectionClass->getProperties() as $reflectionProperty) {
156 $propertyName = $reflectionProperty->getName();
157
158 $this->properties[$propertyName] = [
159 'default' => $reflectionProperty->isDefault(),
160 'private' => $reflectionProperty->isPrivate(),
161 'protected' => $reflectionProperty->isProtected(),
162 'public' => $reflectionProperty->isPublic(),
163 'static' => $reflectionProperty->isStatic(),
164 'type' => null, // Extbase
165 'elementType' => null, // Extbase
166 'annotations' => [],
167 'tags' => []
168 ];
169
170 $docCommentParser = new DocCommentParser(true);
171 $docCommentParser->parseDocComment($reflectionProperty->getDocComment());
172 foreach ($docCommentParser->getTagsValues() as $tag => $values) {
173 $this->properties[$propertyName]['tags'][strtolower($tag)] = $values;
174 }
175
176 $this->properties[$propertyName]['annotations']['inject'] = false;
177 $this->properties[$propertyName]['annotations']['lazy'] = false;
178 $this->properties[$propertyName]['annotations']['transient'] = false;
179 $this->properties[$propertyName]['annotations']['type'] = null;
180 $this->properties[$propertyName]['annotations']['cascade'] = null;
181 $this->properties[$propertyName]['annotations']['dependency'] = null;
182 $this->properties[$propertyName]['annotations']['validators'] = [];
183
184 if ($docCommentParser->isTaggedWith('validate')) {
185 $this->properties[$propertyName]['annotations']['validators'] = $docCommentParser->getTagValues('validate');
186 }
187
188 if ($annotationReader->getPropertyAnnotation($reflectionProperty, Lazy::class) instanceof Lazy) {
189 $this->properties[$propertyName]['annotations']['lazy'] = true;
190 }
191
192 if ($docCommentParser->isTaggedWith('lazy')) {
193 $this->properties[$propertyName]['annotations']['lazy'] = true;
194 trigger_error(
195 'Tagging properties with @lazy is deprecated and will be removed in TYPO3 v10.0.',
196 E_USER_DEPRECATED
197 );
198 }
199
200 if ($annotationReader->getPropertyAnnotation($reflectionProperty, Transient::class) instanceof Transient) {
201 $this->properties[$propertyName]['annotations']['transient'] = true;
202 }
203
204 if ($docCommentParser->isTaggedWith('transient')) {
205 $this->properties[$propertyName]['annotations']['transient'] = true;
206 trigger_error(
207 'Tagging properties with @transient is deprecated and will be removed in TYPO3 v10.0.',
208 E_USER_DEPRECATED
209 );
210 }
211
212 if ($propertyName !== 'settings'
213 && ($annotationReader->getPropertyAnnotation($reflectionProperty, Inject::class) instanceof Inject)
214 ) {
215 try {
216 $varValue = ltrim($docCommentParser->getTagValues('var')[0], '\\');
217 $this->properties[$propertyName]['annotations']['inject'] = true;
218 $this->properties[$propertyName]['annotations']['type'] = $varValue;
219 $this->properties[$propertyName]['annotations']['dependency'] = $varValue;
220
221 $this->injectProperties[] = $propertyName;
222 } catch (\Exception $e) {
223 }
224 }
225
226 if ($propertyName !== 'settings' && $docCommentParser->isTaggedWith('inject')) {
227 trigger_error(
228 'Tagging properties with @inject is deprecated and will be removed in TYPO3 v10.0.',
229 E_USER_DEPRECATED
230 );
231 try {
232 $varValues = $docCommentParser->getTagValues('var');
233 $this->properties[$propertyName]['annotations']['inject'] = true;
234 $this->properties[$propertyName]['annotations']['type'] = ltrim($varValues[0], '\\');
235 $this->properties[$propertyName]['annotations']['dependency'] = ltrim($varValues[0], '\\');
236
237 if (!$reflectionProperty->isPublic()) {
238 trigger_error(
239 'Using @inject with non-public properties is deprecated since TYPO3 v9.0 and will stop working in TYPO3 v10.0.',
240 E_USER_DEPRECATED
241 );
242 }
243
244 $this->injectProperties[] = $propertyName;
245 } catch (\Exception $e) {
246 }
247 }
248
249 if ($docCommentParser->isTaggedWith('var') && !$docCommentParser->isTaggedWith('transient')) {
250 try {
251 $cascadeAnnotationValues = $docCommentParser->getTagValues('cascade');
252 $this->properties[$propertyName]['annotations']['cascade'] = $cascadeAnnotationValues[0];
253 } catch (\Exception $e) {
254 }
255
256 if ($this->properties[$propertyName]['annotations']['cascade'] !== null) {
257 trigger_error(
258 'Tagging properties with @cascade is deprecated and will be removed in TYPO3 v10.0.',
259 E_USER_DEPRECATED
260 );
261 }
262
263 if (($annotation = $annotationReader->getPropertyAnnotation($reflectionProperty, Cascade::class)) instanceof Cascade) {
264 /** @var Cascade $annotation */
265 $this->properties[$propertyName]['annotations']['cascade'] = $annotation->value;
266 }
267
268 try {
269 $type = TypeHandlingUtility::parseType(implode(' ', $docCommentParser->getTagValues('var')));
270 } catch (\Exception $e) {
271 $type = [
272 'type' => null,
273 'elementType' => null
274 ];
275 }
276
277 $this->properties[$propertyName]['type'] = $type['type'] ? ltrim($type['type'], '\\') : null;
278 $this->properties[$propertyName]['elementType'] = $type['elementType'] ? ltrim($type['elementType'], '\\') : null;
279 }
280
281 if ($docCommentParser->isTaggedWith('uuid')) {
282 $this->setUuidPropertyName($propertyName);
283 }
284
285 if ($docCommentParser->isTaggedWith('identity')) {
286 $this->markAsIdentityProperty($propertyName);
287 }
288 }
289 }
290
291 /**
292 * @param \ReflectionClass $reflectionClass
293 */
294 protected function reflectMethods(\ReflectionClass $reflectionClass)
295 {
296 $annotationReader = new AnnotationReader();
297
298 foreach ($reflectionClass->getMethods() as $reflectionMethod) {
299 $methodName = $reflectionMethod->getName();
300
301 $this->methods[$methodName] = [];
302 $this->methods[$methodName]['private'] = $reflectionMethod->isPrivate();
303 $this->methods[$methodName]['protected'] = $reflectionMethod->isProtected();
304 $this->methods[$methodName]['public'] = $reflectionMethod->isPublic();
305 $this->methods[$methodName]['static'] = $reflectionMethod->isStatic();
306 $this->methods[$methodName]['abstract'] = $reflectionMethod->isAbstract();
307 $this->methods[$methodName]['params'] = [];
308 $this->methods[$methodName]['tags'] = [];
309 $this->methods[$methodName]['annotations'] = [];
310
311 $docCommentParser = new DocCommentParser(true);
312 $docCommentParser->parseDocComment($reflectionMethod->getDocComment());
313
314 $this->methods[$methodName]['annotations']['validators'] = [];
315
316 foreach ($docCommentParser->getTagsValues() as $tag => $values) {
317 if ($tag === 'ignorevalidation') {
318 trigger_error(
319 'Tagging methods with @ignorevalidation is deprecated and will be removed in TYPO3 v10.0.',
320 E_USER_DEPRECATED
321 );
322 }
323 if ($tag === 'validate') {
324 $this->methods[$methodName]['annotations']['validators'] = $values;
325 }
326 $this->methods[$methodName]['tags'][$tag] = array_map(function ($value) use ($tag) {
327 // not stripping the dollar sign for @validate annotations is just
328 // a quick fix for a regression introduced in 9.0.0.
329 // This exception to the rules will vanish once the resolving of
330 // validators will take place inside this class and not in the
331 // controller during runtime.
332 return $tag === 'validate' ? $value : ltrim($value, '$');
333 }, $values);
334 }
335
336 foreach ($annotationReader->getMethodAnnotations($reflectionMethod) as $annotation) {
337 if ($annotation instanceof IgnoreValidation) {
338 $this->methods[$methodName]['tags']['ignorevalidation'][] = $annotation->argumentName;
339 }
340 }
341
342 $this->methods[$methodName]['description'] = $docCommentParser->getDescription();
343
344 foreach ($reflectionMethod->getParameters() as $parameterPosition => $reflectionParameter) {
345 /* @var $reflectionParameter \ReflectionParameter */
346
347 $parameterName = $reflectionParameter->getName();
348
349 $this->methods[$methodName]['params'][$parameterName] = [];
350 $this->methods[$methodName]['params'][$parameterName]['position'] = $parameterPosition; // compat
351 $this->methods[$methodName]['params'][$parameterName]['byReference'] = $reflectionParameter->isPassedByReference(); // compat
352 $this->methods[$methodName]['params'][$parameterName]['array'] = $reflectionParameter->isArray(); // compat
353 $this->methods[$methodName]['params'][$parameterName]['optional'] = $reflectionParameter->isOptional();
354 $this->methods[$methodName]['params'][$parameterName]['allowsNull'] = $reflectionParameter->allowsNull(); // compat
355 $this->methods[$methodName]['params'][$parameterName]['class'] = null; // compat
356 $this->methods[$methodName]['params'][$parameterName]['type'] = null;
357 $this->methods[$methodName]['params'][$parameterName]['nullable'] = $reflectionParameter->allowsNull();
358 $this->methods[$methodName]['params'][$parameterName]['default'] = null;
359 $this->methods[$methodName]['params'][$parameterName]['hasDefaultValue'] = $reflectionParameter->isDefaultValueAvailable();
360 $this->methods[$methodName]['params'][$parameterName]['defaultValue'] = null; // compat
361 $this->methods[$methodName]['params'][$parameterName]['dependency'] = null; // Extbase DI
362
363 if ($reflectionParameter->isDefaultValueAvailable()) {
364 $this->methods[$methodName]['params'][$parameterName]['default'] = $reflectionParameter->getDefaultValue();
365 $this->methods[$methodName]['params'][$parameterName]['defaultValue'] = $reflectionParameter->getDefaultValue(); // compat
366 }
367
368 if (($reflectionType = $reflectionParameter->getType()) instanceof \ReflectionType) {
369 $this->methods[$methodName]['params'][$parameterName]['type'] = (string)$reflectionType;
370 $this->methods[$methodName]['params'][$parameterName]['nullable'] = $reflectionType->allowsNull();
371 }
372
373 if (($parameterClass = $reflectionParameter->getClass()) instanceof \ReflectionClass) {
374 $this->methods[$methodName]['params'][$parameterName]['class'] = $parameterClass->getName();
375 $this->methods[$methodName]['params'][$parameterName]['type'] = ltrim($parameterClass->getName(), '\\');
376 } else {
377 $methodTagsAndValues = $this->methods[$methodName]['tags'];
378 if (isset($methodTagsAndValues['param'], $methodTagsAndValues['param'][$parameterPosition])) {
379 $explodedParameters = explode(' ', $methodTagsAndValues['param'][$parameterPosition]);
380 if (count($explodedParameters) >= 2) {
381 if (TypeHandlingUtility::isSimpleType($explodedParameters[0])) {
382 // ensure that short names of simple types are resolved correctly to the long form
383 // this is important for all kinds of type checks later on
384 $typeInfo = TypeHandlingUtility::parseType($explodedParameters[0]);
385
386 $this->methods[$methodName]['params'][$parameterName]['type'] = ltrim($typeInfo['type'], '\\');
387 } else {
388 $this->methods[$methodName]['params'][$parameterName]['type'] = ltrim($explodedParameters[0], '\\');
389 }
390 }
391 }
392 }
393
394 // Extbase DI
395 if ($reflectionParameter->getClass() instanceof \ReflectionClass
396 && ($reflectionMethod->isConstructor() || $this->hasInjectMethodName($reflectionMethod))
397 ) {
398 $this->methods[$methodName]['params'][$parameterName]['dependency'] = $reflectionParameter->getClass()->getName();
399 }
400 }
401
402 // Extbase
403 $this->methods[$methodName]['injectMethod'] = false;
404 if ($this->hasInjectMethodName($reflectionMethod)
405 && count($this->methods[$methodName]['params']) === 1
406 && reset($this->methods[$methodName]['params'])['dependency'] !== null
407 ) {
408 $this->methods[$methodName]['injectMethod'] = true;
409 $this->injectMethods[] = $methodName;
410 }
411 }
412 }
413
414 /**
415 * Returns the class name this schema is referring to
416 *
417 * @return string The class name
418 */
419 public function getClassName(): string
420 {
421 return $this->className;
422 }
423
424 /**
425 * Adds (defines) a specific property and its type.
426 *
427 * @param string $name Name of the property
428 * @param string $type Type of the property
429 * @param bool $lazy Whether the property should be lazy-loaded when reconstituting
430 * @param string $cascade Strategy to cascade the object graph.
431 * @deprecated
432 */
433 public function addProperty($name, $type, $lazy = false, $cascade = '')
434 {
435 trigger_error(
436 'This method will be removed in TYPO3 v10.0, properties will be automatically added on ClassSchema construction.',
437 E_USER_DEPRECATED
438 );
439 $type = TypeHandlingUtility::parseType($type);
440 $this->properties[$name] = [
441 'type' => $type['type'],
442 'elementType' => $type['elementType'],
443 'lazy' => $lazy,
444 'cascade' => $cascade
445 ];
446 }
447
448 /**
449 * Returns the given property defined in this schema. Check with
450 * hasProperty($propertyName) before!
451 *
452 * @param string $propertyName
453 * @return array
454 */
455 public function getProperty($propertyName)
456 {
457 return is_array($this->properties[$propertyName]) ? $this->properties[$propertyName] : [];
458 }
459
460 /**
461 * Returns all properties defined in this schema
462 *
463 * @return array
464 */
465 public function getProperties()
466 {
467 return $this->properties;
468 }
469
470 /**
471 * Sets the model type of the class this schema is referring to.
472 *
473 * @param int $modelType The model type, one of the MODELTYPE_* constants.
474 * @throws \InvalidArgumentException
475 * @deprecated
476 */
477 public function setModelType($modelType)
478 {
479 trigger_error(
480 'This method will be removed in TYPO3 v10.0, modelType will be automatically set on ClassSchema construction.',
481 E_USER_DEPRECATED
482 );
483 if ($modelType < self::MODELTYPE_ENTITY || $modelType > self::MODELTYPE_VALUEOBJECT) {
484 throw new \InvalidArgumentException('"' . $modelType . '" is an invalid model type.', 1212519195);
485 }
486 $this->modelType = $modelType;
487 }
488
489 /**
490 * Returns the model type of the class this schema is referring to.
491 *
492 * @return int The model type, one of the MODELTYPE_* constants.
493 * @deprecated
494 */
495 public function getModelType()
496 {
497 trigger_error(
498 'This method will be removed in TYPO3 v10.0.',
499 E_USER_DEPRECATED
500 );
501 return $this->modelType;
502 }
503
504 /**
505 * Marks the class if it is root of an aggregate and therefore accessible
506 * through a repository - or not.
507 *
508 * @param bool $isRoot TRUE if it is the root of an aggregate
509 */
510 public function setAggregateRoot($isRoot)
511 {
512 $this->aggregateRoot = $isRoot;
513 }
514
515 /**
516 * Whether the class is an aggregate root and therefore accessible through
517 * a repository.
518 *
519 * @return bool TRUE if it is managed
520 */
521 public function isAggregateRoot(): bool
522 {
523 return $this->aggregateRoot;
524 }
525
526 /**
527 * If the class schema has a certain property.
528 *
529 * @param string $propertyName Name of the property
530 * @return bool
531 */
532 public function hasProperty($propertyName): bool
533 {
534 return array_key_exists($propertyName, $this->properties);
535 }
536
537 /**
538 * Sets the property marked as uuid of an object with @uuid
539 *
540 * @param string $propertyName
541 * @throws \InvalidArgumentException
542 * @deprecated
543 */
544 public function setUuidPropertyName($propertyName)
545 {
546 trigger_error(
547 'Tagging properties with @uuid is deprecated and will be removed in TYPO3 v10.0.',
548 E_USER_DEPRECATED
549 );
550 if (!array_key_exists($propertyName, $this->properties)) {
551 throw new \InvalidArgumentException('Property "' . $propertyName . '" must be added to the class schema before it can be marked as UUID property.', 1233863842);
552 }
553 $this->uuidPropertyName = $propertyName;
554 }
555
556 /**
557 * Gets the name of the property marked as uuid of an object
558 *
559 * @return string
560 * @deprecated
561 */
562 public function getUuidPropertyName()
563 {
564 trigger_error(
565 'Tagging properties with @uuid is deprecated and will be removed in TYPO3 v10.0.',
566 E_USER_DEPRECATED
567 );
568 return $this->uuidPropertyName;
569 }
570
571 /**
572 * Marks the given property as one of properties forming the identity
573 * of an object. The property must already be registered in the class
574 * schema.
575 *
576 * @param string $propertyName
577 * @throws \InvalidArgumentException
578 * @deprecated
579 */
580 public function markAsIdentityProperty($propertyName)
581 {
582 trigger_error(
583 'Tagging properties with @identity is deprecated and will be removed in TYPO3 v10.0.',
584 E_USER_DEPRECATED
585 );
586 if (!array_key_exists($propertyName, $this->properties)) {
587 throw new \InvalidArgumentException('Property "' . $propertyName . '" must be added to the class schema before it can be marked as identity property.', 1233775407);
588 }
589 if ($this->properties[$propertyName]['annotations']['lazy'] === true) {
590 throw new \InvalidArgumentException('Property "' . $propertyName . '" must not be makred for lazy loading to be marked as identity property.', 1239896904);
591 }
592 $this->identityProperties[$propertyName] = $this->properties[$propertyName]['type'];
593 }
594
595 /**
596 * Gets the properties (names and types) forming the identity of an object.
597 *
598 * @return array
599 * @see markAsIdentityProperty()
600 * @deprecated
601 */
602 public function getIdentityProperties()
603 {
604 trigger_error(
605 'Tagging properties with @identity is deprecated and will be removed in TYPO3 v10.0.',
606 E_USER_DEPRECATED
607 );
608 return $this->identityProperties;
609 }
610
611 /**
612 * @return bool
613 */
614 public function hasConstructor(): bool
615 {
616 return isset($this->methods['__construct']);
617 }
618
619 /**
620 * @param string $name
621 * @return array
622 */
623 public function getMethod(string $name): array
624 {
625 return $this->methods[$name] ?? [];
626 }
627
628 /**
629 * @return array
630 */
631 public function getMethods(): array
632 {
633 return $this->methods;
634 }
635
636 /**
637 * @param \ReflectionMethod $reflectionMethod
638 * @return bool
639 */
640 protected function hasInjectMethodName(\ReflectionMethod $reflectionMethod): bool
641 {
642 $methodName = $reflectionMethod->getName();
643 if ($methodName === 'injectSettings' || !$reflectionMethod->isPublic()) {
644 return false;
645 }
646
647 if (
648 strpos($reflectionMethod->getName(), 'inject') === 0
649 ) {
650 return true;
651 }
652
653 return false;
654 }
655
656 /**
657 * @return bool
658 * @internal
659 */
660 public function isModel(): bool
661 {
662 return $this->isEntity() || $this->isValueObject();
663 }
664
665 /**
666 * @return bool
667 * @internal
668 */
669 public function isEntity(): bool
670 {
671 return $this->modelType === static::MODELTYPE_ENTITY;
672 }
673
674 /**
675 * @return bool
676 * @internal
677 */
678 public function isValueObject(): bool
679 {
680 return $this->modelType === static::MODELTYPE_VALUEOBJECT;
681 }
682
683 /**
684 * @return bool
685 */
686 public function isSingleton(): bool
687 {
688 return $this->isSingleton;
689 }
690
691 /**
692 * @param string $methodName
693 * @return bool
694 */
695 public function hasMethod(string $methodName): bool
696 {
697 return isset($this->methods[$methodName]);
698 }
699
700 /**
701 * @return array
702 */
703 public function getTags(): array
704 {
705 return $this->tags;
706 }
707
708 /**
709 * @return bool
710 */
711 public function hasInjectProperties(): bool
712 {
713 return count($this->injectProperties) > 0;
714 }
715
716 /**
717 * @return bool
718 */
719 public function hasInjectMethods(): bool
720 {
721 return count($this->injectMethods) > 0;
722 }
723
724 /**
725 * @return array
726 */
727 public function getInjectMethods(): array
728 {
729 $injectMethods = [];
730 foreach ($this->injectMethods as $injectMethodName) {
731 $injectMethods[$injectMethodName] = reset($this->methods[$injectMethodName]['params'])['dependency'];
732 }
733
734 return $injectMethods;
735 }
736
737 /**
738 * @return array
739 */
740 public function getInjectProperties(): array
741 {
742 $injectProperties = [];
743 foreach ($this->injectProperties as $injectPropertyName) {
744 $injectProperties[$injectPropertyName] = $this->properties[$injectPropertyName]['annotations']['dependency'];
745 }
746
747 return $injectProperties;
748 }
749
750 /**
751 * @return array
752 */
753 public function getConstructorArguments(): array
754 {
755 if (!$this->hasConstructor()) {
756 return [];
757 }
758
759 return $this->methods['__construct']['params'];
760 }
761 }