/** * Will create a PointcutPointcut instance referencing all concrete pointcuts configured for a certain advice. * Needs a list of these pointcuts * * @param array $pointcutNames List of names of referenced pointcuts * @param \AppserverIo\Doppelgaenger\Entities\Definitions\Aspect $aspect The aspect to which the advice belongs * * @return \AppserverIo\Doppelgaenger\Entities\Pointcuts\PointcutPointcut */ protected function generatePointcutPointcut(array $pointcutNames, Aspect $aspect) { // there might be several pointcuts // we have to look them up within the pointcuts we got here and the ones we already have in our register $pointcutFactory = new PointcutFactory(); $referencedPointcuts = array(); $pointcutExpression = array(); foreach ($pointcutNames as $pointcutName) { $pointcutName = (string) $pointcutName; $referenceCount = count($referencedPointcuts); // check if we recently parsed the referenced pointcut if ($pointcut = $aspect->getPointcuts()->get($pointcutName)) { $referencedPointcuts[] = $pointcut; } else { // or did we already know of it? $referencedPointcuts = array_merge($referencedPointcuts, $this->getAspectRegister()->lookupPointcuts($pointcutName)); } // build up the expression string for the PointcutPointcut instance if ($referenceCount < count($referencedPointcuts)) { $pointcutExpression[] = $pointcutName; } } /** @var \AppserverIo\Doppelgaenger\Entities\Pointcuts\PointcutPointcut $pointcutPointcut */ $pointcutPointcut = $pointcutFactory->getInstance(PointcutPointcut::TYPE . '(' . implode(PointcutPointcut::EXPRESSION_CONNECTOR, $pointcutExpression) . ')'); $pointcutPointcut->setReferencedPointcuts($referencedPointcuts); return $pointcutPointcut; }
/** * 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); }