/** * Compacts the docblock and its annotations. * * @param string $docblock The docblock. * * @return string The compacted docblock. */ private function compactAnnotations($docblock) { $annotations = array(); $index = -1; $inside = 0; $tokens = $this->tokenizer->parse($docblock); if (empty($tokens)) { return str_repeat("\n", substr_count($docblock, "\n")); } foreach ($tokens as $token) { if (0 === $inside && DocLexer::T_AT === $token[0]) { $index++; } elseif (DocLexer::T_OPEN_PARENTHESIS === $token[0]) { $inside++; } elseif (DocLexer::T_CLOSE_PARENTHESIS === $token[0]) { $inside--; } if (!isset($annotations[$index])) { $annotations[$index] = array(); } $annotations[$index][] = $token; } $breaks = substr_count($docblock, "\n"); $docblock = "/**"; foreach ($annotations as $annotation) { $annotation = new Tokens($annotation); $docblock .= "\n" . $this->converter->convert($annotation); } $breaks -= count($annotations); if ($breaks > 0) { $docblock .= str_repeat("\n", $breaks - 1); $docblock .= "\n*/"; } else { $docblock .= ' */'; } return $docblock; }
public function testIssue14() { $original = <<<CODE <?php // autoload_real.php @generated by Composer /** * @author Made Up <*****@*****.**> */ class ComposerAutoloaderInitc22fe6e3e5ad79bad24655b3e52999df { private static \$loader; /** @inline annotation */ public static function loadClassLoader(\$class) { if ('Composer\\Autoload\\ClassLoader' === \$class) { require __DIR__ . '/ClassLoader.php'; } } public static function getLoader() { if (null !== self::\$loader) { return self::\$loader; } spl_autoload_register(array('ComposerAutoloaderInitc22fe6e3e5ad79bad24655b3e52999df', 'loadClassLoader'), true, true); self::\$loader = \$loader = new \\Composer\\Autoload\\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInitc22fe6e3e5ad79bad24655b3e52999df', 'loadClassLoader')); \$vendorDir = dirname(__DIR__); \$baseDir = dirname(\$vendorDir); \$includePaths = require __DIR__ . '/include_paths.php'; array_push(\$includePaths, get_include_path()); set_include_path(join(PATH_SEPARATOR, \$includePaths)); \$map = require __DIR__ . '/autoload_namespaces.php'; foreach (\$map as \$namespace => \$path) { \$loader->set(\$namespace, \$path); } \$map = require __DIR__ . '/autoload_psr4.php'; foreach (\$map as \$namespace => \$path) { \$loader->setPsr4(\$namespace, \$path); } \$classMap = require __DIR__ . '/autoload_classmap.php'; if (\$classMap) { \$loader->addClassMap(\$classMap); } \$loader->register(true); return \$loader; } } CODE; $expected = <<<CODE <?php class ComposerAutoloaderInitc22fe6e3e5ad79bad24655b3e52999df { private static \$loader; public static function loadClassLoader(\$class) { if ('Composer\\Autoload\\ClassLoader' === \$class) { require __DIR__ . '/ClassLoader.php'; } } public static function getLoader() { if (null !== self::\$loader) { return self::\$loader; } spl_autoload_register(array('ComposerAutoloaderInitc22fe6e3e5ad79bad24655b3e52999df', 'loadClassLoader'), true, true); self::\$loader = \$loader = new \\Composer\\Autoload\\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInitc22fe6e3e5ad79bad24655b3e52999df', 'loadClassLoader')); \$vendorDir = dirname(__DIR__); \$baseDir = dirname(\$vendorDir); \$includePaths = require __DIR__ . '/include_paths.php'; array_push(\$includePaths, get_include_path()); set_include_path(join(PATH_SEPARATOR, \$includePaths)); \$map = require __DIR__ . '/autoload_namespaces.php'; foreach (\$map as \$namespace => \$path) { \$loader->set(\$namespace, \$path); } \$map = require __DIR__ . '/autoload_psr4.php'; foreach (\$map as \$namespace => \$path) { \$loader->setPsr4(\$namespace, \$path); } \$classMap = require __DIR__ . '/autoload_classmap.php'; if (\$classMap) { \$loader->addClassMap(\$classMap); } \$loader->register(true); return \$loader; } } CODE; $tokenizer = new Tokenizer(); $tokenizer->ignore(array('author', 'inline')); $this->php->setTokenizer($tokenizer); $this->assertEquals($expected, $this->php->compact($original)); }
/** * Will return one pointcut which does specifically only match the joinpoints of the structure * which this docblock belongs to * * @param string $docBlock The DocBlock to search in * @param string $targetType Type of the target any resulting joinpoints have, e.g. Joinpoint::TARGET_METHOD * @param string $targetName Name of the target any resulting joinpoints have * * @return \AppserverIo\Doppelgaenger\Entities\Lists\PointcutExpressionList */ public function getPointcutExpressions($docBlock, $targetType, $targetName) { $pointcutExpressions = new PointcutExpressionList(); // get our tokenizer and parse the doc Block $tokenizer = new Tokenizer(); $tokenizer->ignore(array('param', 'return', 'throws')); $tokens = new Tokens($tokenizer->parse($docBlock)); // convert to array and run it through our advice factory $toArray = new ToArray(); $annotations = $toArray->convert($tokens); // create the entities for the join-points and advices the pointcut describes foreach ($annotations as $annotation) { // filter out the annotations which are no proper join-points if (!class_exists('\\AppserverIo\\Psr\\MetaobjectProtocol\\Aop\\Annotations\\Advices\\' . $annotation->name)) { continue; } // build the join-point $joinpoint = new Joinpoint(); $joinpoint->setTarget($targetType); $joinpoint->setCodeHook($annotation->name); $joinpoint->setStructure($this->currentDefinition->getQualifiedName()); $joinpoint->setTargetName($targetName); // build the pointcut(s) foreach ($annotation->values as $rawAdvice) { // as it might be an array we have to sanitize it first if (!is_array($rawAdvice)) { $rawAdvice = array($rawAdvice); } foreach ($rawAdvice as $adviceString) { // create the pointcut $pointcutExpression = new PointcutExpression($adviceString); $pointcutExpression->setJoinpoint($joinpoint); $pointcutExpressions->add($pointcutExpression); } } } return $pointcutExpressions; }
/** * @param $comment * @return mixed */ public function parse($comment) { return $this->annotationToArray->convert(new Tokens($this->annotationTokenizer->parse($comment))); }
/** * Returns the list of file contents compactors. * * @return CompactorInterface[] The list of compactors. * * @throws InvalidArgumentException If a class is not valid. */ public function getCompactors() { $compactors = array(); if (isset($this->raw->compactors)) { foreach ((array) $this->raw->compactors as $class) { if (false === class_exists($class)) { throw new InvalidArgumentException(sprintf('The compactor class "%s" does not exist.', $class)); } $compactor = new $class(); if (false === $compactor instanceof CompactorInterface) { throw new InvalidArgumentException(sprintf('The class "%s" is not a compactor class.', $class)); } if ($compactor instanceof Php) { if (!empty($this->raw->annotations)) { $tokenizer = new Tokenizer(); if (isset($this->raw->annotations->ignore)) { $tokenizer->ignore((array) $this->raw->annotations->ignore); } $compactor->setTokenizer($tokenizer); } } $compactors[] = $compactor; } } return $compactors; }
/** * Returns the property type found in the properties configuration * annotation. * * @param \ReflectionProperty $reflectionProperty The property to return the type for * * @throws \Exception Is thrown if the property has NO bean annotation * @return Mapping The found property type mapping */ public function getPropertyTypeFromDocComment(\ReflectionProperty $reflectionProperty) { // initialize the annotation tokenizer $tokenizer = new Tokenizer(); // set the aliases $aliases = array('AS' => 'AppserverIo\\Description\\Api\\Node'); // parse the doc block $parsed = $tokenizer->parse($reflectionProperty->getDocComment(), $aliases); // convert tokens and return one $tokens = new Tokens($parsed); $toArray = new ToArray(); // iterate over the tokens foreach ($toArray->convert($tokens) as $token) { if ($token->name == 'AppserverIo\\Description\\Api\\Node\\Mapping') { return new $token->name($token); } } }
public function testIgnored() { $ignore = array('abc', 'def'); $this->tokenizer->ignore($ignore); $this->assertEquals($ignore, $this->getPropertyValue($this->tokenizer, 'ignored')); }
/** * Will register a complete aspect to the AspectRegister. * This include its advices and pointcuts which can be looked up from this point on * * @param \AppserverIo\Doppelgaenger\Entities\Definitions\AspectDefinition $aspectDefinition Structure to register as an aspect * * @return null */ public function register(AspectDefinition $aspectDefinition) { // create the new aspect and fill it with things we already know $aspect = new Aspect(); $aspect->setName($aspectDefinition->getName()); $aspect->setNamespace($aspectDefinition->getNamespace()); // prepare the tokenizer we will need for further processing $needles = array(AfterReturning::ANNOTATION, AfterThrowing::ANNOTATION, After::ANNOTATION, Around::ANNOTATION, Before::ANNOTATION); $tokenizer = new Tokenizer(); $tokenizer->ignore(array('param', 'return', 'throws')); // iterate the functions and filter out the ones used as advices $scheduledAdviceDefinitions = array(); foreach ($aspectDefinition->getFunctionDefinitions() as $functionDefinition) { $foundNeedle = false; foreach ($needles as $needle) { // create the advice if (strpos($functionDefinition->getDocBlock(), '@' . $needle) !== false) { $foundNeedle = true; $scheduledAdviceDefinitions[$needle][] = $functionDefinition; break; } } // create the pointcut if (!$foundNeedle && strpos($functionDefinition->getDocBlock(), '@' . Pointcut::ANNOTATION) !== false) { $pointcut = new PointcutDefinition(); $pointcut->setName($functionDefinition->getName()); $tokens = new Tokens($tokenizer->parse($functionDefinition->getDocBlock())); // convert to array and run it through our advice factory $toArray = new ToArray(); $annotations = $toArray->convert($tokens); // create the entities for the join-points and advices the pointcut describes $pointcut->setPointcutExpression(new PointcutExpression(array_pop(array_pop($annotations)->values))); $aspect->getPointcuts()->add($pointcut); } } $this->add($aspect); // do the pointcut lookups where we will need the pointcut factory for later use $pointcutFactory = new PointcutFactory(); foreach ($scheduledAdviceDefinitions as $codeHook => $hookedAdviceDefinitions) { foreach ($hookedAdviceDefinitions as $scheduledAdviceDefinition) { // create our advice $advice = new Advice(); $advice->setAspectName($aspectDefinition->getQualifiedName()); $advice->setName($scheduledAdviceDefinition->getName()); $advice->setCodeHook((string) $codeHook); $tokens = new Tokens($tokenizer->parse($scheduledAdviceDefinition->getDocBlock())); // convert to array and run it through our advice factory $toArray = new ToArray(); $annotations = $toArray->convert($tokens); // create the entities for the join-points and advices the pointcut describes foreach ($annotations as $annotation) { $pointcut = $pointcutFactory->getInstance(array_pop($annotation->values)); if ($pointcut instanceof PointcutPointcut) { // get the referenced pointcuts for the split parts of the expression $expressionParts = explode(PointcutPointcut::EXPRESSION_CONNECTOR, $pointcut->getExpression()); // lookup all the referenced pointcuts $referencedPointcuts = array(); foreach ($expressionParts as $expressionPart) { $referencedPointcuts = array_merge($referencedPointcuts, $this->lookupPointcuts($expressionPart)); } $pointcut->setReferencedPointcuts($referencedPointcuts); } $advice->getPointcuts()->add($pointcut); } $aspect->getAdvices()->add($advice); } } $this->set($aspectDefinition->getQualifiedName(), $aspect); }
/** * Initializes and returns an array with annotation instances from the * passed doc comment. * * @param string $docComment The doc comment to initialize the annotations from * @param array $ignore Array with annotations we want to ignore * @param array $aliases Array with aliases to create annotation instances with * * @return array The array with the ReflectionAnnotation instances loaded from the passed doc comment */ public static function fromDocComment($docComment, array $ignore = array(), array $aliases = array()) { // initialize the array for the annotations $annotations = array(); // initialize the annotation tokenizer $tokenizer = new Tokenizer(); $tokenizer->ignore($ignore); // parse the doc block $parsed = $tokenizer->parse($docComment, $aliases); // convert tokens and return one $tokens = new Tokens($parsed); $toArray = new ToArray(); // register annotations with the real annotation name (not the alias) foreach ($toArray->convert($tokens) as $token) { // check if we've an annotation that matched an alias if (array_key_exists($token->name, $flipped = array_flip($aliases))) { $annotationName = $flipped[$token->name]; } else { $annotationName = $token->name; } // register the annotation with the real annotation name (not the alias) $annotations[$annotationName] = ReflectionAnnotation::fromStdClass($token, $aliases); } // return the list with the annotation instances return $annotations; }