/** * {@inheritDoc} */ public function getMethodAnnotations(ReflectionMethod $method) { $class = $method->getDeclaringClass(); $context = 'method ' . $class->getName() . '::' . $method->getName() . '()'; $this->parser->setTarget(Target::TARGET_METHOD); $this->parser->setImports($this->getMethodImports($method)); $this->parser->setIgnoredAnnotationNames($this->getIgnoredAnnotationNames($class)); return $this->parser->parse($method->getDocComment(), $context); }
/** * Collects parsing metadata for a given annotation class * * @param string $name The annotation name */ private function collectAnnotationMetadata($name) { if (self::$metadataParser == null) { self::$metadataParser = new self(); self::$metadataParser->setTarget(Target::TARGET_CLASS); self::$metadataParser->setIgnoreNotImportedAnnotations(true); self::$metadataParser->setImports(array('target' => 'Doctrine\\Common\\Annotations\\Annotation\\Target', 'attribute' => 'Doctrine\\Common\\Annotations\\Annotation\\Attribute', 'attributes' => 'Doctrine\\Common\\Annotations\\Annotation\\Attributes')); AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Target.php'); AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Attribute.php'); AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Attributes.php'); } $class = new \ReflectionClass($name); $docComment = $class->getDocComment(); // Sets default values for annotation metadata $metadata = array('default_property' => null, 'has_constructor' => null !== ($constructor = $class->getConstructor()) && $constructor->getNumberOfParameters() > 0, 'properties' => array(), 'property_types' => array(), 'attribute_types' => array(), 'targets_literal' => null, 'targets' => Target::TARGET_ALL, 'is_annotation' => false !== strpos($docComment, '@Annotation')); // verify that the class is really meant to be an annotation if ($metadata['is_annotation']) { foreach (self::$metadataParser->parse($docComment, 'class @' . $name) as $annotation) { if ($annotation instanceof Target) { $metadata['targets'] = $annotation->targets; $metadata['targets_literal'] = $annotation->literal; } elseif ($annotation instanceof Attributes) { foreach ($annotation->value as $attrib) { // handle internal type declaration $type = isset(self::$typeMap[$attrib->type]) ? self::$typeMap[$attrib->type] : $attrib->type; // handle the case if the property type is mixed if ('mixed' !== $type) { // Checks if the property has array<type> if (false !== ($pos = strpos($type, '<'))) { $arrayType = substr($type, $pos + 1, -1); $type = 'array'; if (isset(self::$typeMap[$arrayType])) { $arrayType = self::$typeMap[$arrayType]; } $metadata['attribute_types'][$attrib->name]['array_type'] = $arrayType; } $metadata['attribute_types'][$attrib->name]['type'] = $type; $metadata['attribute_types'][$attrib->name]['value'] = $attrib->type; $metadata['attribute_types'][$attrib->name]['required'] = $attrib->required; } } } } // if not has a constructor will inject values into public properties if (false === $metadata['has_constructor']) { // collect all public properties foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) { $metadata['properties'][$property->name] = $property->name; // checks if the property has @var annotation if (false !== ($propertyComment = $property->getDocComment()) && false !== strpos($propertyComment, '@var') && preg_match('/@var\\s+([^\\s]+)/', $propertyComment, $matches)) { // literal type declaration $value = $matches[1]; // handle internal type declaration $type = isset(self::$typeMap[$value]) ? self::$typeMap[$value] : $value; // handle the case if the property type is mixed if ('mixed' !== $type) { // Checks if the property has @var array<type> annotation if (false !== ($pos = strpos($type, '<'))) { $arrayType = substr($type, $pos + 1, -1); $type = 'array'; if (isset(self::$typeMap[$arrayType])) { $arrayType = self::$typeMap[$arrayType]; } $metadata['attribute_types'][$property->name]['array_type'] = $arrayType; } $metadata['attribute_types'][$property->name]['type'] = $type; $metadata['attribute_types'][$property->name]['value'] = $value; $metadata['attribute_types'][$property->name]['required'] = false !== strpos($propertyComment, '@Required'); } } } // choose the first property as default property $metadata['default_property'] = reset($metadata['properties']); } } self::$annotationMetadata[$name] = $metadata; }
/** * Collects parsing metadata for a given annotation class * * @param string $name The annotation name * * @return void */ private function collectAnnotationMetadata($name) { if (self::$metadataParser === null) { self::$metadataParser = new self(); self::$metadataParser->setIgnoreNotImportedAnnotations(true); self::$metadataParser->setIgnoredAnnotationNames($this->ignoredAnnotationNames); self::$metadataParser->setImports(array('enum' => 'Doctrine\\Common\\Annotations\\Annotation\\Enum', 'target' => 'Doctrine\\Common\\Annotations\\Annotation\\Target', 'attribute' => 'Doctrine\\Common\\Annotations\\Annotation\\Attribute', 'attributes' => 'Doctrine\\Common\\Annotations\\Annotation\\Attributes')); AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Enum.php'); AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Target.php'); AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Attribute.php'); AnnotationRegistry::registerFile(__DIR__ . '/Annotation/Attributes.php'); } $class = new \ReflectionClass($name); $docComment = $class->getDocComment(); // Sets default values for annotation metadata $metadata = array('default_property' => null, 'has_constructor' => null !== ($constructor = $class->getConstructor()) && $constructor->getNumberOfParameters() > 0, 'properties' => array(), 'property_types' => array(), 'attribute_types' => array(), 'targets_literal' => null, 'targets' => Target::TARGET_ALL, 'is_annotation' => false !== strpos($docComment, '@Annotation')); // verify that the class is really meant to be an annotation if ($metadata['is_annotation']) { self::$metadataParser->setTarget(Target::TARGET_CLASS); foreach (self::$metadataParser->parse($docComment, 'class @' . $name) as $annotation) { if ($annotation instanceof Target) { $metadata['targets'] = $annotation->targets; $metadata['targets_literal'] = $annotation->literal; continue; } if ($annotation instanceof Attributes) { foreach ($annotation->value as $attribute) { $this->collectAttributeTypeMetadata($metadata, $attribute); } } } // if not has a constructor will inject values into public properties if (false === $metadata['has_constructor']) { // collect all public properties foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) { $metadata['properties'][$property->name] = $property->name; if (false === ($propertyComment = $property->getDocComment())) { continue; } $attribute = new Attribute(); $attribute->required = false !== strpos($propertyComment, '@Required'); $attribute->name = $property->name; $attribute->type = false !== strpos($propertyComment, '@var') && preg_match('/@var\\s+([^\\s]+)/', $propertyComment, $matches) ? $matches[1] : 'mixed'; $this->collectAttributeTypeMetadata($metadata, $attribute); // checks if the property has @Enum if (false !== strpos($propertyComment, '@Enum')) { $context = 'property ' . $class->name . "::\$" . $property->name; self::$metadataParser->setTarget(Target::TARGET_PROPERTY); foreach (self::$metadataParser->parse($propertyComment, $context) as $annotation) { if (!$annotation instanceof Enum) { continue; } $metadata['enum'][$property->name]['value'] = $annotation->value; $metadata['enum'][$property->name]['literal'] = !empty($annotation->literal) ? $annotation->literal : $annotation->value; } } } // choose the first property as default property $metadata['default_property'] = reset($metadata['properties']); } } self::$annotationMetadata[$name] = $metadata; }
public function testAnnotationTarget() { $parser = new DocParser(); $parser->setImports(array('__NAMESPACE__' => 'Doctrine\\Tests\\Common\\Annotations\\Fixtures')); $class = new \ReflectionClass('Doctrine\\Tests\\Common\\Annotations\\Fixtures\\ClassWithValidAnnotationTarget'); $context = 'class ' . $class->getName(); $docComment = $class->getDocComment(); $parser->setTarget(Target::TARGET_CLASS); $this->assertNotNull($parser->parse($docComment, $context)); $property = $class->getProperty('foo'); $docComment = $property->getDocComment(); $context = 'property ' . $class->getName() . "::\$" . $property->getName(); $parser->setTarget(Target::TARGET_PROPERTY); $this->assertNotNull($parser->parse($docComment, $context)); $method = $class->getMethod('someFunction'); $docComment = $property->getDocComment(); $context = 'method ' . $class->getName() . '::' . $method->getName() . '()'; $parser->setTarget(Target::TARGET_METHOD); $this->assertNotNull($parser->parse($docComment, $context)); try { $class = new \ReflectionClass('Doctrine\\Tests\\Common\\Annotations\\Fixtures\\ClassWithInvalidAnnotationTargetAtClass'); $context = 'class ' . $class->getName(); $docComment = $class->getDocComment(); $parser->setTarget(Target::TARGET_CLASS); $parser->parse($class->getDocComment(), $context); $this->fail(); } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { $this->assertNotNull($exc->getMessage()); } try { $class = new \ReflectionClass('Doctrine\\Tests\\Common\\Annotations\\Fixtures\\ClassWithInvalidAnnotationTargetAtMethod'); $method = $class->getMethod('functionName'); $docComment = $method->getDocComment(); $context = 'method ' . $class->getName() . '::' . $method->getName() . '()'; $parser->setTarget(Target::TARGET_METHOD); $parser->parse($docComment, $context); $this->fail(); } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { $this->assertNotNull($exc->getMessage()); } try { $class = new \ReflectionClass('Doctrine\\Tests\\Common\\Annotations\\Fixtures\\ClassWithInvalidAnnotationTargetAtProperty'); $property = $class->getProperty('foo'); $docComment = $property->getDocComment(); $context = 'property ' . $class->getName() . "::\$" . $property->getName(); $parser->setTarget(Target::TARGET_PROPERTY); $parser->parse($docComment, $context); $this->fail(); } catch (\Doctrine\Common\Annotations\AnnotationException $exc) { $this->assertNotNull($exc->getMessage()); } }
/** * Gets the annotations applied to a property. * * @param ReflectionProperty $property The ReflectionProperty of the property * from which the annotations should be read. * @return array An array of Annotations. */ public function getPropertyAnnotations(\ReflectionProperty $property) { $this->parser->setTarget(Target::TARGET_PROPERTY); return $this->parser->parse($property->getDocComment(), 'property ' . $property->getDeclaringClass()->name . '::$' . $property->getName()); }