/** * This method is used to optimize the matching process. * * @param \TYPO3\Flow\Aop\Builder\ClassNameIndex $classNameIndex * @return \TYPO3\Flow\Aop\Builder\ClassNameIndex */ public function reduceTargetClassNames(\TYPO3\Flow\Aop\Builder\ClassNameIndex $classNameIndex) { $classNames = $this->reflectionService->getClassNamesByAnnotation(Flow\ValueObject::class); $annotatedIndex = new \TYPO3\Flow\Aop\Builder\ClassNameIndex(); $annotatedIndex->setClassNames($classNames); return $classNameIndex->intersect($annotatedIndex); }
/** * Returns a new index object which contains all class names of this index * starting with the given prefix * * @param string $prefixFilter A prefix string to filter the class names of this index * @return \TYPO3\Flow\Aop\Builder\ClassNameIndex A new index object */ public function filterByPrefix($prefixFilter) { $pointcuts = array_keys($this->classNames); $result = new ClassNameIndex(); $right = count($pointcuts) - 1; $left = 0; $found = false; $currentPosition = -1; while ($found === false) { if ($left > $right) { break; } $currentPosition = $left + floor(($right - $left) / 2); if (strpos($pointcuts[$currentPosition], $prefixFilter) === 0) { $found = true; break; } else { $comparisonResult = strcmp($prefixFilter, $pointcuts[$currentPosition]); if ($comparisonResult > 0) { $left = $currentPosition + 1; } else { $right = $currentPosition - 1; } } } if ($found === true) { $startIndex = $currentPosition; while ($startIndex >= 0 && strpos($pointcuts[$startIndex], $prefixFilter) === 0) { $startIndex--; } $startIndex++; $endIndex = $currentPosition; while ($endIndex < count($pointcuts) && strpos($pointcuts[$endIndex], $prefixFilter) === 0) { $endIndex++; } $result->setClassNames(array_slice($pointcuts, $startIndex, $endIndex - $startIndex)); } return $result; }
/** * This method is used to optimize the matching process. * * @param \TYPO3\Flow\Aop\Builder\ClassNameIndex $classNameIndex * @return \TYPO3\Flow\Aop\Builder\ClassNameIndex */ public function reduceTargetClassNames(Builder\ClassNameIndex $classNameIndex) { $result = new Builder\ClassNameIndex(); foreach ($this->advisors as $advisor) { $result->applyUnion($advisor->getPointcut()->reduceTargetClassNames($classNameIndex)); } foreach ($this->interfaceIntroductions as $interfaceIntroduction) { $result->applyUnion($interfaceIntroduction->getPointcut()->reduceTargetClassNames($classNameIndex)); } foreach ($this->propertyIntroductions as $propertyIntroduction) { $result->applyUnion($propertyIntroduction->getPointcut()->reduceTargetClassNames($classNameIndex)); } $this->cachedTargetClassNameCandidates = $result; return $result; }
/** * This method is used to optimize the matching process. * * @param \TYPO3\Flow\Aop\Builder\ClassNameIndex $classNameIndex * @return \TYPO3\Flow\Aop\Builder\ClassNameIndex */ public function reduceTargetClassNames(\TYPO3\Flow\Aop\Builder\ClassNameIndex $classNameIndex) { $classNames = $this->reflectionService->getClassesContainingMethodsAnnotatedWith($this->annotation); $annotatedIndex = new \TYPO3\Flow\Aop\Builder\ClassNameIndex(); $annotatedIndex->setClassNames($classNames); return $classNameIndex->intersect($annotatedIndex); }
/** * Adds code to build the methods and advices array in case the parent class has some. * * @param string $className * @param ClassNameIndex $treatedSubClasses * @return ClassNameIndex */ protected function addBuildMethodsAndAdvicesCodeToClass($className, ClassNameIndex $treatedSubClasses) { if ($treatedSubClasses->hasClassName($className)) { return $treatedSubClasses; } $treatedSubClasses = $treatedSubClasses->union(new ClassNameIndex([$className])); if ($this->reflectionService->isClassReflected($className) === false) { return $treatedSubClasses; } $proxyClass = $this->compiler->getProxyClass($className); if ($proxyClass === false) { return $treatedSubClasses; } $callBuildMethodsAndAdvicesArrayCode = " if (method_exists(get_parent_class(), 'Flow_Aop_Proxy_buildMethodsAndAdvicesArray') && is_callable('parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray')) parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray();\n"; $proxyClass->getConstructor()->addPreParentCallCode($callBuildMethodsAndAdvicesArrayCode); $proxyClass->getMethod('__wakeup')->addPreParentCallCode($callBuildMethodsAndAdvicesArrayCode); return $treatedSubClasses; }
/** * This method is used to optimize the matching process. * * @param \TYPO3\Flow\Aop\Builder\ClassNameIndex $classNameIndex * @return \TYPO3\Flow\Aop\Builder\ClassNameIndex */ public function reduceTargetClassNames(\TYPO3\Flow\Aop\Builder\ClassNameIndex $classNameIndex) { if (!preg_match('/^([^\\.\\(\\)\\{\\}\\[\\]\\?\\+\\$\\!\\|]+)/', $this->originalExpressionString, $matches)) { return $classNameIndex; } $prefixFilter = $matches[1]; // We sort here to make sure the index is okay $classNameIndex->sort(); return $classNameIndex->filterByPrefix($prefixFilter); }
/** * This method is used to optimize the matching process. * * @param ClassNameIndex $classNameIndex * @return ClassNameIndex */ public function reduceTargetClassNames(ClassNameIndex $classNameIndex) { $sessionClasses = new ClassNameIndex(); $sessionClasses->setClassNames($this->objectManager->getClassNamesByScope(ObjectConfiguration::SCOPE_SESSION)); return $classNameIndex->intersect($sessionClasses); }
/** * Builds proxy class code which weaves advices into the respective target classes. * * The object configurations provided by the Compiler are searched for possible aspect * annotations. If an aspect class is found, the pointcut expressions are parsed and * a new aspect with one or more advisors is added to the aspect registry of the AOP framework. * Finally all advices are woven into their target classes by generating proxy classes. * * In general, the command typo3.flow:core:compile is responsible for compilation * and calls this method to do so. * * In order to distinguish between an emerged / changed possible target class and * a class which has been matched previously but just didn't have to be proxied, * the latter are kept track of by an "unproxiedClass-*" cache entry. * * @return void */ public function build() { $allAvailableClassNamesByPackage = $this->objectManager->getRegisteredClassNames(); $possibleTargetClassNames = $this->getProxyableClasses($allAvailableClassNamesByPackage); $actualAspectClassNames = $this->reflectionService->getClassNamesByAnnotation('TYPO3\\Flow\\Annotations\\Aspect'); sort($possibleTargetClassNames); sort($actualAspectClassNames); $this->aspectContainers = $this->buildAspectContainers($actualAspectClassNames); $rebuildEverything = FALSE; if ($this->objectConfigurationCache->has('allAspectClassesUpToDate') === FALSE) { $rebuildEverything = TRUE; $this->systemLogger->log('Aspects have been modified, therefore rebuilding all target classes.', LOG_INFO); $this->objectConfigurationCache->set('allAspectClassesUpToDate', TRUE); } $possibleTargetClassNameIndex = new ClassNameIndex(); $possibleTargetClassNameIndex->setClassNames($possibleTargetClassNames); $targetClassNameCandidates = new ClassNameIndex(); foreach ($this->aspectContainers as $aspectContainer) { $targetClassNameCandidates->applyUnion($aspectContainer->reduceTargetClassNames($possibleTargetClassNameIndex)); } $targetClassNameCandidates->sort(); foreach ($targetClassNameCandidates->getClassNames() as $targetClassName) { $isUnproxied = $this->objectConfigurationCache->has('unproxiedClass-' . str_replace('\\', '_', $targetClassName)); $hasCacheEntry = $this->compiler->hasCacheEntryForClass($targetClassName) || $isUnproxied; if ($rebuildEverything === TRUE || $hasCacheEntry === FALSE) { $proxyBuildResult = $this->buildProxyClass($targetClassName, $this->aspectContainers); if ($proxyBuildResult !== FALSE) { if ($isUnproxied) { $this->objectConfigurationCache->remove('unproxiedClass-' . str_replace('\\', '_', $targetClassName)); } $this->systemLogger->log(sprintf('Built AOP proxy for class "%s".', $targetClassName), LOG_DEBUG); } else { $this->objectConfigurationCache->set('unproxiedClass-' . str_replace('\\', '_', $targetClassName), TRUE); } } } }
/** * This method is used to optimize the matching process. * * @param ClassNameIndex $classNameIndex * @return ClassNameIndex */ public function reduceTargetClassNames(ClassNameIndex $classNameIndex) { if ($this->filters === null) { $this->buildPointcutFilters(); } $result = new ClassNameIndex(); foreach ($this->filters as $filter) { $result->applyUnion($filter->reduceTargetClassNames($classNameIndex)); } return $result; }
/** * This method is used to optimize the matching process. * * @param \TYPO3\Flow\Aop\Builder\ClassNameIndex $classNameIndex * @return \TYPO3\Flow\Aop\Builder\ClassNameIndex */ public function reduceTargetClassNames(\TYPO3\Flow\Aop\Builder\ClassNameIndex $classNameIndex) { if (interface_exists($this->interfaceOrClassName)) { $classNames = $this->reflectionService->getAllImplementationClassNamesForInterface($this->interfaceOrClassName); } elseif (class_exists($this->interfaceOrClassName)) { $classNames = $this->reflectionService->getAllSubClassNamesForClass($this->interfaceOrClassName); $classNames[] = $this->interfaceOrClassName; } else { $classNames = array(); } $filteredIndex = new \TYPO3\Flow\Aop\Builder\ClassNameIndex(); $filteredIndex->setClassNames($classNames); return $classNameIndex->intersect($filteredIndex); }
/** * Makes sure that any sub classes of an adviced class also build the advices array on construction. * * @param string $className The adviced class name * @param ClassNameIndex $targetClassNameCandidates target class names for advices * @param ClassNameIndex $treatedSubClasses Already treated (sub) classes to avoid duplication * @return ClassNameIndex The new collection of already treated classes */ protected function proxySubClassesOfClassToEnsureAdvices($className, ClassNameIndex $targetClassNameCandidates, ClassNameIndex $treatedSubClasses) { if ($this->reflectionService->isClassReflected($className) === false) { return $treatedSubClasses; } if (trait_exists($className)) { return $treatedSubClasses; } if (interface_exists($className)) { return $treatedSubClasses; } $subClassNames = $this->reflectionService->getAllSubClassNamesForClass($className); foreach ($subClassNames as $subClassName) { if ($treatedSubClasses->hasClassName($subClassName)) { continue; } if ($this->reflectionService->isClassReflected($subClassName) === false || $targetClassNameCandidates->hasClassName($subClassName)) { continue; } $proxyClass = $this->compiler->getProxyClass($subClassName); if ($proxyClass === false) { continue; } $callBuildMethodsAndAdvicesArrayCode = " if (method_exists(get_parent_class(), 'Flow_Aop_Proxy_buildMethodsAndAdvicesArray') && is_callable('parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray')) parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray();\n"; $proxyClass->getConstructor()->addPreParentCallCode($callBuildMethodsAndAdvicesArrayCode); $proxyClass->getMethod('__wakeup')->addPreParentCallCode($callBuildMethodsAndAdvicesArrayCode); } $treatedSubClasses = $treatedSubClasses->union(new ClassNameIndex($subClassNames)); return $treatedSubClasses; }