/** * 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(); }
/** * Add the Annotated Method to the Navigation * * @param \TYPO3\FLOW3\AOP\JoinPointInterface $joinPoint * @FLOW3\Before("method(public .*\Controller\.*Controller->.*Action(.*))") * @return void */ public function addNavigationitem(\TYPO3\FLOW3\AOP\JoinPointInterface $joinPoint) { $currentClassName = $joinPoint->getClassName(); $currentMethodName = $joinPoint->getMethodName(); $controllers = $this->reflectionService->getAllSubClassNamesForClass("\\TYPO3\\FLOW3\\MVC\\Controller\\ActionController"); foreach ($controllers as $className) { $methods = get_class_methods($className); if (is_array($methods)) { foreach ($methods as $methodName) { if ($this->reflectionService->isMethodAnnotatedWith($className, $methodName, "Admin\\Annotations\\Navigation")) { $annotations = $this->reflectionService->getMethodAnnotations($className, $methodName, "Admin\\Annotations\\Navigation"); foreach ($annotations as $annotation) { $action = str_replace("Action", "", $methodName); $controller = $this->helper->getControllerByClassName($className); $package = $this->objectManager->getPackageKeyByObjectName($className); $arguments = array("action" => $action, "controller" => $controller, "package" => $package); $title = !is_null($annotation->title) ? $annotation->title : sprintf("%s (%s)", $controller, $action); \Admin\Core\API::addNavigationitem($title, $annotation->position, $arguments, $annotation->priority, $annotation->parent); } } } } } $settings = $this->helper->getSettings("Admin.Navigation"); foreach ($settings as $position => $items) { foreach ($items as $title => $conf) { $priority = isset($conf["priority"]) ? $conf["priority"] : 100; $arguments = $conf["Arguments"]; \Admin\Core\API::addNavigationitem($title, strtolower($position), $arguments, $priority); } } }
/** * 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\FLOW3\Object\Proxy\Compiler::renderAnnotation($annotation) . "\n"; } } $methodDocumentation .= "\t */\n"; return $methodDocumentation; }
/** * 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 * @return array An Array of ValidatorConjunctions for each method parameters. * @throws Exception\InvalidValidationConfigurationException * @throws Exception\NoSuchValidatorException * @throws Exception\InvalidTypeHintException */ public function buildMethodArgumentsValidatorConjunctions($className, $methodName) { $validatorConjunctions = array(); $methodParameters = $this->reflectionService->getMethodParameters($className, $methodName); if (count($methodParameters) === 0) { return $validatorConjunctions; } foreach ($methodParameters as $parameterName => $methodParameter) { $validatorConjunction = $this->createValidator('TYPO3\\FLOW3\\Validation\\Validator\\ConjunctionValidator'); if (!array_key_exists('type', $methodParameter)) { throw new \TYPO3\FLOW3\Validation\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; } $validateAnnotations = $this->reflectionService->getMethodAnnotations($className, $methodName, 'TYPO3\\FLOW3\\Annotations\\Validate'); foreach ($validateAnnotations as $validateAnnotation) { $newValidator = $this->createValidator($validateAnnotation->type, $validateAnnotation->options); if ($newValidator === NULL) { throw new \TYPO3\FLOW3\Validation\Exception\NoSuchValidatorException('Invalid validate annotation in ' . $className . '->' . $methodName . '(): Could not resolve class name for validator "' . $validateAnnotation->type . '".', 1239853109); } if (isset($validatorConjunctions[$validateAnnotation->argumentName])) { $validatorConjunctions[$validateAnnotation->argumentName]->addValidator($newValidator); } elseif (strpos($validateAnnotation->argumentName, '.') !== FALSE) { $objectPath = explode('.', $validateAnnotation->argumentName); $argumentName = array_shift($objectPath); $validatorConjunctions[$argumentName]->addValidator($this->buildSubObjectValidator($objectPath, $newValidator)); } else { throw new \TYPO3\FLOW3\Validation\Exception\InvalidValidationConfigurationException('Invalid validate annotation in ' . $className . '->' . $methodName . '(): Validator specified for argument name "' . $validateAnnotation->argumentName . '", but this argument does not exist.', 1253172726); } } return $validatorConjunctions; }
/** * Calls the specified action method and passes the arguments. * * If the action returns a string, it is appended to the content in the * response object. If the action doesn't return anything and a valid * view exists, the view is rendered automatically. * * @return void */ protected function callActionMethod() { $preparedArguments = array(); foreach ($this->arguments as $argument) { $preparedArguments[] = $argument->getValue(); } $validationResult = $this->arguments->getValidationResults(); if (!$validationResult->hasErrors()) { $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments); } else { $ignoreValidationAnnotations = $this->reflectionService->getMethodAnnotations(get_class($this), $this->actionMethodName, 'TYPO3\\FLOW3\\Annotations\\IgnoreValidation'); $ignoredArguments = array_map(function ($annotation) { return $annotation->argumentName; }, $ignoreValidationAnnotations); // if there exists more errors than in ignoreValidationAnnotations_=> call error method // else => call action method $shouldCallActionMethod = TRUE; foreach ($validationResult->getSubResults() as $argumentName => $subValidationResult) { if (!$subValidationResult->hasErrors()) { continue; } if (array_search($argumentName, $ignoredArguments) !== FALSE) { continue; } $shouldCallActionMethod = FALSE; } if ($shouldCallActionMethod) { $actionResult = call_user_func_array(array($this, $this->actionMethodName), $preparedArguments); } else { $actionResult = call_user_func(array($this, $this->errorMethodName)); } } if ($actionResult === NULL && $this->view instanceof \TYPO3\FLOW3\Mvc\View\ViewInterface) { $this->response->appendContent($this->view->render()); } elseif (is_string($actionResult) && strlen($actionResult) > 0) { $this->response->appendContent($actionResult); } elseif (is_object($actionResult) && method_exists($actionResult, '__toString')) { $this->response->appendContent((string) $actionResult); } }
/** * 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\FLOW3\Aop\Exception */ protected function buildAspectContainer($aspectClassName) { $aspectContainer = new \TYPO3\FLOW3\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\\FLOW3\\Annotations\\Around': $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\FLOW3\Aop\Advice\AroundAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\FLOW3\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\FLOW3\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case 'TYPO3\\FLOW3\\Annotations\\Before': $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\FLOW3\Aop\Advice\BeforeAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\FLOW3\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\FLOW3\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case 'TYPO3\\FLOW3\\Annotations\\AfterReturning': $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\FLOW3\Aop\Advice\AfterReturningAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\FLOW3\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\FLOW3\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case 'TYPO3\\FLOW3\\Annotations\\AfterThrowing': $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\FLOW3\Aop\Advice\AfterThrowingAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\FLOW3\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\FLOW3\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case 'TYPO3\\FLOW3\\Annotations\\After': $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $advice = new \TYPO3\FLOW3\Aop\Advice\AfterAdvice($aspectClassName, $methodName); $pointcut = new \TYPO3\FLOW3\Aop\Pointcut\Pointcut($annotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $advisor = new \TYPO3\FLOW3\Aop\Advisor($advice, $pointcut); $aspectContainer->addAdvisor($advisor); break; case 'TYPO3\\FLOW3\\Annotations\\Pointcut': $pointcutFilterComposite = $this->pointcutExpressionParser->parse($annotation->expression, $this->renderSourceHint($aspectClassName, $methodName, $annotationClass)); $pointcut = new \TYPO3\FLOW3\Aop\Pointcut\Pointcut($annotation->expression, $pointcutFilterComposite, $aspectClassName, $methodName); $aspectContainer->addPointcut($pointcut); break; } } } $introduceAnnotation = $this->reflectionService->getClassAnnotation($aspectClassName, 'TYPO3\\FLOW3\\Annotations\\Introduce'); if ($introduceAnnotation !== NULL) { if ($introduceAnnotation->interfaceName === NULL) { throw new \TYPO3\FLOW3\Aop\Exception('The interface introduction in class "' . $aspectClassName . '" does not contain the required interface name).', 1172694761); } $pointcutFilterComposite = $this->pointcutExpressionParser->parse($introduceAnnotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $methodName, 'TYPO3\\FLOW3\\Annotations\\Introduce')); $pointcut = new \TYPO3\FLOW3\Aop\Pointcut\Pointcut($introduceAnnotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $introduction = new \TYPO3\FLOW3\Aop\InterfaceIntroduction($aspectClassName, $introduceAnnotation->interfaceName, $pointcut); $aspectContainer->addInterfaceIntroduction($introduction); } foreach ($this->reflectionService->getClassPropertyNames($aspectClassName) as $propertyName) { $introduceAnnotation = $this->reflectionService->getPropertyAnnotation($aspectClassName, $propertyName, 'TYPO3\\FLOW3\\Annotations\\Introduce'); if ($introduceAnnotation !== NULL) { $pointcutFilterComposite = $this->pointcutExpressionParser->parse($introduceAnnotation->pointcutExpression, $this->renderSourceHint($aspectClassName, $propertyName, 'TYPO3\\FLOW3\\Annotations\\Introduce')); $pointcut = new \TYPO3\FLOW3\Aop\Pointcut\Pointcut($introduceAnnotation->pointcutExpression, $pointcutFilterComposite, $aspectClassName); $introduction = new \TYPO3\FLOW3\Aop\PropertyIntroduction($aspectClassName, $propertyName, $pointcut); $aspectContainer->addPropertyIntroduction($introduction); } } if (count($aspectContainer->getAdvisors()) < 1 && count($aspectContainer->getPointcuts()) < 1 && count($aspectContainer->getInterfaceIntroductions()) < 1) { throw new \TYPO3\FLOW3\Aop\Exception('The class "' . $aspectClassName . '" is tagged to be an aspect but doesn\'t contain advices nor pointcut or introduction declarations.', 1169124534); } return $aspectContainer; }