* (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
* All rights reserved
*
-* This class is a backport of the corresponding class of FLOW3.
+* This class is a backport of the corresponding class of FLOW3.
* All credits go to the v5 team.
*
* This script is part of the TYPO3 project. The TYPO3 project is
* A controller argument
*
* @package Extbase
- * @subpackage MVC
+ * @subpackage MVC\Controller
* @version $ID:$
* @scope prototype
*/
class Tx_Extbase_MVC_Controller_Argument {
- /**
- * @var Tx_Extbase_Persistence_ManagerInterface
- */
- protected $persistenceManager;
-
/**
* @var Tx_Extbase_Persistence_QueryFactory
*/
protected $queryFactory;
-
+
/**
* @var Tx_Extbase_Property_Mapper
*/
protected $propertyMapper;
+ /**
+ * @var Tx_Extbase_Reflection_Service
+ */
+ protected $reflectionService;
+
/**
* Name of this argument
* @var string
* Data type of this argument's value
* @var string
*/
- protected $dataType = 'Text';
+ protected $dataType = NULL;
+
+ /**
+ * If the data type is an object, the class schema of the data type class is resolved
+ * @var Tx_Extbase_Reflection_ClassSchema
+ */
+ protected $dataTypeClassSchema;
/**
* TRUE if this argument is required
*/
protected $uid = NULL;
+ const ORIGIN_CLIENT = 0;
+ const ORIGIN_PERSISTENCE = 1;
+ const ORIGIN_PERSISTENCE_AND_MODIFIED = 2;
+ const ORIGIN_NEWLY_CREATED = 3;
+
+ /**
+ * The origin of the argument value. This is only meaningful after argument mapping.
+ *
+ * One of the ORIGIN_* constants above
+ * @var integer
+ */
+ protected $origin = 0;
+
/**
* Constructs this controller argument
*
* @param string $name Name of this argument
* @param string $dataType The data type of this argument
* @throws InvalidArgumentException if $name is not a string or empty
+ * @api
*/
- public function __construct($name, $dataType = 'Text') {
- $this->propertyMapper = t3lib_div::makeInstance('Tx_Extbase_Property_Mapper');
- if (!is_string($name) || strlen($name) < 1) throw new InvalidArgumentException('$name must be of type string, ' . gettype($name) . ' given.', 1187951688);
+ public function __construct($name, $dataType) {
+ if (!is_string($name)) throw new InvalidArgumentException('$name must be of type string, ' . gettype($name) . ' given.', 1187951688);
+ if (strlen($name) === 0) throw new InvalidArgumentException('$name must be a non-empty string, ' . strlen($name) . ' characters given.', 1232551853);
$this->name = $name;
- if (is_array($dataType)) {
- $this->setNewValidatorChain($dataType);
- } else {
- $this->setDataType($dataType);
- }
+ $this->dataType = $dataType;
+ }
+
+ /**
+ * Initializes this object
+ *
+ * @return void
+ */
+ public function initializeObject() {
+ $this->reflectionService = t3lib_div::makeInstance('Tx_Extbase_Reflection_Service');
+ $this->propertyMapper = t3lib_div::makeInstance('Tx_Extbase_Property_Mapper');
+ $this->propertyMapper->injectReflectionService($this->reflectionService);
+ $this->dataTypeClassSchema = $this->reflectionService->getClassSchema($this->dataType);
}
/**
*
* @param Tx_Extbase_Persistence_ManagerInterface
* @return void
- * @internal
*/
public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface $persistenceManager) {
$this->persistenceManager = $persistenceManager;
*
* @param Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory
* @return void
- * @internal
*/
public function injectQueryFactory(Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory) {
$this->queryFactory = $queryFactory;
}
-
+
/**
* Returns the name of this argument
*
* @return string This argument's name
+ * @api
*/
public function getName() {
return $this->name;
* @param string $shortName A "short name" - a single character
* @return Tx_Extbase_MVC_Controller_Argument $this
* @throws InvalidArgumentException if $shortName is not a character
+ * @api
*/
public function setShortName($shortName) {
if ($shortName !== NULL && (!is_string($shortName) || strlen($shortName) !== 1)) throw new InvalidArgumentException('$shortName must be a single character or NULL', 1195824959);
* Returns the short name of this argument
*
* @return string This argument's short name
+ * @api
*/
public function getShortName() {
return $this->shortName;
}
-
+
/**
* Sets the data type of this argument's value
*
* @param string $dataType The data type. Can be either a built-in type such as "Text" or "Integer" or a fully qualified object name
* @return Tx_Extbase_MVC_Controller_Argument $this
+ * @api
*/
public function setDataType($dataType) {
$this->dataType = $dataType;
* Returns the data type of this argument's value
*
* @return string The data type
+ * @api
*/
public function getDataType() {
return $this->dataType;
*
* @param boolean $required TRUE if this argument should be required
* @return Tx_Extbase_MVC_Controller_Argument $this
+ * @api
*/
public function setRequired($required) {
$this->isRequired = (boolean)$required;
* Returns TRUE if this argument is required
*
* @return boolean TRUE if this argument is required
+ * @api
*/
public function isRequired() {
return $this->isRequired;
*
* @param mixed $defaultValue Default value
* @return void
+ * @api
*/
public function setDefaultValue($defaultValue) {
$this->defaultValue = $defaultValue;
* Returns the default value of this argument
*
* @return mixed The default value
+ * @api
*/
public function getDefaultValue() {
return $this->defaultValue;
}
-
+
/**
* Sets a custom validator which is used supplementary to the base validation
*
* @param Tx_Extbase_Validation_Validator_ValidatorInterface $validator The actual validator object
* @return Tx_Extbase_MVC_Controller_Argument Returns $this (used for fluent interface)
+ * @api
*/
public function setValidator(Tx_Extbase_Validation_Validator_ValidatorInterface $validator) {
$this->validator = $validator;
*
* @param array Object names of the validators
* @return Tx_Extbase_MVC_Controller_Argument Returns $this (used for fluent interface)
+ * @api
*/
public function setNewValidatorConjunction(array $objectNames) {
if ($this->validator === NULL) {
}
return $this;
}
+
/**
* Returns the set validator
*
* @return Tx_Extbase_Validation_Validator_ValidatorInterface The set validator, NULL if none was set
+ * @api
*/
public function getValidator() {
return $this->validator;
}
+ /**
+ * Get the origin of the argument value. This is only meaningful after argument mapping.
+ *
+ * @return integer one of the ORIGIN_* constants
+ * @author Sebastian Kurfürst <sebastian@typo3.org>
+ */
+ public function getOrigin() {
+ return $this->origin;
+ }
+
/**
* Sets the value of this argument.
*
* @throws Tx_Extbase_MVC_Exception_InvalidArgumentValue if the argument is not a valid object of type $dataType
*/
public function setValue($value) {
- if (is_array($value)) {
- if (isset($value['uid'])) {
- $existingObject = $this->findObjectByUid($value['uid']);
- if ($existingObject === FALSE) throw new Tx_Extbase_MVC_Exception_InvalidArgumentValue('Argument "' . $this->name . '": Querying the repository for the specified object was not sucessful.', 1237305720);
- unset($value['uid']);
- if (count($value) === 0) {
- $value = $existingObject;
- } elseif ($existingObject !== NULL) {
- $newObject = clone $existingObject;
- if ($this->propertyMapper->map(array_keys($value), $value, $newObject)) {
- $value = $newObject;
- }
- }
+ $this->value = $this->transformValue($value);
+
+ return $this;
+ }
+
+ /**
+ * Checks if the value is a UUID or an array but should be an object, i.e.
+ * the argument's data type class schema is set. If that is the case, this
+ * method tries to look up the corresponding object instead.
+ *
+ * Additionally, it maps arrays to objects in case it is a normal object.
+ *
+ * @param mixed $value The value of an argument
+ * @return mixed
+ */
+ protected function transformValue($value) {
+ if ($value === NULL) {
+ return NULL;
+ }
+ if (!class_exists($this->dataType)) {
+ return $value;
+ }
+ $transformedValue = NULL;
+ if ($this->dataTypeClassSchema !== NULL) {
+ // The target object is an Entity or ValueObject.
+ if (is_numeric($value)) {
+ $this->origin = self::ORIGIN_PERSISTENCE;
+ $transformedValue = $this->findObjectByUid($value);
+ } elseif (is_array($value)) {
+ $this->origin = self::ORIGIN_PERSISTENCE_AND_MODIFIED;
+ $transformedValue = $this->propertyMapper->map(array_keys($value), $value, $this->dataType);
+ }
+ } else {
+ if (!is_array($value)) {
+ throw new Tx_Extbase_MVC_Exception_InvalidArgumentValue('The value was a simple type, so we could not map it to an object. Maybe the @entity or @valueobject annotations are missing?', 1251730701);
+ }
+ $this->origin = self::ORIGIN_NEWLY_CREATED;
+ $transformedValue = $this->propertyMapper->map(array_keys($value), $value, $this->dataType);
+ }
+
+ if (!($transformedValue instanceof $this->dataType)) {
+ if (is_object($transformedValue)) {
+ throw new Tx_Extbase_MVC_Exception_InvalidArgumentValue('The value must be of type "' . $this->dataType . '", but was of type "' . get_class($transformedValue) . '".', 1251730701);
} else {
- $newObject = t3lib_div::makeInstance($this->dataType);
- if ($this->propertyMapper->map(array_keys($value), $value, $newObject)) {
- $value = $newObject;
- }
+ throw new Tx_Extbase_MVC_Exception_InvalidArgumentValue('The value must be of type "' . $this->dataType . '", but was of type "' . gettype($transformedValue) . '".', 1251730702);
}
}
- $this->value = $value;
- return $this;
+ return $transformedValue;
}
-
+
/**
* Finds an object from the repository by searching for its technical UID.
*
* @return mixed Either the object matching the uid or, if none or more than one object was found, FALSE
*/
protected function findObjectByUid($uid) {
- $query = $this->queryFactory->create($this->dataType);
- $object = current($query->matching($query->withUid($uid))->execute());
- // TODO Check if the object is an Aggregate Root (this can be quite difficult because we have no Repository registration
- if ($object !== NULL) {
- $this->persistenceManager->getSession()->registerReconstitutedObject($object);
- return $object;
- } else {
- return FALSE;
- }
+ $query = $this->queryFactory->create($this->dataType);
+ $result = $query->matching($query->withUid($uid))->execute();
+ $object = NULL;
+ if (count($result) > 0) {
+ $object = current($result);
+ }
+ return $object;
}
/**
* Returns the value of this argument
*
* @return object The value of this argument - if none was set, NULL is returned
+ * @api
*/
public function getValue() {
if ($this->value === NULL) {
* Returns a string representation of this argument's value
*
* @return string
+ * @api
*/
public function __toString() {
return (string)$this->value;