/**
  * @param string $className
  * @param PropertyReflection $property
  * @param string $tagName
  * @param array $tagValues
  * @return array
  */
 protected function reflectPropertyTag($className, PropertyReflection $property, $tagName, $tagValues)
 {
     if ($this->isTagIgnored($tagName)) {
         return null;
     }
     if ($tagName !== 'var' || !isset($tagValues[0])) {
         return $tagValues;
     }
     $propertyName = $property->getName();
     $propertyDeclaringClass = $property->getDeclaringClass();
     if ($propertyDeclaringClass->getName() !== $className && isset($this->classReflectionData[$propertyDeclaringClass->getName()][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tagName])) {
         $tagValues = $this->classReflectionData[$propertyDeclaringClass->getName()][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tagName];
     } else {
         $tagValues[0] = $this->expandType($propertyDeclaringClass, $tagValues[0]);
     }
     return $tagValues;
 }
Пример #2
0
 /**
  * Set a property for a given object.
  * Tries to set the property the following ways:
  * - if target is an array, set value
  * - if super cow powers should be used, set value through reflection
  * - if public setter method exists, call it.
  * - if public property exists, set it directly.
  * - if the target object is an instance of ArrayAccess, it sets the property
  *   on it without checking if it existed.
  * - else, return FALSE
  *
  * @param mixed $subject The target object or array
  * @param string|integer $propertyName Name or index of the property to set
  * @param mixed $propertyValue Value of the property
  * @param boolean $forceDirectAccess directly access property using reflection(!)
  * @return boolean TRUE if the property could be set, FALSE otherwise
  * @throws \InvalidArgumentException in case $object was not an object or $propertyName was not a string
  */
 public static function setProperty(&$subject, $propertyName, $propertyValue, $forceDirectAccess = false)
 {
     if (is_array($subject)) {
         $subject[$propertyName] = $propertyValue;
         return true;
     }
     if (!is_object($subject)) {
         throw new \InvalidArgumentException('subject must be an object or array, ' . gettype($subject) . ' given.', 1237301368);
     }
     if (!is_string($propertyName) && !is_integer($propertyName)) {
         throw new \InvalidArgumentException('Given property name/index is not of type string or integer.', 1231178878);
     }
     if ($forceDirectAccess === true) {
         if (property_exists(get_class($subject), $propertyName)) {
             $propertyReflection = new PropertyReflection(get_class($subject), $propertyName);
             $propertyReflection->setValue($subject, $propertyValue);
         } else {
             $subject->{$propertyName} = $propertyValue;
         }
     } elseif (is_callable(array($subject, $setterMethodName = self::buildSetterMethodName($propertyName)))) {
         $subject->{$setterMethodName}($propertyValue);
     } elseif ($subject instanceof \ArrayAccess) {
         $subject[$propertyName] = $propertyValue;
     } elseif (array_key_exists($propertyName, get_object_vars($subject))) {
         $subject->{$propertyName} = $propertyValue;
     } else {
         return false;
     }
     return true;
 }
 /**
  * Builds methods for a single AOP proxy class for the specified class.
  *
  * @param string $targetClassName Name of the class to create a proxy class file for
  * @param array &$aspectContainers The array of aspect containers from the AOP Framework
  * @return boolean TRUE if the proxy class could be built, FALSE otherwise.
  */
 public function buildProxyClass($targetClassName, array &$aspectContainers)
 {
     $interfaceIntroductions = $this->getMatchingInterfaceIntroductions($aspectContainers, $targetClassName);
     $introducedInterfaces = $this->getInterfaceNamesFromIntroductions($interfaceIntroductions);
     $propertyIntroductions = $this->getMatchingPropertyIntroductions($aspectContainers, $targetClassName);
     $methodsFromTargetClass = $this->getMethodsFromTargetClass($targetClassName);
     $methodsFromIntroducedInterfaces = $this->getIntroducedMethodsFromInterfaceIntroductions($interfaceIntroductions, $targetClassName);
     $interceptedMethods = array();
     $this->addAdvicedMethodsToInterceptedMethods($interceptedMethods, array_merge($methodsFromTargetClass, $methodsFromIntroducedInterfaces), $targetClassName, $aspectContainers);
     $this->addIntroducedMethodsToInterceptedMethods($interceptedMethods, $methodsFromIntroducedInterfaces);
     if (count($interceptedMethods) < 1 && count($introducedInterfaces) < 1 && count($propertyIntroductions) < 1) {
         return FALSE;
     }
     $proxyClass = $this->compiler->getProxyClass($targetClassName);
     if ($proxyClass === FALSE) {
         return FALSE;
     }
     $proxyClass->addInterfaces($introducedInterfaces);
     /** @var $propertyIntroduction PropertyIntroduction */
     foreach ($propertyIntroductions as $propertyIntroduction) {
         $propertyName = $propertyIntroduction->getPropertyName();
         $declaringAspectClassName = $propertyIntroduction->getDeclaringAspectClassName();
         $possiblePropertyTypes = $this->reflectionService->getPropertyTagValues($declaringAspectClassName, $propertyName, 'var');
         if (count($possiblePropertyTypes) > 0 && !$this->reflectionService->isPropertyAnnotatedWith($declaringAspectClassName, $propertyName, 'TYPO3\\Flow\\Annotations\\Transient')) {
             $classSchema = $this->reflectionService->getClassSchema($targetClassName);
             if ($classSchema !== NULL) {
                 $classSchema->addProperty($propertyName, $possiblePropertyTypes[0]);
             }
         }
         $propertyReflection = new PropertyReflection($declaringAspectClassName, $propertyName);
         $propertyReflection->setIsAopIntroduced(TRUE);
         $this->reflectionService->reflectClassProperty($targetClassName, $propertyReflection, new ClassReflection($declaringAspectClassName));
         $proxyClass->addProperty($propertyName, 'NULL', $propertyIntroduction->getPropertyVisibility(), $propertyIntroduction->getPropertyDocComment());
     }
     $proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->addPreParentCallCode("\t\tif (method_exists(get_parent_class(\$this), 'Flow_Aop_Proxy_buildMethodsAndAdvicesArray') && is_callable('parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray')) parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray();\n");
     $proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->addPreParentCallCode($this->buildMethodsAndAdvicesArrayCode($interceptedMethods));
     $proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->overrideMethodVisibility('protected');
     $callBuildMethodsAndAdvicesArrayCode = "\n\t\t\$this->Flow_Aop_Proxy_buildMethodsAndAdvicesArray();\n";
     $proxyClass->getConstructor()->addPreParentCallCode($callBuildMethodsAndAdvicesArrayCode);
     $proxyClass->getMethod('__wakeup')->addPreParentCallCode($callBuildMethodsAndAdvicesArrayCode);
     if (!$this->reflectionService->hasMethod($targetClassName, '__wakeup')) {
         $proxyClass->getMethod('__wakeup')->addPostParentCallCode("\t\tif (method_exists(get_parent_class(\$this), '__wakeup') && is_callable('parent::__wakeup')) parent::__wakeup();\n");
     }
     // FIXME this can be removed again once Doctrine is fixed (see fixMethodsAndAdvicesArrayForDoctrineProxiesCode())
     $proxyClass->getMethod('Flow_Aop_Proxy_fixMethodsAndAdvicesArrayForDoctrineProxies')->addPreParentCallCode($this->fixMethodsAndAdvicesArrayForDoctrineProxiesCode());
     // FIXME this can be removed again once Doctrine is fixed (see fixInjectedPropertiesForDoctrineProxiesCode())
     $proxyClass->getMethod('Flow_Aop_Proxy_fixInjectedPropertiesForDoctrineProxies')->addPreParentCallCode($this->fixInjectedPropertiesForDoctrineProxiesCode());
     $this->buildGetAdviceChainsMethodCode($targetClassName);
     $this->buildInvokeJoinPointMethodCode($targetClassName);
     $this->buildMethodsInterceptorCode($targetClassName, $interceptedMethods);
     $proxyClass->addProperty('Flow_Aop_Proxy_targetMethodsAndGroupedAdvices', 'array()');
     $proxyClass->addProperty('Flow_Aop_Proxy_groupedAdviceChains', 'array()');
     $proxyClass->addProperty('Flow_Aop_Proxy_methodIsInAdviceMode', 'array()');
     return TRUE;
 }
 /**
  * Builds methods for a single AOP proxy class for the specified class.
  *
  * @param string $targetClassName Name of the class to create a proxy class file for
  * @param array &$aspectContainers The array of aspect containers from the AOP Framework
  * @return boolean TRUE if the proxy class could be built, FALSE otherwise.
  */
 public function buildProxyClass($targetClassName, array &$aspectContainers)
 {
     $interfaceIntroductions = $this->getMatchingInterfaceIntroductions($aspectContainers, $targetClassName);
     $introducedInterfaces = $this->getInterfaceNamesFromIntroductions($interfaceIntroductions);
     $introducedTraits = $this->getMatchingTraitNamesFromIntroductions($aspectContainers, $targetClassName);
     $propertyIntroductions = $this->getMatchingPropertyIntroductions($aspectContainers, $targetClassName);
     $methodsFromTargetClass = $this->getMethodsFromTargetClass($targetClassName);
     $methodsFromIntroducedInterfaces = $this->getIntroducedMethodsFromInterfaceIntroductions($interfaceIntroductions, $targetClassName);
     $interceptedMethods = array();
     $this->addAdvicedMethodsToInterceptedMethods($interceptedMethods, array_merge($methodsFromTargetClass, $methodsFromIntroducedInterfaces), $targetClassName, $aspectContainers);
     $this->addIntroducedMethodsToInterceptedMethods($interceptedMethods, $methodsFromIntroducedInterfaces);
     if (count($interceptedMethods) < 1 && count($introducedInterfaces) < 1 && count($propertyIntroductions) < 1) {
         return false;
     }
     $proxyClass = $this->compiler->getProxyClass($targetClassName);
     if ($proxyClass === false) {
         return false;
     }
     $proxyClass->addInterfaces($introducedInterfaces);
     $proxyClass->addTraits($introducedTraits);
     /** @var $propertyIntroduction PropertyIntroduction */
     foreach ($propertyIntroductions as $propertyIntroduction) {
         $propertyName = $propertyIntroduction->getPropertyName();
         $declaringAspectClassName = $propertyIntroduction->getDeclaringAspectClassName();
         $possiblePropertyTypes = $this->reflectionService->getPropertyTagValues($declaringAspectClassName, $propertyName, 'var');
         if (count($possiblePropertyTypes) > 0 && !$this->reflectionService->isPropertyAnnotatedWith($declaringAspectClassName, $propertyName, \TYPO3\Flow\Annotations\Transient::class)) {
             $classSchema = $this->reflectionService->getClassSchema($targetClassName);
             if ($classSchema !== null) {
                 $classSchema->addProperty($propertyName, $possiblePropertyTypes[0]);
             }
         }
         $propertyReflection = new PropertyReflection($declaringAspectClassName, $propertyName);
         $propertyReflection->setIsAopIntroduced(true);
         $this->reflectionService->reflectClassProperty($targetClassName, $propertyReflection, new ClassReflection($declaringAspectClassName));
         $proxyClass->addProperty($propertyName, var_export($propertyIntroduction->getInitialValue(), true), $propertyIntroduction->getPropertyVisibility(), $propertyIntroduction->getPropertyDocComment());
     }
     $proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->addPreParentCallCode("        if (method_exists(get_parent_class(), 'Flow_Aop_Proxy_buildMethodsAndAdvicesArray') && is_callable('parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray')) parent::Flow_Aop_Proxy_buildMethodsAndAdvicesArray();\n");
     $proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->addPreParentCallCode($this->buildMethodsAndAdvicesArrayCode($interceptedMethods));
     $proxyClass->getMethod('Flow_Aop_Proxy_buildMethodsAndAdvicesArray')->overrideMethodVisibility('protected');
     $callBuildMethodsAndAdvicesArrayCode = "\n        \$this->Flow_Aop_Proxy_buildMethodsAndAdvicesArray();\n";
     $proxyClass->getConstructor()->addPreParentCallCode($callBuildMethodsAndAdvicesArrayCode);
     $proxyClass->getMethod('__wakeup')->addPreParentCallCode($callBuildMethodsAndAdvicesArrayCode);
     $proxyClass->getMethod('__clone')->addPreParentCallCode($callBuildMethodsAndAdvicesArrayCode);
     if (!$this->reflectionService->hasMethod($targetClassName, '__wakeup')) {
         $proxyClass->getMethod('__wakeup')->addPostParentCallCode("        if (method_exists(get_parent_class(), '__wakeup') && is_callable('parent::__wakeup')) parent::__wakeup();\n");
     }
     $proxyClass->addTraits(['\\' . AdvicesTrait::class]);
     $this->buildMethodsInterceptorCode($targetClassName, $interceptedMethods);
     $proxyClass->addProperty('Flow_Aop_Proxy_targetMethodsAndGroupedAdvices', 'array()');
     $proxyClass->addProperty('Flow_Aop_Proxy_groupedAdviceChains', 'array()');
     $proxyClass->addProperty('Flow_Aop_Proxy_methodIsInAdviceMode', 'array()');
     return true;
 }
 /**
  * @param string $className
  * @param PropertyReflection $property
  * @return integer visibility
  */
 public function reflectClassProperty($className, PropertyReflection $property)
 {
     $propertyName = $property->getName();
     $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName] = array();
     $visibility = $property->isPublic() ? self::VISIBILITY_PUBLIC : ($property->isProtected() ? self::VISIBILITY_PROTECTED : self::VISIBILITY_PRIVATE);
     $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_VISIBILITY] = $visibility;
     foreach ($property->getTagsValues() as $tagName => $tagValues) {
         if ($this->isTagIgnored($tagName)) {
             continue;
         }
         if ($tagName === 'var' && isset($tagValues[0])) {
             if ($property->getDeclaringClass()->getName() !== $className && isset($this->classReflectionData[$property->getDeclaringClass()->getName()][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tagName])) {
                 $tagValues = $this->classReflectionData[$property->getDeclaringClass()->getName()][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tagName];
             } else {
                 $tagValues[0] = $this->expandType($property->getDeclaringClass(), $tagValues[0]);
             }
         }
         $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_TAGS_VALUES][$tagName] = $tagValues;
     }
     foreach ($this->annotationReader->getPropertyAnnotations($property, $propertyName) as $annotation) {
         $this->classReflectionData[$className][self::DATA_CLASS_PROPERTIES][$propertyName][self::DATA_PROPERTY_ANNOTATIONS][get_class($annotation)][] = $annotation;
     }
     return $visibility;
 }