/**
  * Reflects the given class and stores the results in this service's properties.
  *
  * @param string $className Full qualified name of the class to reflect
  * @return void
  * @throws Exception\InvalidClassException
  */
 protected function reflectClass($className)
 {
     $this->log(sprintf('Reflecting class %s', $className), LOG_DEBUG);
     $className = $this->cleanClassName($className);
     if (strpos($className, 'TYPO3\\Flow\\Persistence\\Doctrine\\Proxies') === 0 && in_array(\Doctrine\ORM\Proxy\Proxy::class, class_implements($className))) {
         // Somebody tried to reflect a doctrine proxy, which will have severe side effects.
         // see bug http://forge.typo3.org/issues/29449 for details.
         throw new Exception\InvalidClassException('The class with name "' . $className . '" is a Doctrine proxy. It is not supported to reflect doctrine proxy classes.', 1314944681);
     }
     $class = new ClassReflection($className);
     if (!isset($this->classReflectionData[$className])) {
         $this->classReflectionData[$className] = [];
     }
     if ($class->isAbstract() || $class->isInterface()) {
         $this->classReflectionData[$className][self::DATA_CLASS_ABSTRACT] = true;
     }
     if ($class->isFinal()) {
         $this->classReflectionData[$className][self::DATA_CLASS_FINAL] = true;
     }
     /** @var $parentClass ClassReflection */
     foreach ($this->getParentClasses($class) as $parentClass) {
         $this->addParentClass($className, $parentClass);
     }
     /** @var $interface ClassReflection */
     foreach ($class->getInterfaces() as $interface) {
         $this->addImplementedInterface($className, $interface);
     }
     foreach ($this->annotationReader->getClassAnnotations($class) as $annotation) {
         $annotationClassName = get_class($annotation);
         $this->annotatedClasses[$annotationClassName][$className] = true;
         $this->classReflectionData[$className][self::DATA_CLASS_ANNOTATIONS][] = $annotation;
     }
     /** @var $property PropertyReflection */
     foreach ($class->getProperties() as $property) {
         $this->reflectClassProperty($className, $property);
     }
     foreach ($class->getMethods() as $method) {
         $this->reflectClassMethod($className, $method);
     }
     // Sort reflection data so that the cache data is deterministic. This is
     // important for comparisons when checking if classes have changed in a
     // Development context.
     ksort($this->classReflectionData);
     $this->updatedReflectionData[$className] = true;
 }
예제 #2
0
 /**
  * Reflects the given class and stores the results in this service's properties.
  *
  * @param string $className Full qualified name of the class to reflect
  * @return void
  * @throws \TYPO3\Flow\Reflection\Exception\InvalidClassException
  */
 protected function reflectClass($className)
 {
     $this->log(sprintf('Reflecting class %s', $className), LOG_DEBUG);
     $className = trim($className, '\\');
     if (strpos($className, 'TYPO3\\Flow\\Persistence\\Doctrine\\Proxies') === 0 && array_search('Doctrine\\ORM\\Proxy\\Proxy', class_implements($className))) {
         // Somebody tried to reflect a doctrine proxy, which will have severe side effects.
         // see bug http://forge.typo3.org/issues/29449 for details.
         throw new Exception\InvalidClassException('The class with name "' . $className . '" is a Doctrine proxy. It is not supported to reflect doctrine proxy classes.', 1314944681);
     }
     try {
         $class = new ClassReflection($className);
     } catch (Exception\ClassLoadingForReflectionFailedException $exception) {
         $this->markClassUnconfigurable($className);
         $this->log('Could not reflect "' . $className . '" because the class could not be loaded.', LOG_DEBUG);
         return;
     }
     if (!isset($this->classReflectionData[$className])) {
         $this->classReflectionData[$className] = array();
     }
     if ($class->isAbstract()) {
         $this->classReflectionData[$className][self::DATA_CLASS_ABSTRACT] = TRUE;
     }
     if ($class->isFinal()) {
         $this->classReflectionData[$className][self::DATA_CLASS_FINAL] = TRUE;
     }
     /** @var $parentClass \TYPO3\Flow\Reflection\ClassReflection */
     foreach ($this->getParentClasses($class) as $parentClass) {
         $parentClassName = $parentClass->getName();
         if (!isset($this->classReflectionData[$parentClassName])) {
             $this->reflectClass($parentClassName);
         }
         $this->classReflectionData[$parentClassName][self::DATA_CLASS_SUBCLASSES][$className] = TRUE;
     }
     /** @var $interface \TYPO3\Flow\Reflection\ClassReflection */
     foreach ($class->getInterfaces() as $interface) {
         if (!isset($this->classReflectionData[$className][self::DATA_CLASS_ABSTRACT])) {
             $interfaceName = $interface->getName();
             if (!isset($this->classReflectionData[$interfaceName])) {
                 $this->reflectClass($interfaceName);
             }
             $this->classReflectionData[$interfaceName][self::DATA_INTERFACE_IMPLEMENTATIONS][$className] = TRUE;
         }
     }
     foreach ($this->annotationReader->getClassAnnotations($class) as $annotation) {
         $annotationClassName = get_class($annotation);
         $this->annotatedClasses[$annotationClassName][$className] = TRUE;
         $this->classReflectionData[$className][self::DATA_CLASS_ANNOTATIONS][] = $annotation;
     }
     /** @var $property \TYPO3\Flow\Reflection\PropertyReflection */
     foreach ($class->getProperties() as $property) {
         $propertyName = $property->getName();
         $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName] = array();
         $visibility = $property->isPublic() ? self::VISIBILITY_PUBLIC : ($property->isProtected() ? self::VISIBILITY_PROTECTED : self::VISIBILITY_PRIVATE);
         $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_VISIBILITY] = $visibility;
         foreach ($property->getTagsValues() as $tag => $values) {
             if (array_search($tag, $this->settings['reflection']['ignoredTags']) === FALSE) {
                 if ($tag === 'var' && isset($values[0])) {
                     if ($property->getDeclaringClass()->getName() !== $className && isset($this->classReflectionData[$property->getDeclaringClass()->getName()][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tag])) {
                         $values = $this->classReflectionData[$property->getDeclaringClass()->getName()][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tag];
                     } else {
                         $values[0] = $this->expandType($class, $values[0]);
                     }
                 }
                 $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tag] = $values;
             }
         }
         foreach ($this->annotationReader->getPropertyAnnotations($property, $propertyName) as $annotation) {
             $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_ANNOTATIONS][get_class($annotation)][] = $annotation;
         }
     }
     /** @var $method \TYPO3\Flow\Reflection\MethodReflection */
     foreach ($class->getMethods() as $method) {
         $methodName = $method->getName();
         if ($method->isFinal()) {
             $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_FINAL] = TRUE;
         }
         if ($method->isStatic()) {
             $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_STATIC] = TRUE;
         }
         $visibility = $method->isPublic() ? self::VISIBILITY_PUBLIC : ($method->isProtected() ? self::VISIBILITY_PROTECTED : self::VISIBILITY_PRIVATE);
         $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_VISIBILITY] = $visibility;
         foreach ($this->getMethodAnnotations($className, $methodName) as $methodAnnotation) {
             $this->classesByMethodAnnotations[get_class($methodAnnotation)][$className] = $methodName;
         }
         $paramAnnotations = $method->isTaggedWith('param') ? $method->getTagValues('param') : array();
         /** @var $parameter \TYPO3\Flow\Reflection\ParameterReflection */
         foreach ($method->getParameters() as $parameter) {
             $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_PARAMETERS][$parameter->getName()] = $this->convertParameterReflectionToArray($parameter, $method);
             if ($this->settings['reflection']['logIncorrectDocCommentHints'] === TRUE) {
                 if (isset($paramAnnotations[$parameter->getPosition()])) {
                     $parameterAnnotation = explode(' ', $paramAnnotations[$parameter->getPosition()], 3);
                     if (count($parameterAnnotation) < 2) {
                         $this->log('  Wrong @param use for "' . $method->getName() . '::' . $parameter->getName() . '": "' . implode(' ', $parameterAnnotation) . '"', LOG_DEBUG);
                     } else {
                         if (isset($this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_PARAMETERS][$parameter->getName()][self::DATA_PARAMETER_TYPE]) && $this->classReflectionData[$className][self::DATA_CLASS_METHODS][$methodName][self::DATA_METHOD_PARAMETERS][$parameter->getName()][self::DATA_PARAMETER_TYPE] !== ltrim($parameterAnnotation[0], '\\')) {
                             $this->log('  Wrong type in @param for "' . $method->getName() . '::' . $parameter->getName() . '": "' . $parameterAnnotation[0] . '"', LOG_DEBUG);
                         }
                         if ($parameter->getName() !== ltrim($parameterAnnotation[1], '$&')) {
                             $this->log('  Wrong name in @param for "' . $method->getName() . '::$' . $parameter->getName() . '": "' . $parameterAnnotation[1] . '"', LOG_DEBUG);
                         }
                     }
                 } else {
                     $this->log('  Missing @param for "' . $method->getName() . '::$' . $parameter->getName(), LOG_DEBUG);
                 }
             }
         }
     }
     // Sort reflection data so that the cache data is deterministic. This is
     // important for comparisons when checking if classes have changed in a
     // Development context.
     ksort($this->classReflectionData);
     $this->updatedReflectionData[$className] = TRUE;
 }