[-TASK] Extbase (Persistence): Removed unnecessary classes, code and empty interfaces.
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / MVC / Controller / Argument.php
index 3bbc20d..6fb2709 100644 (file)
@@ -5,6 +5,9 @@
 *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
 *  All rights reserved
 *
+*  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
 *  free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 /**
  * A controller argument
  *
- * @package TYPO3
- * @subpackage extbase
+ * @package Extbase
+ * @subpackage MVC\Controller
  * @version $ID:$
  * @scope prototype
+ * @api
  */
-class Tx_ExtBase_MVC_Controller_Argument {
+class Tx_Extbase_MVC_Controller_Argument {
+
+       /**
+        * @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
@@ -48,7 +67,13 @@ class Tx_ExtBase_MVC_Controller_Argument {
         * 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
@@ -63,57 +88,88 @@ class Tx_ExtBase_MVC_Controller_Argument {
        protected $value = NULL;
 
        /**
-        * The argument is valid
-        * @var boolean
+        * Default value. Used if argument is optional.
+        * @var mixed
         */
-       protected $isValid = NULL;
+       protected $defaultValue = NULL;
 
        /**
-        * Any error (Tx_ExtBase_Error_Error) that occured while initializing this argument (e.g. a mapping error)
-        * @var array
-        */
-       protected $errors = array();
-
-       /**
-        * The property validator for this argument
-        * @var Tx_ExtBase_Validation_Validator_ValidatorInterface
+        * A custom validator, used supplementary to the base validation
+        * @var Tx_Extbase_Validation_Validator_ValidatorInterface
         */
        protected $validator = NULL;
 
        /**
-        * The property validator for this arguments datatype
-        * @var Tx_ExtBase_Validation_Validator_ValidatorInterface
-        */
-       // TODO Remove DatatypeValidator
-       protected $datatypeValidator = NULL;
-
-       /**
         * Uid for the argument, if it has one
         * @var string
         */
        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') {
-               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 = (strstr($this->dataType, '_') !== FALSE) ? $this->reflectionService->getClassSchema($this->dataType) : NULL;
+       }
+
+       /**
+        * Injects the Persistence Manager
+        *
+        * @param Tx_Extbase_Persistence_ManagerInterface
+        * @return void
+        */
+       public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface $persistenceManager) {
+               $this->persistenceManager = $persistenceManager;
+       }
+
+       /**
+        * Injects a QueryFactory instance
+        *
+        * @param Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory
+        * @return void
+        */
+       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;
@@ -123,11 +179,12 @@ class Tx_ExtBase_MVC_Controller_Argument {
         * Sets the short name of this argument.
         *
         * @param string $shortName A "short name" - a single character
-        * @return Tx_ExtBase_MVC_Controller_Argument $this
+        * @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);
+               if ($shortName !== NULL && (!is_string($shortName) || strlen($shortName) !== 1)) throw new InvalidArgumentException('$shortName must be a single character or NULL', 1195824959);
                $this->shortName = $shortName;
                return $this;
        }
@@ -136,6 +193,7 @@ class Tx_ExtBase_MVC_Controller_Argument {
         * Returns the short name of this argument
         *
         * @return string This argument's short name
+        * @api
         */
        public function getShortName() {
                return $this->shortName;
@@ -144,18 +202,13 @@ class Tx_ExtBase_MVC_Controller_Argument {
        /**
         * Sets the data type of this argument's value
         *
-        * @param string $dataType: Name of the data type
-        * @return Tx_ExtBase_MVC_Controller_Argument $this
+        * @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 != '' ? $dataType : 'Text');
-               // TODO Make validator path and class names configurable
-               $dataTypeValidatorClassName = 'Tx_ExtBase_Validation_Validator_' . $this->dataType;
-               $classFilePathAndName = t3lib_extMgm::extPath('extbase') . 'Classes/Validation/Validator/' . $this->dataType . '.php';
-               if (isset($classFilePathAndName) && file_exists($classFilePathAndName)) {                       
-                       require_once($classFilePathAndName);
-                       $this->datatypeValidator = t3lib_div::makeInstance($dataTypeValidatorClassName);
-               }
+               $this->dataType = $dataType;
+               $this->dataTypeClassSchema = $this->reflectionService->getClassSchema($dataType);
                return $this;
        }
 
@@ -163,6 +216,7 @@ class Tx_ExtBase_MVC_Controller_Argument {
         * Returns the data type of this argument's value
         *
         * @return string The data type
+        * @api
         */
        public function getDataType() {
                return $this->dataType;
@@ -172,10 +226,11 @@ class Tx_ExtBase_MVC_Controller_Argument {
         * Marks this argument to be required
         *
         * @param boolean $required TRUE if this argument should be required
-        * @return Tx_ExtBase_MVC_Controller_Argument $this
+        * @return Tx_Extbase_MVC_Controller_Argument $this
+        * @api
         */
        public function setRequired($required) {
-               $this->isRequired = $required;
+               $this->isRequired = (boolean)$required;
                return $this;
        }
 
@@ -183,170 +238,182 @@ class Tx_ExtBase_MVC_Controller_Argument {
         * Returns TRUE if this argument is required
         *
         * @return boolean TRUE if this argument is required
+        * @api
         */
        public function isRequired() {
                return $this->isRequired;
        }
 
        /**
-        * Sets the value of this argument.
+        * Sets the default value of the argument
         *
-        * @param mixed $value: The value of this argument
-        * @return Tx_ExtBase_MVC_Controller_Argument $this
-        * @throws Tx_ExtBase_Exception_InvalidArgumentValue if the argument is not a valid object of type $dataType
+        * @param mixed $defaultValue Default value
+        * @return void
+        * @api
         */
-       public function setValue($value) {
-               if ($this->isValidValueForThisArgument($value)) {
-                       $this->value = $value;
-               }
-               return $this;
+       public function setDefaultValue($defaultValue) {
+               $this->defaultValue = $defaultValue;
        }
 
        /**
-        * Returns the value of this argument
+        * Returns the default value of this argument
         *
-        * @return object The value of this argument - if none was set, NULL is returned
+        * @return mixed The default value
+        * @api
         */
-       public function getValue() {
-               return $this->value;
+       public function getDefaultValue() {
+               return $this->defaultValue;
        }
 
        /**
-        * Checks if this argument has a value set.
+        * Sets a custom validator which is used supplementary to the base validation
         *
-        * @return boolean TRUE if a value was set, otherwise FALSE
+        * @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 isValue() {
-               return $this->value !== NULL;
+       public function setValidator(Tx_Extbase_Validation_Validator_ValidatorInterface $validator) {
+               $this->validator = $validator;
+               return $this;
        }
 
        /**
-        * undocumented function
+        * Create and set a validator chain
         *
-        * @param string $value 
-        * @return boolean TRUE if the value is valid for this argument, otherwise FALSE
-        */
-       protected function isValidValueForThisArgument($value) {
-               $isValid = TRUE;
-               $validatorErrors = t3lib_div::makeInstance('Tx_ExtBase_Validation_Errors');
-               // TODO use only Validator; do not distinguish between Validator and DatatypeValidator
-               if ($this->getValidator() !== NULL) {
-                       $isValid &= $this->getValidator()->isValid($value, $validatorErrors);
-               } elseif ($this->getDatatypeValidator() !== NULL) {
-                       $isValid = $this->getDatatypeValidator()->isValid($value, $validatorErrors);                    
-               } else {
-                       throw new Tx_ExtBase_Validation_Exception_NoValidatorFound('No appropriate validator for the argument "' . $this->getName() . '" was found.', 1235748909);
+        * @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) {
+                       $this->validator = t3lib_div::makeInstance('Tx_Extbase_Validation_Validator_ConjunctionValidator');
                }
-               if (!$isValid) {
-                       foreach ($validatorErrors as $error) {
-                               $this->addError($error);
-                       }
+               foreach ($objectNames as $objectName) {
+                       if (!class_exists($objectName)) $objectName = 'Tx_Extbase_Validation_Validator_' . $objectName;
+                       $this->validator->addValidator(t3lib_div::makeInstance($objectName));
                }
-               $this->isValid = $isValid;
-               return (boolean)$isValid;
+               return $this;
        }
 
        /**
-        * Returns TRUE when the argument is valid
-        *
-        * @return boolean TRUE if the argument is valid
-        */
-       public function isValid() {
-               return $this->isValid;
-       }
-       
-       /**
-        * Add an initialization error (e.g. a mapping error)
+        * Returns the set validator
         *
-        * @param string An error text
-        * @return void
+        * @return Tx_Extbase_Validation_Validator_ValidatorInterface The set validator, NULL if none was set
+        * @api
         */
-       public function addError($error) {
-               $this->errors[] = $error;
+       public function getValidator() {
+               return $this->validator;
        }
 
        /**
-        * Get all initialization errors
+        * Get the origin of the argument value. This is only meaningful after argument mapping.
         *
-        * @return array An array containing Tx_ExtBase_Error_Error objects
-        * @see addError(Tx_ExtBase_Error_Error $error)
+        * @return integer one of the ORIGIN_* constants
+        * @author Sebastian Kurf├╝rst <sebastian@typo3.org>
         */
-       public function getErrors() {
-               return $this->errors;
+       public function getOrigin() {
+               return $this->origin;
        }
 
        /**
-        * Set an additional validator
+        * Sets the value of this argument.
         *
-        * @param string Class name of a validator
-        * @return Tx_ExtBase_MVC_Controller_Argument Returns $this (used for fluent interface)
+        * @param mixed $value: The value of this argument
+        * @return Tx_Extbase_MVC_Controller_Argument $this
+        * @throws Tx_Extbase_MVC_Exception_InvalidArgumentValue if the argument is not a valid object of type $dataType
         */
-       public function setValidator($className) {
-               $this->validator = t3lib_div::makeInstance($className);
+       public function setValue($value) {
+               $this->value = $this->transformValue($value);
+
                return $this;
        }
 
        /**
-        * Returns the set validator
+        * 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.
         *
-        * @return Tx_ExtBase_Validation_Validator_ValidatorInterface The set validator, NULL if none was set
-        */
-       public function getValidator() {
-               return $this->validator;
-       }
-
-       /**
-        * Returns the set datatype validator
+        * Additionally, it maps arrays to objects in case it is a normal object.
         *
-        * @return Tx_ExtBase_Validation_Validator_ValidatorInterface The set datatype validator
+        * @param mixed $value The value of an argument
+        * @return mixed
         */
-       public function getDatatypeValidator() {
-               return $this->datatypeValidator;
+       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)) {
+                       throw new Tx_Extbase_MVC_Exception_InvalidArgumentValue('The value must be of type "' . $this->dataType . '", but was of type "' . (is_object($transformedValue) ? get_class($transformedValue) : gettype($transformedValue)) . '".', 1251730701);
+               }
+               return $transformedValue;
        }
-       
+
        /**
-        * Create and set a validator chain
+        * Finds an object from the repository by searching for its technical UID.
         *
-        * @param array Object names of the validators
-        * @return Tx_ExtBase_MVC_Controller_Argument Returns $this (used for fluent interface)
-        */
-       public function setNewValidatorChain(array $validators) {
-               $this->validator = t3lib_div::makeInstance('Tx_ExtBase_Validation_Validator_ChainValidator');
-               foreach ($validators as $validator) {
-                       if (is_array($validator)) {
-                               $objectName = 'Tx_ExtBase_Validation_Validator_' . $validator[0];
-                               $this->validator->addValidator(new $objectName);
-                       } else {
-                               $objectName = 'Tx_ExtBase_Validation_Validator_' . $validator;
-                               $this->validator->addValidator(t3lib_div::makeInstance($objectName));
-                       }
+        * @param int $uid The object's 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);
+               $query->getQuerySettings()->setRespectSysLanguage(FALSE);
+               $result = $query->matching($query->withUid($uid))->execute();
+               $object = NULL;
+               if (count($result) > 0) {
+                       $object = current($result);
                }
-               return $this;
+               return $object;
        }
-       
+
        /**
-        * Set the uid for the argument.
+        * Returns the value of this argument
         *
-        * @param string $uid The uid for the argument.
-        * @return void
+        * @return object The value of this argument - if none was set, NULL is returned
+        * @api
         */
-       public function setUid($uid) {
-               $this->uid = $uid;
+       public function getValue() {
+               if ($this->value === NULL) {
+                       return $this->defaultValue;
+               } else {
+                       return $this->value;
+               }
        }
 
        /**
-        * Get the uid of the argument, if it has one.
+        * Checks if this argument has a value set.
         *
-        * @return string Uid of the argument. If none set, returns NULL.
+        * @return boolean TRUE if a value was set, otherwise FALSE
         */
-       public function getUid() {
-               return $this->uid;
+       public function isValue() {
+               return $this->value !== NULL;
        }
 
        /**
         * Returns a string representation of this argument's value
         *
         * @return string
+        * @api
         */
        public function __toString() {
                return (string)$this->value;