/**
  * Checks if the specified method matches with the method annotation filter pattern
  *
  * @param string $className Name of the class to check against - not used here
  * @param string $methodName Name of the method
  * @param string $methodDeclaringClassName Name of the class the method was originally declared in
  * @param mixed $pointcutQueryIdentifier Some identifier for this query - must at least differ from a previous identifier. Used for circular reference detection - not used here
  * @return boolean TRUE if the class matches, otherwise FALSE
  */
 public function matches($className, $methodName, $methodDeclaringClassName, $pointcutQueryIdentifier)
 {
     if ($methodDeclaringClassName === null || !method_exists($methodDeclaringClassName, $methodName)) {
         return false;
     }
     $designatedAnnotations = $this->reflectionService->getMethodAnnotations($methodDeclaringClassName, $methodName, $this->annotation);
     if ($designatedAnnotations !== array() || $this->annotationValueConstraints === array()) {
         $matches = $designatedAnnotations !== array();
     } else {
         // It makes no sense to check property values for an annotation that is used multiple times, we shortcut and check the value against the first annotation found.
         $firstFoundAnnotation = $designatedAnnotations;
         $annotationProperties = $this->reflectionService->getClassPropertyNames($this->annotation);
         foreach ($this->annotationValueConstraints as $propertyName => $expectedValue) {
             if (!array_key_exists($propertyName, $annotationProperties)) {
                 $this->systemLogger->log('The property "' . $propertyName . '" declared in pointcut does not exist in annotation ' . $this->annotation, LOG_NOTICE);
                 return false;
             }
             if ($firstFoundAnnotation->{$propertyName} === $expectedValue) {
                 $matches = true;
             } else {
                 return false;
             }
         }
     }
     return $matches;
 }
 /**
  * Checks if the specified method matches with the method annotation filter pattern
  *
  * @param string $className Name of the class to check against - not used here
  * @param string $methodName Name of the method
  * @param string $methodDeclaringClassName Name of the class the method was originally declared in
  * @param mixed $pointcutQueryIdentifier Some identifier for this query - must at least differ from a previous identifier. Used for circular reference detection - not used here
  * @return boolean TRUE if the class matches, otherwise FALSE
  */
 public function matches($className, $methodName, $methodDeclaringClassName, $pointcutQueryIdentifier)
 {
     if ($methodDeclaringClassName === NULL || !method_exists($methodDeclaringClassName, $methodName)) {
         return FALSE;
     }
     return $this->reflectionService->getMethodAnnotations($methodDeclaringClassName, $methodName, $this->annotation) !== array();
 }
 /**
  * Builds the method documentation block for the specified method keeping the vital annotations
  *
  * @param string $className Name of the class the method is declared in
  * @param string $methodName Name of the method to create the parameters code for
  * @return string $methodDocumentation DocComment for the given method
  */
 protected function buildMethodDocumentation($className, $methodName)
 {
     $methodDocumentation = "\t/**\n\t * Autogenerated Proxy Method\n";
     if ($this->reflectionService->hasMethod($className, $methodName)) {
         $methodTags = $this->reflectionService->getMethodTagsValues($className, $methodName);
         $allowedTags = array('param', 'return', 'throws');
         foreach ($methodTags as $tag => $values) {
             if (in_array($tag, $allowedTags)) {
                 if (count($values) === 0) {
                     $methodDocumentation .= '	 * @' . $tag . "\n";
                 } else {
                     foreach ($values as $value) {
                         $methodDocumentation .= '	 * @' . $tag . ' ' . $value . "\n";
                     }
                 }
             }
         }
         $methodAnnotations = $this->reflectionService->getMethodAnnotations($className, $methodName);
         foreach ($methodAnnotations as $annotation) {
             $methodDocumentation .= '	 * ' . \TYPO3\Flow\Object\Proxy\Compiler::renderAnnotation($annotation) . "\n";
         }
     }
     $methodDocumentation .= "\t */\n";
     return $methodDocumentation;
 }
예제 #4
0
 /**
  * Detects and registers any validators for arguments:
  * - by the data type specified in the param annotations
  * - additional validators specified in the validate annotations of a method
  *
  * @param string $className
  * @param string $methodName
  * @param array $methodParameters Optional pre-compiled array of method parameters
  * @param array $methodValidateAnnotations Optional pre-compiled array of validate annotations (as array)
  * @return array An Array of ValidatorConjunctions for each method parameters.
  * @throws \TYPO3\Flow\Validation\Exception\InvalidValidationConfigurationException
  * @throws \TYPO3\Flow\Validation\Exception\NoSuchValidatorException
  * @throws \TYPO3\Flow\Validation\Exception\InvalidTypeHintException
  */
 public function buildMethodArgumentsValidatorConjunctions($className, $methodName, array $methodParameters = NULL, array $methodValidateAnnotations = NULL)
 {
     $validatorConjunctions = array();
     if ($methodParameters === NULL) {
         $methodParameters = $this->reflectionService->getMethodParameters($className, $methodName);
     }
     if (count($methodParameters) === 0) {
         return $validatorConjunctions;
     }
     foreach ($methodParameters as $parameterName => $methodParameter) {
         $validatorConjunction = $this->createValidator('TYPO3\\Flow\\Validation\\Validator\\ConjunctionValidator');
         if (!array_key_exists('type', $methodParameter)) {
             throw new Exception\InvalidTypeHintException('Missing type information, probably no @param annotation for parameter "$' . $parameterName . '" in ' . $className . '->' . $methodName . '()', 1281962564);
         }
         if (strpos($methodParameter['type'], '\\') === FALSE) {
             $typeValidator = $this->createValidator($methodParameter['type']);
         } elseif (strpos($methodParameter['type'], '\\Model\\') !== FALSE) {
             $possibleValidatorClassName = str_replace('\\Model\\', '\\Validator\\', $methodParameter['type']) . 'Validator';
             $typeValidator = $this->createValidator($possibleValidatorClassName);
         } else {
             $typeValidator = NULL;
         }
         if ($typeValidator !== NULL) {
             $validatorConjunction->addValidator($typeValidator);
         }
         $validatorConjunctions[$parameterName] = $validatorConjunction;
     }
     if ($methodValidateAnnotations === NULL) {
         $validateAnnotations = $this->reflectionService->getMethodAnnotations($className, $methodName, 'TYPO3\\Flow\\Annotations\\Validate');
         $methodValidateAnnotations = array_map(function ($validateAnnotation) {
             return array('type' => $validateAnnotation->type, 'options' => $validateAnnotation->options, 'argumentName' => $validateAnnotation->argumentName);
         }, $validateAnnotations);
     }
     foreach ($methodValidateAnnotations as $annotationParameters) {
         $newValidator = $this->createValidator($annotationParameters['type'], $annotationParameters['options']);
         if ($newValidator === NULL) {
             throw new Exception\NoSuchValidatorException('Invalid validate annotation in ' . $className . '->' . $methodName . '(): Could not resolve class name for  validator "' . $annotationParameters['type'] . '".', 1239853109);
         }
         if (isset($validatorConjunctions[$annotationParameters['argumentName']])) {
             $validatorConjunctions[$annotationParameters['argumentName']]->addValidator($newValidator);
         } elseif (strpos($annotationParameters['argumentName'], '.') !== FALSE) {
             $objectPath = explode('.', $annotationParameters['argumentName']);
             $argumentName = array_shift($objectPath);
             $validatorConjunctions[$argumentName]->addValidator($this->buildSubObjectValidator($objectPath, $newValidator));
         } else {
             throw new Exception\InvalidValidationConfigurationException('Invalid validate annotation in ' . $className . '->' . $methodName . '(): Validator specified for argument name "' . $annotationParameters['argumentName'] . '", but this argument does not exist.', 1253172726);
         }
     }
     return $validatorConjunctions;
 }
 /**
  * Creates and returns an aspect from the annotations found in a class which
  * is tagged as an aspect. The object acting as an advice will already be
  * fetched (and therefore instantiated if necessary).
  *
  * @param  string $aspectClassName Name of the class which forms the aspect, contains advices etc.
  * @return mixed The aspect container containing one or more advisors or FALSE if no container could be built
  * @throws \TYPO3\Flow\Aop\Exception
  */
 protected function buildAspectContainer($aspectClassName)
 {
     $aspectContainer = new \TYPO3\Flow\Aop\AspectContainer($aspectClassName);
     $methodNames = get_class_methods($aspectClassName);
     foreach ($methodNames as $methodName) {
         foreach ($this->reflectionService->getMethodAnnotations($aspectClassName, $methodName) as $annotation) {
             $annotationClass = get_class($annotation);
             switch ($annotationClass) {
                 case \TYPO3\Flow\Annotations\Around::class:
                     $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass));
                     $advice = new \TYPO3\Flow\Aop\Advice\AroundAdvice($aspectClassName, $methodName);
                     $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName);
                     $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut);
                     $aspectContainer->addAdvisor($advisor);
                     break;
                 case \TYPO3\Flow\Annotations\Before::class:
                     $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass));
                     $advice = new \TYPO3\Flow\Aop\Advice\BeforeAdvice($aspectClassName, $methodName);
                     $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName);
                     $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut);
                     $aspectContainer->addAdvisor($advisor);
                     break;
                 case \TYPO3\Flow\Annotations\AfterReturning::class:
                     $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass));
                     $advice = new \TYPO3\Flow\Aop\Advice\AfterReturningAdvice($aspectClassName, $methodName);
                     $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName);
                     $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut);
                     $aspectContainer->addAdvisor($advisor);
                     break;
                 case \TYPO3\Flow\Annotations\AfterThrowing::class:
                     $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass));
                     $advice = new \TYPO3\Flow\Aop\Advice\AfterThrowingAdvice($aspectClassName, $methodName);
                     $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName);
                     $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut);
                     $aspectContainer->addAdvisor($advisor);
                     break;
                 case \TYPO3\Flow\Annotations\After::class:
                     $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass));
                     $advice = new \TYPO3\Flow\Aop\Advice\AfterAdvice($aspectClassName, $methodName);
                     $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName);
                     $advisor = new \TYPO3\Flow\Aop\Advisor($advice, $pointcut);
                     $aspectContainer->addAdvisor($advisor);
                     break;
                 case \TYPO3\Flow\Annotations\Pointcut::class:
                     $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->expression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass));
                     $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($annotation->expression, $pointcutFilterComposite, $aspectClassName, $methodName);
                     $aspectContainer->addPointcut($pointcut);
                     break;
             }
         }
     }
     $introduceAnnotation = $this->reflectionService->getClassAnnotation($aspectClassName, \TYPO3\Flow\Annotations\Introduce::class);
     if ($introduceAnnotation !== null) {
         if ($introduceAnnotation->interfaceName === null && $introduceAnnotation->traitName === null) {
             throw new \TYPO3\Flow\Aop\Exception('The introduction in class "' . $aspectClassName . '" does neither contain an interface name nor a trait name, at least one is required.', 1172694761);
         }
         $pointcutFilterComposite = $this->pointcutExpressionParser->parse($introduceAnnotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $introduceAnnotation->interfaceName, \TYPO3\Flow\Annotations\Introduce::class));
         $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($introduceAnnotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName);
         if ($introduceAnnotation->interfaceName !== null) {
             $introduction = new \TYPO3\Flow\Aop\InterfaceIntroduction($aspectClassName, $introduceAnnotation->interfaceName, $pointcut);
             $aspectContainer->addInterfaceIntroduction($introduction);
         }
         if ($introduceAnnotation->traitName !== null) {
             $introduction = new \TYPO3\Flow\Aop\TraitIntroduction($aspectClassName, $introduceAnnotation->traitName, $pointcut);
             $aspectContainer->addTraitIntroduction($introduction);
         }
     }
     foreach ($this->reflectionService->getClassPropertyNames($aspectClassName) as $propertyName) {
         $introduceAnnotation = $this->reflectionService->getPropertyAnnotation($aspectClassName, $propertyName, \TYPO3\Flow\Annotations\Introduce::class);
         if ($introduceAnnotation !== null) {
             $pointcutFilterComposite = $this->pointcutExpressionParser->parse($introduceAnnotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $propertyName, \TYPO3\Flow\Annotations\Introduce::class));
             $pointcut = new \TYPO3\Flow\Aop\Pointcut\Pointcut($introduceAnnotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName);
             $introduction = new PropertyIntroduction($aspectClassName, $propertyName, $pointcut);
             $aspectContainer->addPropertyIntroduction($introduction);
         }
     }
     if (count($aspectContainer->getAdvisors()) < 1 && count($aspectContainer->getPointcuts()) < 1 && count($aspectContainer->getInterfaceIntroductions()) < 1 && count($aspectContainer->getTraitIntroductions()) < 1 && count($aspectContainer->getPropertyIntroductions()) < 1) {
         throw new \TYPO3\Flow\Aop\Exception('The class "' . $aspectClassName . '" is tagged to be an aspect but doesn\'t contain advices nor pointcut or introduction declarations.', 1169124534);
     }
     return $aspectContainer;
 }