/** * Resumes an existing session, if any. * * @return integer If a session was resumed, the inactivity of since the last request is returned * @api */ public function resume() { if ($this->started === false && $this->canBeResumed()) { $this->sessionIdentifier = $this->sessionCookie->getValue(); $this->response->setCookie($this->sessionCookie); $this->started = true; $sessionObjects = $this->storageCache->get($this->storageIdentifier . md5('TYPO3_Flow_Object_ObjectManager')); if (is_array($sessionObjects)) { foreach ($sessionObjects as $object) { if ($object instanceof ProxyInterface) { $objectName = $this->objectManager->getObjectNameByClassName(get_class($object)); if ($this->objectManager->getScope($objectName) === ObjectConfiguration::SCOPE_SESSION) { $this->objectManager->setInstance($objectName, $object); $this->objectManager->get(Aspect\LazyLoadingAspect::class)->registerSessionInstance($objectName, $object); } } } } else { // Fallback for some malformed session data, if it is no array but something else. // In this case, we reset all session objects (graceful degradation). $this->storageCache->set($this->storageIdentifier . md5('TYPO3_Flow_Object_ObjectManager'), [], [$this->storageIdentifier], 0); } $lastActivitySecondsAgo = $this->now - $this->lastActivityTimestamp; $this->lastActivityTimestamp = $this->now; return $lastActivitySecondsAgo; } }
/** * Checks if the specified class and method matches against the filter * * @param string $className Name of the class to check against * @param string $methodName Name of the method to check against * @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. * @return boolean TRUE if the class / method match, otherwise FALSE */ public function matches($className, $methodName, $methodDeclaringClassName, $pointcutQueryIdentifier) { if ($methodName === null) { return false; } $objectName = $this->objectManager->getObjectNameByClassName($className); if (empty($objectName)) { return false; } if ($this->objectManager->getScope($objectName) !== ObjectConfiguration::SCOPE_SESSION) { return false; } if (preg_match('/^__wakeup|__construct|__destruct|__sleep|__serialize|__unserialize|__clone|shutdownObject|initializeObject|inject.*$/', $methodName) !== 0) { return false; } return true; }
/** * Builds a base validator conjunction for the given data type. * * The base validation rules are those which were declared directly in a class (typically * a model) through some validate annotations on properties. * * If a property holds a class for which a base validator exists, that property will be * checked as well, regardless of a validate annotation * * Additionally, if a custom validator was defined for the class in question, it will be added * to the end of the conjunction. A custom validator is found if it follows the naming convention * "Replace '\Model\' by '\Validator\' and append 'Validator'". * * Example: $targetClassName is Neos\Foo\Domain\Model\Quux, then the validator will be found if it has the * name Neos\Foo\Domain\Validator\QuuxValidator * * @param string $indexKey The key to use as index in $this->baseValidatorConjunctions; calculated from target class name and validation groups * @param string $targetClassName The data type to build the validation conjunction for. Needs to be the fully qualified class name. * @param array $validationGroups The validation groups to build the validator for * @return void * @throws Exception\NoSuchValidatorException * @throws \InvalidArgumentException */ protected function buildBaseValidatorConjunction($indexKey, $targetClassName, array $validationGroups) { $conjunctionValidator = new ConjunctionValidator(); $this->baseValidatorConjunctions[$indexKey] = $conjunctionValidator; if (!TypeHandling::isSimpleType($targetClassName) && class_exists($targetClassName)) { // Model based validator $classSchema = $this->reflectionService->getClassSchema($targetClassName); if ($classSchema !== null && $classSchema->isAggregateRoot()) { $objectValidator = new AggregateBoundaryValidator(array()); } else { $objectValidator = new GenericObjectValidator([]); } $conjunctionValidator->addValidator($objectValidator); foreach ($this->reflectionService->getClassPropertyNames($targetClassName) as $classPropertyName) { $classPropertyTagsValues = $this->reflectionService->getPropertyTagsValues($targetClassName, $classPropertyName); if (!isset($classPropertyTagsValues['var'])) { throw new \InvalidArgumentException(sprintf('There is no @var annotation for property "%s" in class "%s".', $classPropertyName, $targetClassName), 1363778104); } try { $parsedType = TypeHandling::parseType(trim(implode('', $classPropertyTagsValues['var']), ' \\')); } catch (InvalidTypeException $exception) { throw new \InvalidArgumentException(sprintf(' @var annotation of ' . $exception->getMessage(), 'class "' . $targetClassName . '", property "' . $classPropertyName . '"'), 1315564744, $exception); } if ($this->reflectionService->isPropertyAnnotatedWith($targetClassName, $classPropertyName, Flow\IgnoreValidation::class)) { continue; } $propertyTargetClassName = $parsedType['type']; if (TypeHandling::isCollectionType($propertyTargetClassName) === true) { $collectionValidator = $this->createValidator(Validator\CollectionValidator::class, ['elementType' => $parsedType['elementType'], 'validationGroups' => $validationGroups]); $objectValidator->addPropertyValidator($classPropertyName, $collectionValidator); } elseif (!TypeHandling::isSimpleType($propertyTargetClassName) && $this->objectManager->isRegistered($propertyTargetClassName) && $this->objectManager->getScope($propertyTargetClassName) === Configuration::SCOPE_PROTOTYPE) { $validatorForProperty = $this->getBaseValidatorConjunction($propertyTargetClassName, $validationGroups); if (count($validatorForProperty) > 0) { $objectValidator->addPropertyValidator($classPropertyName, $validatorForProperty); } } $validateAnnotations = $this->reflectionService->getPropertyAnnotations($targetClassName, $classPropertyName, Flow\Validate::class); foreach ($validateAnnotations as $validateAnnotation) { if (count(array_intersect($validateAnnotation->validationGroups, $validationGroups)) === 0) { // In this case, the validation groups for the property do not match current validation context continue; } $newValidator = $this->createValidator($validateAnnotation->type, $validateAnnotation->options); if ($newValidator === null) { throw new Exception\NoSuchValidatorException('Invalid validate annotation in ' . $targetClassName . '::' . $classPropertyName . ': Could not resolve class name for validator "' . $validateAnnotation->type . '".', 1241098027); } $objectValidator->addPropertyValidator($classPropertyName, $newValidator); } } if (count($objectValidator->getPropertyValidators()) === 0) { $conjunctionValidator->removeValidator($objectValidator); } } $this->addCustomValidators($targetClassName, $conjunctionValidator); }
/** * Builds a new instance of $objectType with the given $possibleConstructorArgumentValues. * If constructor argument values are missing from the given array the method looks for a * default value in the constructor signature. * * Furthermore, the constructor arguments are removed from $possibleConstructorArgumentValues * * @param array &$possibleConstructorArgumentValues * @param string $objectType * @return object The created instance * @throws InvalidTargetException if a required constructor argument is missing */ protected function buildObject(array &$possibleConstructorArgumentValues, $objectType) { $constructorArguments = []; $className = $this->objectManager->getClassNameByObjectName($objectType); $constructorSignature = $this->getConstructorArgumentsForClass($className); if (count($constructorSignature)) { foreach ($constructorSignature as $constructorArgumentName => $constructorArgumentReflection) { if (array_key_exists($constructorArgumentName, $possibleConstructorArgumentValues)) { $constructorArguments[] = $possibleConstructorArgumentValues[$constructorArgumentName]; unset($possibleConstructorArgumentValues[$constructorArgumentName]); } elseif ($constructorArgumentReflection['optional'] === true) { $constructorArguments[] = $constructorArgumentReflection['defaultValue']; } elseif ($this->objectManager->isRegistered($constructorArgumentReflection['type']) && $this->objectManager->getScope($constructorArgumentReflection['type']) === Configuration::SCOPE_SINGLETON) { $constructorArguments[] = $this->objectManager->get($constructorArgumentReflection['type']); } else { throw new InvalidTargetException('Missing constructor argument "' . $constructorArgumentName . '" for object of type "' . $objectType . '".', 1268734872); } } $classReflection = new \ReflectionClass($className); return $classReflection->newInstanceArgs($constructorArguments); } else { return new $className(); } }
/** * Renders a dump of the given object * * @param object $object * @param integer $level * @param boolean $renderProperties * @param boolean $plaintext * @param boolean $ansiColors * @return string */ protected static function renderObjectDump($object, $level, $renderProperties = true, $plaintext = false, $ansiColors = false) { $dump = ''; $scope = ''; $additionalAttributes = ''; if ($object instanceof \Doctrine\Common\Collections\Collection || $object instanceof \ArrayObject) { return self::renderArrayDump(\Doctrine\Common\Util\Debug::export($object, 3), $level, $plaintext, $ansiColors); } // Objects returned from Doctrine's Debug::export function are stdClass with special properties: try { $objectIdentifier = ObjectAccess::getProperty($object, 'Persistence_Object_Identifier', true); } catch (\Neos\Utility\Exception\PropertyNotAccessibleException $exception) { $objectIdentifier = spl_object_hash($object); } $className = $object instanceof \stdClass && isset($object->__CLASS__) ? $object->__CLASS__ : get_class($object); if (isset(self::$renderedObjects[$objectIdentifier]) || preg_match(self::getIgnoredClassesRegex(), $className) !== 0) { $renderProperties = false; } self::$renderedObjects[$objectIdentifier] = true; if (self::$objectManager !== null) { $objectName = self::$objectManager->getObjectNameByClassName(get_class($object)); if ($objectName !== false) { switch (self::$objectManager->getScope($objectName)) { case Configuration::SCOPE_PROTOTYPE: $scope = 'prototype'; break; case Configuration::SCOPE_SINGLETON: $scope = 'singleton'; break; case Configuration::SCOPE_SESSION: $scope = 'session'; break; } } else { $additionalAttributes .= ' debug-unregistered'; } } if ($renderProperties === true && !$plaintext) { if ($scope === '') { $scope = 'prototype'; } $scope .= '<a id="o' . $objectIdentifier . '"></a>'; } if ($plaintext) { $dump .= $className; $dump .= $scope !== '' ? ' ' . self::ansiEscapeWrap($scope, '44;37', $ansiColors) : ''; } else { $dump .= '<span class="debug-object' . $additionalAttributes . '" title="' . $objectIdentifier . '">' . $className . '</span>'; $dump .= $scope !== '' ? '<span class="debug-scope">' . $scope . '</span>' : ''; } if (property_exists($object, 'Persistence_Object_Identifier')) { $persistenceIdentifier = $objectIdentifier; $persistenceType = 'persistable'; } elseif ($object instanceof \Closure) { $persistenceIdentifier = 'n/a'; $persistenceType = 'closure'; } else { $persistenceIdentifier = 'unknown'; $persistenceType = 'object'; } if ($plaintext) { $dump .= ' ' . self::ansiEscapeWrap($persistenceType, '42;37', $ansiColors); } else { $dump .= '<span class="debug-ptype" title="' . $persistenceIdentifier . '">' . $persistenceType . '</span>'; } if ($object instanceof ProxyInterface || property_exists($object, '__IS_PROXY__') && $object->__IS_PROXY__ === true) { if ($plaintext) { $dump .= ' ' . self::ansiEscapeWrap('proxy', '41;37', $ansiColors); } else { $dump .= '<span class="debug-proxy" title="' . $className . '">proxy</span>'; } } if ($renderProperties === true) { if ($object instanceof \SplObjectStorage) { $dump .= ' (' . (count($object) ?: 'empty') . ')'; foreach ($object as $value) { $dump .= chr(10); $dump .= str_repeat(' ', $level); $dump .= self::renderObjectDump($value, 0, false, $plaintext, $ansiColors); } } else { $objectReflection = new \ReflectionObject($object); $properties = $objectReflection->getProperties(); foreach ($properties as $property) { if (preg_match(self::$blacklistedPropertyNames, $property->getName())) { continue; } $dump .= chr(10); $dump .= str_repeat(' ', $level) . ($plaintext ? '' : '<span class="debug-property">') . self::ansiEscapeWrap($property->getName(), '36', $ansiColors) . ($plaintext ? '' : '</span>') . ' => '; $property->setAccessible(true); $value = $property->getValue($object); if (is_array($value)) { $dump .= self::renderDump($value, $level + 1, $plaintext, $ansiColors); } elseif (is_object($value)) { $dump .= self::renderObjectDump($value, $level + 1, true, $plaintext, $ansiColors); } else { $dump .= self::renderDump($value, $level, $plaintext, $ansiColors); } } } } elseif (isset(self::$renderedObjects[$objectIdentifier])) { if (!$plaintext) { $dump = '<a href="#o' . $objectIdentifier . '" onclick="document.location.hash=\'#o' . $objectIdentifier . '\'; return false;" class="debug-seeabove" title="see above">' . $dump . '</a>'; } } return $dump; }
/** * Serializes an object as property array. * * @param object $object The object to store in the registry * @param boolean $isTopLevelItem Internal flag for managing the recursion * @return array The property array */ public function serializeObjectAsPropertyArray($object, $isTopLevelItem = true) { if ($isTopLevelItem) { $this->objectReferences = new \SplObjectStorage(); } $this->objectReferences->attach($object); $className = get_class($object); $propertyArray = []; foreach ($this->reflectionService->getClassPropertyNames($className) as $propertyName) { if ($this->reflectionService->isPropertyTaggedWith($className, $propertyName, 'transient')) { continue; } $propertyReflection = new PropertyReflection($className, $propertyName); $propertyValue = $propertyReflection->getValue($object); if (is_object($propertyValue) && $propertyValue instanceof DependencyInjection\DependencyProxy) { continue; } if (is_object($propertyValue) && isset($this->objectReferences[$propertyValue])) { $propertyArray[$propertyName][self::TYPE] = 'object'; $propertyArray[$propertyName][self::VALUE] = \spl_object_hash($propertyValue); continue; } $propertyClassName = is_object($propertyValue) ? get_class($propertyValue) : ''; if ($propertyClassName === 'SplObjectStorage') { $propertyArray[$propertyName][self::TYPE] = 'SplObjectStorage'; $propertyArray[$propertyName][self::VALUE] = []; foreach ($propertyValue as $storedObject) { $propertyArray[$propertyName][self::VALUE][] = spl_object_hash($storedObject); $this->serializeObjectAsPropertyArray($storedObject, false); } } elseif (is_object($propertyValue) && $propertyValue instanceof \Doctrine\Common\Collections\Collection) { $propertyArray[$propertyName][self::TYPE] = 'Collection'; $propertyArray[$propertyName][self::CLASSNAME] = get_class($propertyValue); foreach ($propertyValue as $storedObject) { $propertyArray[$propertyName][self::VALUE][] = spl_object_hash($storedObject); $this->serializeObjectAsPropertyArray($storedObject, false); } } elseif (is_object($propertyValue) && $propertyValue instanceof \ArrayObject) { $propertyArray[$propertyName][self::TYPE] = 'ArrayObject'; $propertyArray[$propertyName][self::VALUE] = $this->buildStorageArrayForArrayProperty($propertyValue->getArrayCopy()); } elseif (is_object($propertyValue) && $this->persistenceManager->isNewObject($propertyValue) === false && ($this->reflectionService->isClassAnnotatedWith($propertyClassName, Flow\Entity::class) || $this->reflectionService->isClassAnnotatedWith($propertyClassName, Flow\ValueObject::class) || $this->reflectionService->isClassAnnotatedWith($propertyClassName, ORM\Entity::class))) { $propertyArray[$propertyName][self::TYPE] = 'persistenceObject'; $propertyArray[$propertyName][self::VALUE] = get_class($propertyValue) . ':' . $this->persistenceManager->getIdentifierByObject($propertyValue); } elseif (is_object($propertyValue)) { $propertyObjectName = $this->objectManager->getObjectNameByClassName($propertyClassName); if ($this->objectManager->getScope($propertyObjectName) === Configuration::SCOPE_SINGLETON) { continue; } $propertyArray[$propertyName][self::TYPE] = 'object'; $propertyArray[$propertyName][self::VALUE] = spl_object_hash($propertyValue); $this->serializeObjectAsPropertyArray($propertyValue, false); } elseif (is_array($propertyValue)) { $propertyArray[$propertyName][self::TYPE] = 'array'; $propertyArray[$propertyName][self::VALUE] = $this->buildStorageArrayForArrayProperty($propertyValue); } else { $propertyArray[$propertyName][self::TYPE] = 'simple'; $propertyArray[$propertyName][self::VALUE] = $propertyValue; } } $this->objectsAsArray[spl_object_hash($object)] = [self::CLASSNAME => $className, self::PROPERTIES => $propertyArray]; if ($isTopLevelItem) { return $this->objectsAsArray; } }