It is strongly discouraged to change the default annotation parsing process.
protected final function getDocParser() { $docParser = new DocParser(); $docParser->setImports(array('desc' => 'JMS\\TranslationBundle\\Annotation\\Desc', 'meaning' => 'JMS\\TranslationBundle\\Annotation\\Meaning', 'ignore' => 'JMS\\TranslationBundle\\Annotation\\Ignore')); $docParser->setIgnoreNotImportedAnnotations(true); return $docParser; }
public function testIssueWithNamespacesOrImports() { $docblock = "@Entity"; $parser = new DocParser(); $annots = $parser->parse($docblock); $this->assertEquals(1, count($annots)); $this->assertInstanceOf("Entity", $annots[0]); $this->assertEquals(1, count($annots)); }
private function extract($directory) { $twig = new \Twig_Environment(); $twig->addExtension(new SymfonyTranslationExtension($translator = new IdentityTranslator(new MessageSelector()))); $twig->addExtension(new TranslationExtension($translator)); $docParser = new DocParser(); $docParser->setImports(array('desc' => 'JMS\\TranslationBundle\\Annotation\\Desc', 'meaning' => 'JMS\\TranslationBundle\\Annotation\\Meaning', 'ignore' => 'JMS\\TranslationBundle\\Annotation\\Ignore')); $docParser->setIgnoreNotImportedAnnotations(true); $factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $extractor = new FileExtractor($twig, new NullLogger(), array(new DefaultPhpFileExtractor($docParser), new TranslationContainerExtractor(), new TwigFileExtractor($twig), new ValidationExtractor($factory), new FormExtractor($docParser))); $extractor->setDirectory($directory); return $extractor->extract(); }
public function scanForAnnotations(string $docBlock, $context, array $imports) : Annotations { // Hack to ensure an attempt to autoload an annotation class is made AnnotationRegistry::registerLoader(function ($class) { return (bool) class_exists($class); }); $imports = array_combine(array_map(function ($string) { return strtolower($string); }, array_keys($imports)), array_values($imports)); $parser = new DocParser(); $parser->setIgnoreNotImportedAnnotations(true); $parser->setImports($imports); return new Annotations($parser->parse($docBlock, $context)); }
/** * @return AnnotationReader */ public static function getAnnotationReader() { if (self::$annotationReader !== null) { return self::$annotationReader; } //For old AnnotationReader (<=1.2.7) //For new (>1.2.7) version of AnnotationReader, we can give a DocParser since a3c2928912eeb5dc5678352f22c378173def16b6 $parser = new DocParser(); $parser->setIgnoreNotImportedAnnotations(true); self::$annotationReader = new AnnotationReader($parser); //For old version of AnnotationReader (<=1.2.7) , we have to specify manually all ignored annotations foreach (self::$ignoredAnnotationNames as $ignoredAnnotationName) { self::$annotationReader->addGlobalIgnoredName($ignoredAnnotationName); } return self::$annotationReader; }
/** * Dispatch annotations found in phpDoc with context given in second argument. * * @param string $phpDoc phpDoc * @param mixed $context context */ private function processDocComment($phpDoc, $context = null) { $annotations = $this->docParser->parse($phpDoc); foreach ($annotations as $annotation) { $this->collection->dispatch(Events::TOKEN_PHP_ANNOTATION, new Context\PHP\Annotation($annotation, $context), $this->result); } }
/** * @param Node $node * @return void */ public function enterNode(Node $node) { if (!$node instanceof Node\Expr\MethodCall || !is_string($node->name) || !in_array(strtolower($node->name), array_map('strtolower', array_keys($this->methodsToExtractFrom)))) { $this->previousNode = $node; return; } $ignore = false; $desc = $meaning = null; if (null !== ($docComment = $this->getDocCommentForNode($node))) { if ($docComment instanceof Doc) { $docComment = $docComment->getText(); } foreach ($this->docParser->parse($docComment, 'file ' . $this->file . ' near line ' . $node->getLine()) as $annot) { if ($annot instanceof Ignore) { $ignore = true; } elseif ($annot instanceof Desc) { $desc = $annot->text; } elseif ($annot instanceof Meaning) { $meaning = $annot->text; } } } if (!$node->args[0]->value instanceof String_) { if ($ignore) { return; } $message = sprintf('Can only extract the translation id from a scalar string, but got "%s". Please refactor your code to make it extractable, or add the doc comment /** @Ignore */ to this code element (in %s on line %d).', get_class($node->args[0]->value), $this->file, $node->args[0]->value->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } $id = $node->args[0]->value->value; $index = $this->methodsToExtractFrom[strtolower($node->name)]; if (isset($node->args[$index])) { if (!$node->args[$index]->value instanceof String_) { if ($ignore) { return; } $message = sprintf('Can only extract the translation domain from a scalar string, but got "%s". Please refactor your code to make it extractable, or add the doc comment /** @Ignore */ to this code element (in %s on line %d).', get_class($node->args[0]->value), $this->file, $node->args[0]->value->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } $domain = $node->args[$index]->value->value; } else { $domain = 'messages'; } $message = new Message($id, $domain); $message->setDesc($desc); $message->setMeaning($meaning); $message->addSource($this->fileSourceFactory->create($this->file, $node->getLine())); $this->catalogue->add($message); }
/** * {@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); }
private function extract($file, FormExtractor $extractor = null) { if (!is_file($file = __DIR__ . '/Fixture/' . $file)) { throw new RuntimeException(sprintf('The file "%s" does not exist.', $file)); } $file = new \SplFileInfo($file); if (null === $extractor) { $docParser = new DocParser(); $docParser->setImports(array('desc' => 'JMS\\TranslationBundle\\Annotation\\Desc', 'meaning' => 'JMS\\TranslationBundle\\Annotation\\Meaning', 'ignore' => 'JMS\\TranslationBundle\\Annotation\\Ignore')); $docParser->setIgnoreNotImportedAnnotations(true); $extractor = new FormExtractor($docParser); } $lexer = new \PHPParser_Lexer(file_get_contents($file)); $parser = new \PHPParser_Parser(); $ast = $parser->parse($lexer); $catalogue = new MessageCatalogue(); $extractor->visitPhpFile($file, $catalogue, $ast); return $catalogue; }
/** * @group performance */ public function testDocParsePerformance() { $imports = array('ignorephpdoc' => 'Annotations\\Annotation\\IgnorePhpDoc', 'ignoreannotation' => 'Annotations\\Annotation\\IgnoreAnnotation', 'route' => 'Doctrine\\Tests\\Common\\Annotations\\Fixtures\\Annotation\\Route', 'template' => 'Doctrine\\Tests\\Common\\Annotations\\Fixtures\\Annotation\\Template', '__NAMESPACE__' => 'Doctrine\\Tests\\Common\\Annotations\\Fixtures'); $ignored = array('access', 'author', 'copyright', 'deprecated', 'example', 'ignore', 'internal', 'link', 'see', 'since', 'tutorial', 'version', 'package', 'subpackage', 'name', 'global', 'param', 'return', 'staticvar', 'static', 'var', 'throws', 'inheritdoc'); $parser = new DocParser(); $method = $this->getMethod(); $methodComment = $method->getDocComment(); $classComment = $method->getDeclaringClass()->getDocComment(); $time = microtime(true); for ($i = 0, $c = 200; $i < $c; $i++) { $parser = new DocParser(); $parser->setImports($imports); $parser->setIgnoredAnnotationNames($ignored); $parser->parse($methodComment); $parser->parse($classComment); } $time = microtime(true) - $time; $this->printResults('doc-parser', $time, $c); }
private function extract($directory) { $twig = new \Twig_Environment(); $twig->addExtension(new SymfonyTranslationExtension($translator = new IdentityTranslator(new MessageSelector()))); $twig->addExtension(new TranslationExtension($translator)); $loader = new \Twig_Loader_Filesystem(realpath(__DIR__ . "/Fixture/SimpleTest/Resources/views/")); $twig->setLoader($loader); $docParser = new DocParser(); $docParser->setImports(array('desc' => 'JMS\\TranslationBundle\\Annotation\\Desc', 'meaning' => 'JMS\\TranslationBundle\\Annotation\\Meaning', 'ignore' => 'JMS\\TranslationBundle\\Annotation\\Ignore')); $docParser->setIgnoreNotImportedAnnotations(true); //use correct factory class depending on whether using Symfony 2 or 3 if (class_exists('Symfony\\Component\\Validator\\Mapping\\Factory\\LazyLoadingMetadataFactory')) { $metadataFactoryClass = 'Symfony\\Component\\Validator\\Mapping\\Factory\\LazyLoadingMetadataFactory'; } else { $metadataFactoryClass = 'Symfony\\Component\\Validator\\Mapping\\ClassMetadataFactory'; } $factory = new $metadataFactoryClass(new AnnotationLoader(new AnnotationReader())); $extractor = new FileExtractor($twig, new NullLogger(), array(new DefaultPhpFileExtractor($docParser), new TranslationContainerExtractor(), new TwigFileExtractor($twig), new ValidationExtractor($factory), new FormExtractor($docParser))); $extractor->setDirectory($directory); return $extractor->extract(); }
/** * @param $item * @param null $domain */ private function parseItem($item, $domain = null) { // get doc comment $ignore = false; $desc = $meaning = $docComment = null; if ($item->key) { $docComment = $item->key->getDocComment(); } if (!$docComment) { $docComment = $item->value->getDocComment(); } $docComment = is_object($docComment) ? $docComment->getText() : null; if ($docComment) { if ($docComment instanceof Doc) { $docComment = $docComment->getText(); } foreach ($this->docParser->parse($docComment, 'file ' . $this->file . ' near line ' . $item->value->getLine()) as $annot) { if ($annot instanceof Ignore) { $ignore = true; } elseif ($annot instanceof Desc) { $desc = $annot->text; } elseif ($annot instanceof Meaning) { $meaning = $annot->text; } } } // check if the value is explicitly set to false => e.g. for FormField that should be rendered without label $ignore = $ignore || !$item->value instanceof Node\Scalar\String_ || $item->value->value == false; if (!$item->value instanceof Node\Scalar\String_ && !$item->value instanceof Node\Scalar\LNumber) { if ($ignore) { return; } $message = sprintf('Unable to extract translation id for form label/title/placeholder from non-string values, but got "%s" in %s on line %d. Please refactor your code to pass a string, or add "/** @Ignore */".', get_class($item->value), $this->file, $item->value->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } if ($domain === false) { // Don't translate when domain is `false` return; } $source = $this->fileSourceFactory->create($this->file, $item->value->getLine()); $id = $item->value->value; if (null === $domain) { $this->defaultDomainMessages[] = array('id' => $id, 'source' => $source, 'desc' => $desc, 'meaning' => $meaning); } else { $this->addToCatalogue($id, $source, $domain, $desc, $meaning); } }
/** * Use doctrine to parse the comment block and return the detected annotations. * * @param string $comment a T_DOC_COMMENT. * @param Context $context * @return array Annotations */ public function fromComment($comment, $context = null) { if ($context === null) { $context = new Context(['comment' => $comment]); } else { $context->comment = $comment; } try { self::$context = $context; if ($context->is('annotations') === false) { $context->annotations = []; } $comment = preg_replace_callback('/^[\\t ]*\\*[\\t ]+/m', function ($match) { // Replace leading tabs with spaces. // Workaround for http://www.doctrine-project.org/jira/browse/DCOM-255 return str_replace("\t", ' ', $match[0]); }, $comment); $annotations = $this->docParser->parse($comment, $context); self::$context = null; return $annotations; } catch (Exception $e) { self::$context = null; if (preg_match('/^(.+) at position ([0-9]+) in ' . preg_quote($context, '/') . '\\.$/', $e->getMessage(), $matches)) { $errorMessage = $matches[1]; $errorPos = $matches[2]; $atPos = strpos($comment, '@'); $context->line += substr_count($comment, "\n", 0, $atPos + $errorPos); $lines = explode("\n", substr($comment, $atPos, $errorPos)); $context->character = strlen(array_pop($lines)) + 1; // position starts at 0 character starts at 1 Logger::warning(new Exception($errorMessage . ' in ' . $context, $e->getCode(), $e)); } else { Logger::warning($e); } return []; } }
public function register(Application $app) { $app['translation-extractor.logger'] = $app->share(function (Application $app) { return $app['monolog']; }); $app['translation-extractor.doc-parser'] = $app->share(function () { $parser = new DocParser(); $parser->addNamespace("JMS\\TranslationBundle\\Annotation"); return $parser; }); $app['translation-extractor.node-visitors'] = $app->share(function (Application $app) { return [new ConstraintExtractor($app), new ValidationExtractor($app['validator']->getMetadataFactory()), new DefaultPhpFileExtractor($app['translation-extractor.doc-parser']), new TwigFileExtractor($app['twig']), new FormExtractor($app['translation-extractor.doc-parser']), new HelpMessageExtractor($app['translation-extractor.doc-parser'])]; }); $app['translation-extractor.file-extractor'] = $app->share(function (Application $app) { return new FileExtractor($app['twig'], $app['translation-extractor.logger'], $app['translation-extractor.node-visitors']); }); $app['translation-extractor.extractor-manager'] = $app->share(function (Application $app) { return new ExtractorManager($app['translation-extractor.file-extractor'], $app['translation-extractor.logger']); }); $app['translation-extractor.writer'] = $app->share(function (Application $app) { return new FileWriter($app['translation-extractor.writers']); }); $app['translation-extractor.writers'] = $app->share(function () { return ['po' => new SymfonyDumperAdapter(new PoFileDumper(), 'po'), 'xlf' => new XliffDumper()]; }); $app['translation-extractor.loader-manager'] = $app->share(function (Application $app) { return new LoaderManager($app['translation-extractor.loaders']); }); $app['translation-extractor.loaders'] = $app->share(function () { return ['po' => new SymfonyLoaderAdapter(new PoFileLoader()), 'xlf' => new XliffLoader()]; }); $app['translation-extractor.updater'] = $app->share(function (Application $app) { AnnotationRegistry::registerAutoloadNamespace('JMS\\TranslationBundle\\Annotation', $app['root.path'] . '/vendor/jms/translation-bundle'); return new Updater($app['translation-extractor.loader-manager'], $app['translation-extractor.extractor-manager'], $app['translation-extractor.logger'], $app['translation-extractor.writer']); }); }
/** * Collects parsing metadata for a given class. * * @param \ReflectionClass $class */ private function collectParsingMetadata(ReflectionClass $class) { $ignoredAnnotationNames = self::$globalIgnoredNames; $annotations = $this->preParser->parse($class->getDocComment(), 'class ' . $class->name); foreach ($annotations as $annotation) { if ($annotation instanceof IgnoreAnnotation) { foreach ($annotation->names as $annot) { $ignoredAnnotationNames[$annot] = true; } } } $name = $class->getName(); $this->imports[$name] = array_merge(self::$globalImports, $this->phpParser->parseClass($class), array('__NAMESPACE__' => $class->getNamespaceName())); $this->ignoredAnnotationNames[$name] = $ignoredAnnotationNames; }
/** * @param Node $node */ public function enterNode(Node $node) { if (!$node instanceof Node\Expr\New_ || !is_string($node->class) || strtolower($node->class) !== 'validationerror') { $this->previousNode = $node; return; } $ignore = false; $desc = $meaning = null; if (null !== ($docComment = $this->getDocCommentForNode($node))) { if ($docComment instanceof Doc) { $docComment = $docComment->getText(); } foreach ($this->docParser->parse($docComment, 'file ' . $this->file . ' near line ' . $node->getLine()) as $annot) { if ($annot instanceof Ignore) { $ignore = true; } elseif ($annot instanceof Desc) { $desc = $annot->text; } elseif ($annot instanceof Meaning) { $meaning = $annot->text; } } } if (!$node->args[0]->value instanceof String_) { if ($ignore) { return; } $message = sprintf('Can only extract the translation id from a scalar string, but got "%s". Please refactor your code to make it extractable, or add the doc comment /** @Ignore */ to this code element (in %s on line %d).', get_class($node->args[0]->value), $this->file, $node->args[0]->value->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } $message = new Message($node->args[0]->value->value, $this->defaultDomain); $message->setDesc($desc); $message->setMeaning($meaning); $message->addSource($this->fileSourceFactory->create($this->file, $node->getLine())); $this->catalogue->add($message); // plural if ($node->args[1]->value instanceof String_) { $message = new Message($node->args[1]->value->value, $this->defaultDomain); $message->setDesc($desc); $message->setMeaning($meaning); $message->addSource($this->fileSourceFactory->create($this->file, $node->getLine())); $this->catalogue->add($message); } }
/** * @param RefComment $comment * * @return Annotation[] */ private function parseComment(RefComment $comment = null) { if ($comment === null) { return []; } $annotations = $this->docParser->parse($comment->text); foreach ($annotations as $key => $annotation) { if (!$annotation instanceof Annotation) { unset($annotations[$key]); continue; } if ($annotation instanceof ContentInterface) { $content = $this->extractContent($comment->text, get_class($annotation)); $annotation->setContent($content); } } return $annotations; }
/** * * @param Context $context * @return AbstractAnnotation[] */ protected function parseContext($context) { try { self::$context = $context; $annotations = $this->docParser->parse($context->comment, $context); self::$context = null; } catch (\Exception $e) { self::$context = null; if (preg_match('/^(.+) at position ([0-9]+) in ' . preg_quote($context, '/') . '\\.$/', $e->getMessage(), $matches)) { $errorMessage = $matches[1]; $errorPos = $matches[2]; $atPos = strpos($context->comment, '@'); $context->line += substr_count($context->comment, "\n", 0, $atPos + $errorPos); $lines = explode("\n", substr($context->comment, $atPos, $errorPos)); $context->character = strlen(array_pop($lines)) + 1; // position starts at 0 character starts at 1 Logger::warning(new \Exception($errorMessage . ' in ' . $context, $e->getCode(), $e)); } else { Logger::warning($e); } return array(); } foreach ($annotations as $annotation) { foreach ($this->processors as $processor) { $processor->process($annotation, $context); } if ($annotation instanceof AbstractAnnotation) { if ($annotation->hasPartialId()) { if ($this->hasPartial($annotation->_partialId)) { Logger::notice('partial="' . $annotation->_partialId . '" is not unique. another was found in ' . $annotation->_context); } $this->setPartial($annotation->_partialId, $annotation); } elseif ($annotation instanceof Resource) { $this->resources[] = $annotation; } elseif ($annotation instanceof Model) { $this->models[] = $annotation; } } } return $annotations; }
protected function setUp() { $docParser = new DocParser(); $docParser->setImports(array('desc' => 'JMS\\TranslationBundle\\Annotation\\Desc', 'meaning' => 'JMS\\TranslationBundle\\Annotation\\Meaning', 'ignore' => 'JMS\\TranslationBundle\\Annotation\\Ignore')); $docParser->setIgnoreNotImportedAnnotations(true); $this->extractor = new FormExtractor($docParser); }
public function enterNode(\PHPParser_Node $node) { /** * determine domain from namespace of files. * Finder appears to start with root level files so Namespace is correct for remaining files */ if ($node instanceof \PHPParser_Node_Stmt_Namespace) { if (isset($node->name)) { if (array_key_exists($node->name->toString(), $this->bundles)) { $this->domain = strtolower($this->bundles[$node->name->toString()]); } return; } else { foreach ($node->stmts as $node) { $this->enterNode($node); } return; } } if (!$node instanceof \PHPParser_Node_Expr_MethodCall || !is_string($node->name) || !in_array(strtolower($node->name), $this->methodNames)) { $this->previousNode = $node; return; } $ignore = false; $desc = $meaning = null; if (null !== ($docComment = $this->getDocCommentForNode($node))) { foreach ($this->docParser->parse($docComment, 'file ' . $this->file . ' near line ' . $node->getLine()) as $annot) { if ($annot instanceof Ignore) { $ignore = true; } else { if ($annot instanceof Desc) { $desc = $annot->text; } else { if ($annot instanceof Meaning) { $meaning = $annot->text; } } } } } if (!$node->args[0]->value instanceof \PHPParser_Node_Scalar_String) { if ($ignore) { return; } $message = sprintf('Can only extract the translation id from a scalar string, but got "%s". Please refactor your code to make it extractable, or add the doc comment /** @Ignore */ to this code element (in %s on line %d).', get_class($node->args[0]->value), $this->file, $node->args[0]->value->getLine()); if ($this->logger) { $this->logger->err($message); return; } throw new RuntimeException($message); } $id = $node->args[0]->value->value; if (in_array(strtolower($node->name), array('_n', '_fn'), true)) { // concatenate pluralized strings from zikula functions $id = $node->args[0]->value->value . '|' . $node->args[1]->value->value; } // determine location of domain $domainIndex = array_search(strtolower($node->name), $this->methodNames); if (isset($node->args[$domainIndex])) { if (!$node->args[$domainIndex]->value instanceof \PHPParser_Node_Scalar_String) { if ($ignore) { return; } $message = sprintf('Can only extract the translation domain from a scalar string, but got "%s". Please refactor your code to make it extractable, or add the doc comment /** @Ignore */ to this code element (in %s on line %d).', get_class($node->args[0]->value), $this->file, $node->args[0]->value->getLine()); if ($this->logger) { $this->logger->err($message); return; } throw new RuntimeException($message); } $domain = $node->args[$domainIndex]->value->value; } else { $domain = !empty($this->domain) ? $this->domain : 'messages'; } $message = new Message($id, $domain); $message->setDesc($desc); $message->setMeaning($meaning); $message->addSource(new FileSource((string) $this->file, $node->getLine())); $this->catalogue->add($message); }
/** * @param Node $node * @return void */ public function enterNode(Node $node) { if ($node instanceof Node\Stmt\Namespace_) { if (isset($node->name)) { $this->namespace = implode('\\', $node->name->parts); } return; } if ($node instanceof Node\Stmt\Class_) { $name = '' === $this->namespace ? $node->name : $this->namespace . '\\' . $node->name; if (!class_exists($name)) { return; } $ref = new \ReflectionClass($name); if (!$ref->isSubclassOf('Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException') && $ref->name !== 'Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException') { return; } if (!$ref->hasMethod('getMessageKey')) { return; } $this->inAuthException = true; return; } if (!$this->inAuthException) { return; } if ($node instanceof Node\Stmt\ClassMethod) { if ('getmessagekey' === strtolower($node->name)) { $this->inGetMessageKey = true; } return; } if (!$this->inGetMessageKey) { return; } if (!$node instanceof Node\Stmt\Return_) { return; } $ignore = false; $desc = $meaning = null; if ($docComment = $node->getDocComment()) { foreach ($this->docParser->parse($docComment->getText(), 'file ' . $this->file . ' near line ' . $node->getLine()) as $annot) { if ($annot instanceof Ignore) { $ignore = true; } elseif ($annot instanceof Desc) { $desc = $annot->text; } elseif ($annot instanceof Meaning) { $meaning = $annot->text; } } } if (!$node->expr instanceof Node\Scalar\String_) { if ($ignore) { return; } $message = sprintf('Could not extract id from return value, expected scalar string but got %s (in %s on line %d).', get_class($node->expr), $this->file, $node->expr->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } $message = Message::create($node->expr->value, $this->domain)->setDesc($desc)->setMeaning($meaning)->addSource(new FileSource((string) $this->file, $node->expr->getLine())); $this->catalogue->add($message); }
/** * 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; }
/** * 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()); }
public function createTestParser() { $parser = new DocParser(); $parser->setIgnoreNotImportedAnnotations(true); $parser->setImports(array('name' => 'Doctrine\\Tests\\Common\\Annotations\\Name', '__NAMESPACE__' => 'Doctrine\\Tests\\Common\\Annotations')); return $parser; }
/** * 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; }
/** * 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) { return $this->parser->parse($property->getDocComment(), 'property ' . $property->getDeclaringClass()->name . '::$' . $property->getName()); }