/** * {@inheritdoc} * * @param object $element * @param string $propertyPath * @return mixed */ protected function getPropertyPath($element, $propertyPath) { if ($propertyPath[0] === '_') { return \TYPO3\FLOW3\Reflection\ObjectAccess::getPropertyPath($element, substr($propertyPath, 1)); } else { return $element->getProperty($propertyPath); } }
/** * @test */ public function overridingFromTypoScriptInFilesystemFollowingNodePathsWorks() { $typoScriptService = $this->objectManager->get('TYPO3\\TYPO3\\Domain\\Service\\TypoScriptService'); ObjectAccess::setProperty($typoScriptService, 'typoScriptsPathPattern', __DIR__ . '/Fixtures/ResourcesFixture/TypoScripts', TRUE); $objectTree = $typoScriptService->getMergedTypoScriptObjectTree($this->homeNode, $this->homeNode->getNode('about-us/history')); $this->assertEquals('Root', $objectTree['text1']['value']); $this->assertEquals('AboutUs', $objectTree['text2']['value']); $this->assertEquals('History', $objectTree['text3']['value']); $this->assertEquals('Additional', $objectTree['text4']['value']); }
public function setUp() { parent::setUp(); $nodeRepository = $this->objectManager->get('TYPO3\\TYPO3CR\\Domain\\Repository\\NodeRepository'); \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($nodeRepository, 'context', new \TYPO3\TYPO3\Domain\Service\ContentContext('live'), TRUE); $siteImportService = $this->objectManager->get('TYPO3\\TYPO3\\Domain\\Service\\SiteImportService'); $siteImportService->importSitesFromFile(__DIR__ . '/Fixtures/NodeStructure.xml'); $this->persistenceManager->persistAll(); $propertyMapper = $this->objectManager->get('TYPO3\\FLOW3\\Property\\PropertyMapper'); $this->node = $propertyMapper->convert('/sites/example/home', 'TYPO3\\TYPO3CR\\Domain\\Model\\Node'); $this->assertFalse($propertyMapper->getMessages()->hasErrors()); }
/** * Updates the password credential from the POST vars, if the POST parameters * are available. Sets the authentication status to AUTHENTICATION_NEEDED, if credentials have been sent. * * Note: You need to send the password in this POST parameter: * __authentication[TYPO3][FLOW3][Security][Authentication][Token][PasswordToken][password] * * @param \TYPO3\FLOW3\Mvc\ActionRequest $actionRequest The current action request * @return void */ public function updateCredentials(\TYPO3\FLOW3\Mvc\ActionRequest $actionRequest) { if ($actionRequest->getHttpRequest()->getMethod() !== 'POST') { return; } $postArguments = $actionRequest->getInternalArguments(); $password = \TYPO3\FLOW3\Reflection\ObjectAccess::getPropertyPath($postArguments, '__authentication.TYPO3.FLOW3.Security.Authentication.Token.PasswordToken.password'); if (!empty($password)) { $this->credentials['password'] = $password; $this->setAuthenticationStatus(self::AUTHENTICATION_NEEDED); } }
public function getMapping($key) { if (isset($this->mappings[$key])) { $property = $this->mappings[$key]; if (isset($this->object->properties[$property])) { return $this->object->properties[$property]->value; } return \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($this->object->object, $property); } if (isset($this->object->properties[$key])) { return $this->object->properties[$key]->value; } # $getter = "get" . ucfirst($key); # if(method_exists($this->object->object, $getter)) # return call_user_func(array($this->object->object, $getter)); return false; }
/** * {@inheritdoc} * * @param \TYPO3\Eel\FlowQuery\FlowQuery $flowQuery the FlowQuery object * @param array $arguments the arguments for this operation * @return mixed|null if the operation is final, the return value */ public function evaluate(\TYPO3\Eel\FlowQuery\FlowQuery $flowQuery, array $arguments) { if (!isset($arguments[0]) || empty($arguments[0])) { throw new \TYPO3\Eel\FlowQuery\FlowQueryException('property() does not support returning all attributes yet', 1332492263); } else { $context = $flowQuery->getContext(); $propertyPath = $arguments[0]; if (!isset($context[0])) { return NULL; } $element = $context[0]; if ($propertyPath[0] === '_') { return \TYPO3\FLOW3\Reflection\ObjectAccess::getPropertyPath($element, substr($propertyPath, 1)); } else { return $element->getProperty($propertyPath); } } }
/** * Check the property value for allowed types and throw exceptions for * unsupported types. * * @param object $object The object with the property to check * @param string $propertyName The name of the property to check * @param array $propertyMetaData Property metadata * @return mixed The value of the property * @throws \TYPO3\FLOW3\Persistence\Generic\Exception\UnexpectedTypeException * @throws \TYPO3\FLOW3\Persistence\Exception * @throws \TYPO3\FLOW3\Persistence\Exception\IllegalObjectTypeException * @api */ protected function checkPropertyValue($object, $propertyName, array $propertyMetaData) { $propertyValue = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($object, $propertyName, TRUE); $propertyType = $propertyMetaData['type']; if ($propertyType === 'ArrayObject') { throw new \TYPO3\FLOW3\Persistence\Exception('ArrayObject properties are not supported - missing feature?!?', 1283524355); } if (is_object($propertyValue)) { if ($propertyType === 'object') { if (!$propertyValue instanceof \TYPO3\FLOW3\Persistence\Aspect\PersistenceMagicInterface) { throw new \TYPO3\FLOW3\Persistence\Exception\IllegalObjectTypeException('Property of generic type object holds "' . get_class($propertyValue) . '", which is not persistable (no entity or value object), in ' . get_class($object) . '::' . $propertyName, 1283531761); } } elseif (!$propertyValue instanceof $propertyType) { throw new \TYPO3\FLOW3\Persistence\Generic\Exception\UnexpectedTypeException('Expected property of type ' . $propertyType . ', but got ' . get_class($propertyValue) . ' for ' . get_class($object) . '::' . $propertyName, 1244465558); } } elseif ($propertyValue !== NULL && $propertyType !== $this->getType($propertyValue)) { throw new \TYPO3\FLOW3\Persistence\Generic\Exception\UnexpectedTypeException('Expected property of type ' . $propertyType . ', but got ' . gettype($propertyValue) . ' for ' . get_class($object) . '::' . $propertyName, 1244465559); } return $propertyValue; }
/** * Creates a URI representation (path segment) for the given object matching $this->uriPattern. * * @param mixed $object object of type $this->objectType * @return string URI representation (path segment) of the given object * @throws \TYPO3\FLOW3\Mvc\Exception\InvalidUriPatternException */ protected function createPathSegmentForObject($object) { $uriPattern = $this->getUriPattern(); if ($uriPattern === '') { return $this->rewriteForUri($this->persistenceManager->getIdentifierByObject($object)); } $matches = array(); preg_match_all('/(?P<dynamic>{?)(?P<content>[^}{]+)}?/', $uriPattern, $matches, PREG_SET_ORDER); $pathSegment = ''; foreach ($matches as $match) { if (empty($match['dynamic'])) { $pathSegment .= $match['content']; } else { $dynamicPathSegmentParts = explode(':', $match['content']); $propertyPath = $dynamicPathSegmentParts[0]; $dynamicPathSegment = \TYPO3\FLOW3\Reflection\ObjectAccess::getPropertyPath($object, $propertyPath); if (is_object($dynamicPathSegment)) { if ($dynamicPathSegment instanceof \DateTime) { $dateFormat = isset($dynamicPathSegmentParts[1]) ? trim($dynamicPathSegmentParts[1]) : 'Y-m-d'; $pathSegment .= $this->rewriteForUri($dynamicPathSegment->format($dateFormat)); } else { throw new \TYPO3\FLOW3\Mvc\Exception\InvalidUriPatternException('Invalid uriPattern "' . $uriPattern . '" for route part "' . $this->getName() . '". Property "' . $propertyPath . '" must be of type string or \\DateTime. "' . (is_object($dynamicPathSegment) ? get_class($dynamicPathSegment) : gettype($dynamicPathSegment)) . '" given.', 1316442409); } } else { $pathSegment .= $this->rewriteForUri($dynamicPathSegment); } } } return $pathSegment; }
/** * Traverses the given object structure in order to transform it into an * array structure. * * @param object $object Object to traverse * @param mixed $configuration Configuration for transforming the given object or NULL * @return array Object structure as an aray */ protected function transformObject($object, $configuration) { if ($object instanceof \DateTime) { return $object->format('Y-m-d\\TH:i:s'); } else { $propertyNames = \TYPO3\FLOW3\Reflection\ObjectAccess::getGettablePropertyNames($object); $propertiesToRender = array(); foreach ($propertyNames as $propertyName) { if (isset($configuration['_only']) && is_array($configuration['_only']) && !in_array($propertyName, $configuration['_only'])) { continue; } if (isset($configuration['_exclude']) && is_array($configuration['_exclude']) && in_array($propertyName, $configuration['_exclude'])) { continue; } $propertyValue = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($object, $propertyName); if (!is_array($propertyValue) && !is_object($propertyValue)) { $propertiesToRender[$propertyName] = $propertyValue; } elseif (isset($configuration['_descend']) && array_key_exists($propertyName, $configuration['_descend'])) { $propertiesToRender[$propertyName] = $this->transformValue($propertyValue, $configuration['_descend'][$propertyName]); } } if (isset($configuration['_exposeObjectIdentifier']) && $configuration['_exposeObjectIdentifier'] === TRUE) { if (isset($configuration['_exposedObjectIdentifierKey']) && strlen($configuration['_exposedObjectIdentifierKey']) > 0) { $identityKey = $configuration['_exposedObjectIdentifierKey']; } else { $identityKey = '__identity'; } $propertiesToRender[$identityKey] = $this->persistenceManager->getIdentifierByObject($object); } return $propertiesToRender; } }
/** * Convert an object from $source to an object. * * @param mixed $source * @param string $targetType * @param array $convertedChildProperties * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration * @return object the target type * @throws \TYPO3\FLOW3\Property\Exception\InvalidTargetException * @throws \TYPO3\FLOW3\Property\Exception\InvalidDataTypeException * @throws \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException */ public function convertFrom($source, $targetType, array $convertedChildProperties = array(), \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) { $effectiveTargetType = $targetType; if (isset($source['__type'])) { if ($configuration->getConfigurationValue('TYPO3\\FLOW3\\Property\\TypeConverter\\ObjectConverter', self::CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED) !== TRUE) { throw new \TYPO3\FLOW3\Property\Exception\InvalidPropertyMappingConfigurationException('Override of target type not allowed. To enable this, you need to set the PropertyMappingConfiguration Value "CONFIGURATION_OVERRIDE_TARGET_TYPE_ALLOWED" to TRUE.', 1317051258); } $effectiveTargetType = $source['__type']; } $object = $this->buildObject($convertedChildProperties, $effectiveTargetType); if ($effectiveTargetType !== $targetType && !$object instanceof $targetType) { throw new \TYPO3\FLOW3\Property\Exception\InvalidDataTypeException('The given type "' . $source['__type'] . '" is not a subtype of "' . $targetType . '"', 1317051266); } foreach ($convertedChildProperties as $propertyName => $propertyValue) { $result = \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($object, $propertyName, $propertyValue); if ($result === FALSE) { throw new \TYPO3\FLOW3\Property\Exception\InvalidTargetException('Property "' . $propertyName . '" having a value of type "' . (is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue)) . '" could not be set in target object of type "' . $targetType . '".', 1304538165); } } return $object; }
/** * 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) { return self::renderArrayDump(\Doctrine\Common\Util\Debug::export($object, 12), $level, $plaintext, $ansiColors); } // Objects returned from Doctrine's Debug::export function are stdClass with special properties: try { $objectIdentifier = ObjectAccess::getProperty($object, 'FLOW3_Persistence_Identifier', TRUE); } catch (\TYPO3\FLOW3\Reflection\Exception\PropertyNotAccessibleException $exception) { $objectIdentifier = spl_object_hash($object); } $className = $object instanceof \stdClass && isset($object->__CLASS__) ? $object->__CLASS__ : get_class($object); if (preg_match(self::$blacklistedClassNames, $className) !== 0 || isset(self::$renderedObjects[$objectIdentifier])) { $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 \TYPO3\FLOW3\Object\Configuration\Configuration::SCOPE_PROTOTYPE: $scope = 'prototype'; break; case \TYPO3\FLOW3\Object\Configuration\Configuration::SCOPE_SINGLETON: $scope = 'singleton'; break; case \TYPO3\FLOW3\Object\Configuration\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, 'FLOW3_Persistence_Identifier')) { $persistenceIdentifier = $objectIdentifier; $persistenceType = 'persistable'; } 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 \TYPO3\FLOW3\Object\Proxy\ProxyInterface || isset($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 { $classReflection = new \ReflectionClass($className); $properties = $classReflection->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; }
/** * Returns the route value of the current route part. * This method can be overridden by custom RoutePartHandlers to implement custom resolving mechanisms. * * @param array $routeValues An array with key/value pairs to be resolved by Dynamic Route Parts. * @return string|array value to resolve. * @api */ protected function findValueToResolve(array $routeValues) { return \TYPO3\FLOW3\Reflection\ObjectAccess::getPropertyPath($routeValues, $this->name); }
/** * @test */ public function getPropertyPathReturnsNullIfSubjectOnPathIsNoObject() { $object = new \stdClass(); $object->foo = 'Hello World'; $this->assertNull(\TYPO3\FLOW3\Reflection\ObjectAccess::getPropertyPath($object, 'foo.bar')); }
/** * After returning advice, generates the value hash for the object * * @param \TYPO3\FLOW3\Aop\JoinPointInterface $joinPoint The current join point * @return void * @FLOW3\Before("classAnnotatedWith(TYPO3\FLOW3\Annotations\ValueObject) && method(.*->__construct())") */ public function generateValueHash(\TYPO3\FLOW3\Aop\JoinPointInterface $joinPoint) { $proxy = $joinPoint->getProxy(); $hashSource = get_class($proxy); if (property_exists($proxy, 'FLOW3_Persistence_Identifier')) { $hashSource .= \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($proxy, 'FLOW3_Persistence_Identifier', TRUE); } foreach ($joinPoint->getMethodArguments() as $argumentValue) { if (is_array($argumentValue)) { $hashSource .= $this->useIgBinary === TRUE ? igbinary_serialize($argumentValue) : serialize($argumentValue); } elseif (!is_object($argumentValue)) { $hashSource .= $argumentValue; } elseif (property_exists($argumentValue, 'FLOW3_Persistence_Identifier')) { $hashSource .= \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($argumentValue, 'FLOW3_Persistence_Identifier', TRUE); } elseif ($argumentValue instanceof \DateTime) { $hashSource .= $argumentValue->getTimestamp(); } } $proxy = $joinPoint->getProxy(); \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($proxy, 'FLOW3_Persistence_Identifier', sha1($hashSource), TRUE); }
/** * Load the property value to be used for validation. * * In case the object is a doctrine proxy, we need to load the real instance first. * * @param object $object * @param string $propertyName * @return mixed */ protected function getPropertyValue($object, $propertyName) { if ($object instanceof \Doctrine\ORM\Proxy\Proxy) { $reflectionLoadMethod = new \ReflectionMethod($object, '__load'); $reflectionLoadMethod->setAccessible(TRUE); $reflectionLoadMethod->invoke($object); } if (\TYPO3\FLOW3\Reflection\ObjectAccess::isPropertyGettable($object, $propertyName)) { return \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($object, $propertyName); } else { return \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($object, $propertyName, TRUE); } }
/** * Converts the specified node path into a Node. * * The node path must be an absolute context node path and can be specified as a string or as an array item with the * key "__contextNodePath". The latter case is for updating existing nodes. * * This conversion method does not support / allow creation of new nodes because new nodes should be created through * the createNode() method of an existing reference node. * * Also note that the context's "current node" is not affected by this object converter, you will need to set it to * whatever node your "current" node is, if any. * * All elements in the source array which start with two underscores (like __contextNodePath) are specially treated * by this converter. * * All elements in the source array which start with a *single underscore (like _hidden) are *directly* set on the Node * object. * * All other elements, not being prefixed with underscore, are properties of the node. * * @param string|array $source Either a string or array containing the absolute context node path which identifies the node. For example "/sites/mysitecom/homepage/about@user-admin" * @param string $targetType not used * @param array $subProperties not used * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration not used * @return mixed An object or \TYPO3\FLOW3\Error\Error if the input format is not supported or could not be converted for other reasons * @throws \Exception */ public function convertFrom($source, $targetType, array $subProperties = array(), \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) { if (is_string($source)) { $source = array('__contextNodePath' => $source); } if (!is_array($source) || !isset($source['__contextNodePath'])) { return new Error('Could not convert ' . gettype($source) . ' to Node object, a valid absolute context node path as a string or array is expected.', 1302879936); } preg_match(NodeInterface::MATCH_PATTERN_CONTEXTPATH, $source['__contextNodePath'], $matches); if (!isset($matches['NodePath'])) { return new Error('Could not convert array to Node object because the node path was invalid.', 1285162903); } $nodePath = $matches['NodePath']; if ($this->nodeRepository->getContext() === NULL) { $workspaceName = isset($matches['WorkspaceName']) ? $matches['WorkspaceName'] : 'live'; $contentContext = new ContentContext($workspaceName); $this->nodeRepository->setContext($contentContext); } else { $contentContext = $this->nodeRepository->getContext(); $workspaceName = $contentContext->getWorkspace()->getName(); } if ($workspaceName !== 'live') { $contentContext->setInvisibleContentShown(TRUE); if ($configuration->getConfigurationValue('TYPO3\\TYPO3\\Routing\\NodeObjectConverter', self::REMOVED_CONTENT_SHOWN) === TRUE) { $contentContext->setRemovedContentShown(TRUE); } } $workspace = $contentContext->getWorkspace(FALSE); if (!$workspace) { return new Error(sprintf('Could not convert %s to Node object because the workspace "%s" as specified in the context node path does not exist.', $source['__contextNodePath'], $workspaceName), 1285162905); } $currentAccessModeFromContext = $contentContext->isInaccessibleContentShown(); $contentContext->setInaccessibleContentShown(TRUE); $node = $contentContext->getNode($nodePath); $contentContext->setInaccessibleContentShown($currentAccessModeFromContext); if (!$node) { return new Error(sprintf('Could not convert array to Node object because the node "%s" does not exist.', $nodePath), 1285162908); } $contentTypeProperties = $node->getContentType()->getProperties(); foreach ($source as $nodePropertyKey => $nodePropertyValue) { if (substr($nodePropertyKey, 0, 2) === '__') { continue; } if ($nodePropertyKey[0] === '_') { $propertyName = substr($nodePropertyKey, 1); // TODO: Hack: we need to create DateTime objects for some properties of Node if (($propertyName === 'hiddenBeforeDateTime' || $propertyName === 'hiddenAfterDateTime') && is_string($nodePropertyValue)) { if ($nodePropertyValue !== '') { $nodePropertyValue = \DateTime::createFromFormat('!Y-m-d', $nodePropertyValue); } else { $nodePropertyValue = NULL; } } \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($node, $propertyName, $nodePropertyValue); } else { if (!isset($contentTypeProperties[$nodePropertyKey])) { throw new \Exception('TODO: content type XY does not have a property YY according to the schema'); } if (isset($contentTypeProperties[$nodePropertyKey]['type'])) { $targetType = $contentTypeProperties[$nodePropertyKey]['type']; if ($this->objectManager->isRegistered($targetType)) { $nodePropertyValue = $this->propertyMapper->convert(json_decode($nodePropertyValue, TRUE), $targetType); } } $node->setProperty($nodePropertyKey, $nodePropertyValue); } } return $node; }
public function toArray() { $array = array(); $properties = get_class_vars(get_class($this)); foreach ($properties as $property => $value) { $value = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($this, $property); if (is_object($value) && is_callable(array($value, "__toString"))) { $array[$property] = strval($value); } else { $array[$property] = $value; } } return $array; }
/** * Returns the identifier for the given object either from * the session, if the object was registered, or from the object * itself using a special uuid property or the internal * properties set by AOP. * * Note: this returns an UUID even if the object has not been persisted * in case of AOP-managed entities. Use isNewObject() if you need * to distinguish those cases. * * @param object $object * @return string * @api */ public function getIdentifierByObject($object) { if ($this->hasObject($object)) { return $this->objectMap[$object]; } $idPropertyNames = $this->reflectionService->getPropertyNamesByTag(get_class($object), 'id'); if (count($idPropertyNames) === 1) { $idPropertyName = $idPropertyNames[0]; return \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($object, $idPropertyName, TRUE); } elseif (property_exists($object, 'FLOW3_Persistence_Identifier')) { return \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($object, 'FLOW3_Persistence_Identifier', TRUE); } return NULL; }
/** * Wrap the $content identified by $node with the needed markup for * the backend. * $parameters can be used to further pass parameters to the content element. * * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node * @param string $typoscriptPath * @param string $content * @param boolean $isPage * @return string */ public function wrapContentObject(\TYPO3\TYPO3CR\Domain\Model\NodeInterface $node, $typoscriptPath, $content, $isPage = FALSE) { $contentType = $node->getContentType(); $tagBuilder = new \TYPO3\Fluid\Core\ViewHelper\TagBuilder('div'); $tagBuilder->forceClosingTag(TRUE); if (!$node->isRemoved()) { $tagBuilder->setContent($content); } if (!$isPage) { $cssClasses = array('t3-contentelement'); $cssClasses[] = str_replace(array(':', '.'), '-', strtolower($contentType->getName())); if ($node->isHidden()) { $cssClasses[] = 't3-contentelement-hidden'; } if ($node->isRemoved()) { $cssClasses[] = 't3-contentelement-removed'; } $tagBuilder->addAttribute('class', implode(' ', $cssClasses)); $tagBuilder->addAttribute('id', 'c' . $node->getIdentifier()); } try { $this->accessDecisionManager->decideOnResource('TYPO3_TYPO3_Backend_BackendController'); } catch (\TYPO3\FLOW3\Security\Exception\AccessDeniedException $e) { return $tagBuilder->render(); } $tagBuilder->addAttribute('typeof', 'typo3:' . $contentType->getName()); $tagBuilder->addAttribute('about', $node->getContextPath()); $this->addScriptTag($tagBuilder, '__workspacename', $node->getWorkspace()->getName()); $this->addScriptTag($tagBuilder, '_removed', $node->isRemoved() ? 'true' : 'false', 'boolean'); $this->addScriptTag($tagBuilder, '_typoscriptPath', $typoscriptPath); foreach ($contentType->getProperties() as $propertyName => $propertyConfiguration) { $dataType = isset($propertyConfiguration['type']) ? $propertyConfiguration['type'] : 'string'; if ($propertyName[0] === '_') { $propertyValue = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($node, substr($propertyName, 1)); } else { $propertyValue = $node->getProperty($propertyName); } // Serialize boolean values to String if (isset($propertyConfiguration['type']) && $propertyConfiguration['type'] === 'boolean') { $propertyValue = $propertyValue ? 'true' : 'false'; } // Serialize date values to String if ($propertyValue !== NULL && isset($propertyConfiguration['type']) && $propertyConfiguration['type'] === 'date') { $propertyValue = $propertyValue->format('Y-m-d'); } // Serialize objects to JSON strings if (is_object($propertyValue) && $propertyValue !== NULL && isset($propertyConfiguration['type']) && $this->objectManager->isRegistered($propertyConfiguration['type'])) { $gettableProperties = \TYPO3\FLOW3\Reflection\ObjectAccess::getGettableProperties($propertyValue); $convertedProperties = array(); foreach ($gettableProperties as $key => $value) { if (is_object($value)) { $entityIdentifier = $this->persistenceManager->getIdentifierByObject($value); if ($entityIdentifier !== NULL) { $value = $entityIdentifier; } } $convertedProperties[$key] = $value; } $propertyValue = json_encode($convertedProperties); $dataType = 'jsonEncoded'; } $this->addScriptTag($tagBuilder, $propertyName, $propertyValue, $dataType); } if (!$isPage) { // add CSS classes $this->addScriptTag($tagBuilder, '__contenttype', $contentType->getName()); } else { $tagBuilder->addAttribute('id', 't3-page-metainformation'); $tagBuilder->addAttribute('data-__sitename', $this->nodeRepository->getContext()->getCurrentSite()->getName()); $tagBuilder->addAttribute('data-__siteroot', sprintf('/sites/%s@%s', $this->nodeRepository->getContext()->getCurrentSite()->getNodeName(), $this->nodeRepository->getContext()->getWorkspace()->getName())); } return $tagBuilder->render(); }
/** * Iterates through all segments in $this->uriPattern and creates * appropriate RoutePart instances. * * @return void * @throws \TYPO3\FLOW3\Mvc\Exception\InvalidRoutePartHandlerException * @throws \TYPO3\FLOW3\Mvc\Exception\InvalidUriPatternException */ public function parse() { if ($this->isParsed || $this->uriPattern === NULL || $this->uriPattern === '') { return; } $this->routeParts = array(); $currentRoutePartIsOptional = FALSE; if (substr($this->uriPattern, -1) === '/') { throw new \TYPO3\FLOW3\Mvc\Exception\InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" ends with a slash, which is not allowed. You can put the trailing slash in brackets to make it optional.', 1234782997); } if ($this->uriPattern[0] === '/') { throw new \TYPO3\FLOW3\Mvc\Exception\InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" starts with a slash, which is not allowed.', 1234782983); } $matches = array(); preg_match_all(self::PATTERN_EXTRACTROUTEPARTS, $this->uriPattern, $matches, PREG_SET_ORDER); $lastRoutePart = NULL; foreach ($matches as $match) { $routePartType = empty($match['dynamic']) ? self::ROUTEPART_TYPE_STATIC : self::ROUTEPART_TYPE_DYNAMIC; $routePartName = $match['content']; if (!empty($match['optionalStart'])) { if ($lastRoutePart !== NULL && $lastRoutePart->isOptional()) { throw new \TYPO3\FLOW3\Mvc\Exception\InvalidUriPatternException('the URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains successive optional Route sections, which is not allowed.', 1234562050); } $currentRoutePartIsOptional = TRUE; } $routePart = NULL; switch ($routePartType) { case self::ROUTEPART_TYPE_DYNAMIC: if ($lastRoutePart instanceof \TYPO3\FLOW3\Mvc\Routing\DynamicRoutePartInterface) { throw new \TYPO3\FLOW3\Mvc\Exception\InvalidUriPatternException('the URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains successive Dynamic Route Parts, which is not allowed.', 1218446975); } if (isset($this->routePartsConfiguration[$routePartName]['handler'])) { $routePart = $this->objectManager->get($this->routePartsConfiguration[$routePartName]['handler']); if (!$routePart instanceof \TYPO3\FLOW3\Mvc\Routing\DynamicRoutePartInterface) { throw new \TYPO3\FLOW3\Mvc\Exception\InvalidRoutePartHandlerException('routePart handlers must implement "\\TYPO3\\FLOW3\\Mvc\\Routing\\DynamicRoutePartInterface" in route "' . $this->getName() . '"', 1218480972); } } elseif (isset($this->routePartsConfiguration[$routePartName]['objectType'])) { $routePart = new \TYPO3\FLOW3\Mvc\Routing\IdentityRoutePart(); $routePart->setObjectType($this->routePartsConfiguration[$routePartName]['objectType']); if (isset($this->routePartsConfiguration[$routePartName]['uriPattern'])) { $routePart->setUriPattern($this->routePartsConfiguration[$routePartName]['uriPattern']); } } else { $routePart = new \TYPO3\FLOW3\Mvc\Routing\DynamicRoutePart(); } $routePartDefaultValue = \TYPO3\FLOW3\Reflection\ObjectAccess::getPropertyPath($this->defaults, $routePartName); if ($routePartDefaultValue !== NULL) { $routePart->setDefaultValue($routePartDefaultValue); } break; case self::ROUTEPART_TYPE_STATIC: $routePart = new \TYPO3\FLOW3\Mvc\Routing\StaticRoutePart(); if ($lastRoutePart !== NULL && $lastRoutePart instanceof \TYPO3\FLOW3\Mvc\Routing\DynamicRoutePartInterface) { $lastRoutePart->setSplitString($routePartName); } } $routePart->setName($routePartName); $routePart->setOptional($currentRoutePartIsOptional); $routePart->setLowerCase($this->lowerCase); if (isset($this->routePartsConfiguration[$routePartName]['options'])) { $routePart->setOptions($this->routePartsConfiguration[$routePartName]['options']); } if (isset($this->routePartsConfiguration[$routePartName]['toLowerCase'])) { $routePart->setLowerCase($this->routePartsConfiguration[$routePartName]['toLowerCase']); } $this->routeParts[] = $routePart; if (!empty($match['optionalEnd'])) { if (!$currentRoutePartIsOptional) { throw new \TYPO3\FLOW3\Mvc\Exception\InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains an unopened optional section.', 1234564495); } $currentRoutePartIsOptional = FALSE; } $lastRoutePart = $routePart; } if ($currentRoutePartIsOptional) { throw new \TYPO3\FLOW3\Mvc\Exception\InvalidUriPatternException('The URI pattern "' . $this->uriPattern . '" of route "' . $this->getName() . '" contains an unterminated optional section.', 1234563922); } $this->isParsed = TRUE; }
/** * Redirects directly to \TYPO3\FLOW3\Reflection\ObjectAccess::getPropertyPath($result, $propertyPath) * This is only needed for unit tests! * * @param mixed $object The object to fetch the property from * @param string $path The path to the property to be fetched * @return mixed The property value */ protected function getObjectValueByPath($object, $path) { return \TYPO3\FLOW3\Reflection\ObjectAccess::getPropertyPath($object, $path); }
/** * returns the specified property of the mixed variable * * @param string $property * @param string $mixed * @return void * @author Marc Neuhaus */ public function getValue($property, $mixed) { $value = null; try { if (is_object($mixed) || is_array($mixed)) { $value = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($mixed, $property); } } catch (\TYPO3\FLOW3\Reflection\Exception\PropertyNotAccessibleException $e) { var_dump($e); } return $value; }
/** * Registers an object which has been created or cloned during this request. * * The given object must contain the FLOW3_Persistence_Identifier property, thus * the PersistenceMagicInterface type hint. A "new" object does not necessarily * have to be known by any repository or be persisted in the end. * * Objects registered with this method must be known to the getObjectByIdentifier() * method. * * @param \TYPO3\FLOW3\Persistence\Aspect\PersistenceMagicInterface $object The new object to register * @return void */ public function registerNewObject(\TYPO3\FLOW3\Persistence\Aspect\PersistenceMagicInterface $object) { $identifier = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($object, 'FLOW3_Persistence_Identifier', TRUE); $this->newObjects[$identifier] = $object; }
/** * Convert an object from $source to an entity or a value object. * * @param mixed $source * @param string $targetType * @param array $convertedChildProperties * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration * @return object the target type * @throws \TYPO3\FLOW3\Property\Exception\InvalidTargetException * @throws \InvalidArgumentException */ public function convertFrom($source, $targetType, array $convertedChildProperties = array(), \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL) { if (is_array($source)) { if ($this->reflectionService->isClassAnnotatedWith($targetType, 'TYPO3\\FLOW3\\Annotations\\ValueObject')) { // Unset identity for valueobject to use constructor mapping, since the identity is determined from // constructor arguments unset($source['__identity']); } $object = $this->handleArrayData($source, $targetType, $convertedChildProperties, $configuration); } elseif (is_string($source)) { if ($source === '') { return NULL; } $object = $this->fetchObjectFromPersistence($source, $targetType); } else { throw new \InvalidArgumentException('Only strings and arrays are accepted.', 1305630314); } foreach ($convertedChildProperties as $propertyName => $propertyValue) { $result = \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($object, $propertyName, $propertyValue); if ($result === FALSE) { throw new \TYPO3\FLOW3\Property\Exception\InvalidTargetException('Property "' . $propertyName . '" having a value of type "' . (is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue)) . '" could not be set in target object of type "' . $targetType . '".', 1297935345); } } return $object; }
/** * @test */ public function validatePasswordWillUseStrategyIdentifierFromHashedPassword() { $settings = array('security' => array('cryptography' => array('hashingStrategies' => array('TestStrategy' => 'TYPO3\\FLOW3\\Test\\TestStrategy')))); $this->hashService->injectSettings($settings); $mockStrategy = $this->getMock('TYPO3\\FLOW3\\Security\\Cryptography\\PasswordHashingStrategyInterface'); $mockObjectManager = $this->getMock('TYPO3\\FLOW3\\Object\\ObjectManagerInterface'); $mockObjectManager->expects($this->any())->method('get')->will($this->returnValue($mockStrategy)); \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($this->hashService, 'objectManager', $mockObjectManager, TRUE); $mockStrategy->expects($this->atLeastOnce())->method('validatePassword')->with('myTestPassword', '---hashed-password---')->will($this->returnValue(TRUE)); $result = $this->hashService->validatePassword('myTestPassword', 'TestStrategy=>---hashed-password---'); $this->assertEquals(TRUE, $result); }
public function getStringByProperties($source) { $properties = $this->getProperties($source); $strings = array(); $count = 0; foreach ($properties as $key => $meta) { if ($count > 3) { break; } if ($key !== "FLOW3_Persistence_Identifier") { if (\TYPO3\FLOW3\Reflection\ObjectAccess::isPropertyGettable($source, $key)) { $value = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($source, $key); if (is_string($value)) { $strings[] = $value; $count++; } elseif (is_object($value) && $this->nestingLevel < 3) { $this->nestingLevel++; $string = $this->convertFrom($value, "string"); if (!is_null($string)) { $strings[] = $string; $count++; } $this->nestingLevel--; } } } } if (!empty($strings)) { return implode(", ", $strings); } return false; }
/** * @test */ public function collectionValidatorIsValidEarlyReturnsOnUnitializedDoctrinePersistenceCollections() { $entityManager = $this->getMock('Doctrine\\ORM\\EntityManager', array(), array(), '', FALSE); $collection = new \Doctrine\Common\Collections\ArrayCollection(array()); $persistentCollection = new \Doctrine\ORM\PersistentCollection($entityManager, '', $collection); \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($persistentCollection, 'initialized', FALSE, TRUE); $this->mockValidatorResolver->expects($this->never())->method('createValidator'); $this->validator->validate($persistentCollection); }
/** * MongoDB does not do partial updates, thus this method always collects the * full set of properties. * Value objects are always inlined. * * @param string $identifier The object's identifier * @param object $object The object to work on * @param array $properties The properties to collect (as per class schema) * @param boolean $dirty A dirty flag that is passed by reference and set to TRUE if a dirty property was found * @author Karsten Dambekalns <*****@*****.**> * @author Christopher Hlubek <*****@*****.**> */ protected function collectProperties($identifier, $object, array $properties, &$dirty) { $propertyData = array(); foreach ($properties as $propertyName => $propertyMetaData) { $this->checkPropertyValue($object, $propertyName, $propertyMetaData); $propertyValue = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($object, $propertyName, TRUE); if ($this->persistenceSession->isDirty($object, $propertyName)) { $dirty = TRUE; } $this->flattenValue($identifier, $object, $propertyName, $propertyMetaData, $propertyData); } return $propertyData; }
/** * Sets the given properties on the object. * * @param object $object The object to set properties on * @param string $identifier The identifier of the object * @param array $objectData * @return void * @throws \TYPO3\FLOW3\Persistence\Exception\UnknownObjectException */ public function thawProperties($object, $identifier, array $objectData) { $classSchema = $this->reflectionService->getClassSchema($objectData['classname']); foreach ($objectData['properties'] as $propertyName => $propertyData) { if (!$classSchema->hasProperty($propertyName)) { continue; } $propertyValue = NULL; if ($propertyData['value'] !== NULL) { switch ($propertyData['type']) { case 'integer': $propertyValue = (int) $propertyData['value']; break; case 'float': $propertyValue = (double) $propertyData['value']; break; case 'boolean': $propertyValue = (bool) $propertyData['value']; break; case 'string': $propertyValue = (string) $propertyData['value']; break; case 'array': $propertyValue = $this->mapArray($propertyData['value']); break; case 'Doctrine\\Common\\Collections\\Collection': case 'Doctrine\\Common\\Collections\\ArrayCollection': $propertyValue = new \Doctrine\Common\Collections\ArrayCollection($this->mapArray($propertyData['value'])); break; case 'SplObjectStorage': $propertyMetaData = $classSchema->getProperty($propertyName); $propertyValue = $this->mapSplObjectStorage($propertyData['value'], $propertyMetaData['lazy']); break; case 'DateTime': $propertyValue = $this->mapDateTime($propertyData['value']); break; default: if ($propertyData['value'] === FALSE) { throw new \TYPO3\FLOW3\Persistence\Exception\UnknownObjectException('An expected object was not found by the backend. It was expected for ' . $objectData['classname'] . '::' . $propertyName, 1289509867); } $propertyValue = $this->mapToObject($propertyData['value']); break; } } else { switch ($propertyData['type']) { case 'NULL': continue; break; case 'array': $propertyValue = $this->mapArray(NULL); break; case 'Doctrine\\Common\\Collections\\Collection': case 'Doctrine\\Common\\Collections\\ArrayCollection': $propertyValue = new \Doctrine\Common\Collections\ArrayCollection(); break; case 'SplObjectStorage': $propertyValue = $this->mapSplObjectStorage(NULL); break; } } \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($object, $propertyName, $propertyValue, TRUE); } if (isset($objectData['metadata'])) { $object->FLOW3_Persistence_Metadata = $objectData['metadata']; } \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($object, 'FLOW3_Persistence_Identifier', $identifier, TRUE); }
/** * Returns the (internal) identifier for the object, if it is known to the * backend. Otherwise NULL is returned. * * Note: this returns an identifier even if the object has not been * persisted in case of AOP-managed entities. Use isNewObject() if you need * to distinguish those cases. * * @param object $object * @return mixed The identifier for the object if it is known, or NULL * @api * @todo improve try/catch block */ public function getIdentifierByObject($object) { if ($this->entityManager->contains($object)) { try { return current($this->entityManager->getUnitOfWork()->getEntityIdentifier($object)); } catch (\Doctrine\ORM\ORMException $e) { return NULL; } } elseif (property_exists($object, 'FLOW3_Persistence_Identifier')) { return \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($object, 'FLOW3_Persistence_Identifier', TRUE); } else { return NULL; } }