[-TASK] Exbase (Persistence): Removed option deleteChildObjects.
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / MVC / Controller / Argument.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
6 * All rights reserved
7 *
8 * This class is a backport of the corresponding class of FLOW3.
9 * All credits go to the v5 team.
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 /**
29 * A controller argument
30 *
31 * @package Extbase
32 * @subpackage MVC\Controller
33 * @version $ID:$
34 * @scope prototype
35 */
36 class Tx_Extbase_MVC_Controller_Argument {
37
38 /**
39 * @var Tx_Extbase_Persistence_QueryFactory
40 */
41 protected $queryFactory;
42
43 /**
44 * @var Tx_Extbase_Property_Mapper
45 */
46 protected $propertyMapper;
47
48 /**
49 * @var Tx_Extbase_Reflection_Service
50 */
51 protected $reflectionService;
52
53 /**
54 * Name of this argument
55 * @var string
56 */
57 protected $name = '';
58
59 /**
60 * Short name of this argument
61 * @var string
62 */
63 protected $shortName = NULL;
64
65 /**
66 * Data type of this argument's value
67 * @var string
68 */
69 protected $dataType = NULL;
70
71 /**
72 * If the data type is an object, the class schema of the data type class is resolved
73 * @var Tx_Extbase_Reflection_ClassSchema
74 */
75 protected $dataTypeClassSchema;
76
77 /**
78 * TRUE if this argument is required
79 * @var boolean
80 */
81 protected $isRequired = FALSE;
82
83 /**
84 * Actual value of this argument
85 * @var object
86 */
87 protected $value = NULL;
88
89 /**
90 * Default value. Used if argument is optional.
91 * @var mixed
92 */
93 protected $defaultValue = NULL;
94
95 /**
96 * A custom validator, used supplementary to the base validation
97 * @var Tx_Extbase_Validation_Validator_ValidatorInterface
98 */
99 protected $validator = NULL;
100
101 /**
102 * Uid for the argument, if it has one
103 * @var string
104 */
105 protected $uid = NULL;
106
107 const ORIGIN_CLIENT = 0;
108 const ORIGIN_PERSISTENCE = 1;
109 const ORIGIN_PERSISTENCE_AND_MODIFIED = 2;
110 const ORIGIN_NEWLY_CREATED = 3;
111
112 /**
113 * The origin of the argument value. This is only meaningful after argument mapping.
114 *
115 * One of the ORIGIN_* constants above
116 * @var integer
117 */
118 protected $origin = 0;
119
120 /**
121 * Constructs this controller argument
122 *
123 * @param string $name Name of this argument
124 * @param string $dataType The data type of this argument
125 * @throws InvalidArgumentException if $name is not a string or empty
126 * @api
127 */
128 public function __construct($name, $dataType) {
129 if (!is_string($name)) throw new InvalidArgumentException('$name must be of type string, ' . gettype($name) . ' given.', 1187951688);
130 if (strlen($name) === 0) throw new InvalidArgumentException('$name must be a non-empty string, ' . strlen($name) . ' characters given.', 1232551853);
131 $this->name = $name;
132 $this->dataType = $dataType;
133 }
134
135 /**
136 * Initializes this object
137 *
138 * @return void
139 */
140 public function initializeObject() {
141 $this->reflectionService = t3lib_div::makeInstance('Tx_Extbase_Reflection_Service');
142 $this->propertyMapper = t3lib_div::makeInstance('Tx_Extbase_Property_Mapper');
143 $this->propertyMapper->injectReflectionService($this->reflectionService);
144 $this->dataTypeClassSchema = $this->reflectionService->getClassSchema($this->dataType);
145 }
146
147 /**
148 * Injects the Persistence Manager
149 *
150 * @param Tx_Extbase_Persistence_ManagerInterface
151 * @return void
152 */
153 public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface $persistenceManager) {
154 $this->persistenceManager = $persistenceManager;
155 }
156
157 /**
158 * Injects a QueryFactory instance
159 *
160 * @param Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory
161 * @return void
162 */
163 public function injectQueryFactory(Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory) {
164 $this->queryFactory = $queryFactory;
165 }
166
167 /**
168 * Returns the name of this argument
169 *
170 * @return string This argument's name
171 * @api
172 */
173 public function getName() {
174 return $this->name;
175 }
176
177 /**
178 * Sets the short name of this argument.
179 *
180 * @param string $shortName A "short name" - a single character
181 * @return Tx_Extbase_MVC_Controller_Argument $this
182 * @throws InvalidArgumentException if $shortName is not a character
183 * @api
184 */
185 public function setShortName($shortName) {
186 if ($shortName !== NULL && (!is_string($shortName) || strlen($shortName) !== 1)) throw new InvalidArgumentException('$shortName must be a single character or NULL', 1195824959);
187 $this->shortName = $shortName;
188 return $this;
189 }
190
191 /**
192 * Returns the short name of this argument
193 *
194 * @return string This argument's short name
195 * @api
196 */
197 public function getShortName() {
198 return $this->shortName;
199 }
200
201 /**
202 * Sets the data type of this argument's value
203 *
204 * @param string $dataType The data type. Can be either a built-in type such as "Text" or "Integer" or a fully qualified object name
205 * @return Tx_Extbase_MVC_Controller_Argument $this
206 * @api
207 */
208 public function setDataType($dataType) {
209 $this->dataType = $dataType;
210 $this->dataTypeClassSchema = $this->reflectionService->getClassSchema($dataType);
211 return $this;
212 }
213
214 /**
215 * Returns the data type of this argument's value
216 *
217 * @return string The data type
218 * @api
219 */
220 public function getDataType() {
221 return $this->dataType;
222 }
223
224 /**
225 * Marks this argument to be required
226 *
227 * @param boolean $required TRUE if this argument should be required
228 * @return Tx_Extbase_MVC_Controller_Argument $this
229 * @api
230 */
231 public function setRequired($required) {
232 $this->isRequired = (boolean)$required;
233 return $this;
234 }
235
236 /**
237 * Returns TRUE if this argument is required
238 *
239 * @return boolean TRUE if this argument is required
240 * @api
241 */
242 public function isRequired() {
243 return $this->isRequired;
244 }
245
246 /**
247 * Sets the default value of the argument
248 *
249 * @param mixed $defaultValue Default value
250 * @return void
251 * @api
252 */
253 public function setDefaultValue($defaultValue) {
254 $this->defaultValue = $defaultValue;
255 }
256
257 /**
258 * Returns the default value of this argument
259 *
260 * @return mixed The default value
261 * @api
262 */
263 public function getDefaultValue() {
264 return $this->defaultValue;
265 }
266
267 /**
268 * Sets a custom validator which is used supplementary to the base validation
269 *
270 * @param Tx_Extbase_Validation_Validator_ValidatorInterface $validator The actual validator object
271 * @return Tx_Extbase_MVC_Controller_Argument Returns $this (used for fluent interface)
272 * @api
273 */
274 public function setValidator(Tx_Extbase_Validation_Validator_ValidatorInterface $validator) {
275 $this->validator = $validator;
276 return $this;
277 }
278
279 /**
280 * Create and set a validator chain
281 *
282 * @param array Object names of the validators
283 * @return Tx_Extbase_MVC_Controller_Argument Returns $this (used for fluent interface)
284 * @api
285 */
286 public function setNewValidatorConjunction(array $objectNames) {
287 if ($this->validator === NULL) {
288 $this->validator = t3lib_div::makeInstance('Tx_Extbase_Validation_Validator_ConjunctionValidator');
289 }
290 foreach ($objectNames as $objectName) {
291 if (!class_exists($objectName)) $objectName = 'Tx_Extbase_Validation_Validator_' . $objectName;
292 $this->validator->addValidator(t3lib_div::makeInstance($objectName));
293 }
294 return $this;
295 }
296
297 /**
298 * Returns the set validator
299 *
300 * @return Tx_Extbase_Validation_Validator_ValidatorInterface The set validator, NULL if none was set
301 * @api
302 */
303 public function getValidator() {
304 return $this->validator;
305 }
306
307 /**
308 * Get the origin of the argument value. This is only meaningful after argument mapping.
309 *
310 * @return integer one of the ORIGIN_* constants
311 * @author Sebastian Kurf├╝rst <sebastian@typo3.org>
312 */
313 public function getOrigin() {
314 return $this->origin;
315 }
316
317 /**
318 * Sets the value of this argument.
319 *
320 * @param mixed $value: The value of this argument
321 * @return Tx_Extbase_MVC_Controller_Argument $this
322 * @throws Tx_Extbase_MVC_Exception_InvalidArgumentValue if the argument is not a valid object of type $dataType
323 */
324 public function setValue($value) {
325 $this->value = $this->transformValue($value);
326
327 return $this;
328 }
329
330 /**
331 * Checks if the value is a UUID or an array but should be an object, i.e.
332 * the argument's data type class schema is set. If that is the case, this
333 * method tries to look up the corresponding object instead.
334 *
335 * Additionally, it maps arrays to objects in case it is a normal object.
336 *
337 * @param mixed $value The value of an argument
338 * @return mixed
339 */
340 protected function transformValue($value) {
341 if ($value === NULL) {
342 return NULL;
343 }
344 if (!class_exists($this->dataType)) {
345 return $value;
346 }
347 $transformedValue = NULL;
348 if ($this->dataTypeClassSchema !== NULL) {
349 // The target object is an Entity or ValueObject.
350 if (is_numeric($value)) {
351 $this->origin = self::ORIGIN_PERSISTENCE;
352 $transformedValue = $this->findObjectByUid($value);
353 } elseif (is_array($value)) {
354 $this->origin = self::ORIGIN_PERSISTENCE_AND_MODIFIED;
355 $transformedValue = $this->propertyMapper->map(array_keys($value), $value, $this->dataType);
356 }
357 } else {
358 if (!is_array($value)) {
359 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);
360 }
361 $this->origin = self::ORIGIN_NEWLY_CREATED;
362 $transformedValue = $this->propertyMapper->map(array_keys($value), $value, $this->dataType);
363 }
364
365 if (!($transformedValue instanceof $this->dataType)) {
366 if (is_object($transformedValue)) {
367 throw new Tx_Extbase_MVC_Exception_InvalidArgumentValue('The value must be of type "' . $this->dataType . '", but was of type "' . get_class($transformedValue) . '".', 1251730701);
368 } else {
369 throw new Tx_Extbase_MVC_Exception_InvalidArgumentValue('The value must be of type "' . $this->dataType . '", but was of type "' . gettype($transformedValue) . '".', 1251730702);
370 }
371 }
372 return $transformedValue;
373 }
374
375 /**
376 * Finds an object from the repository by searching for its technical UID.
377 *
378 * @param int $uid The object's uid
379 * @return mixed Either the object matching the uid or, if none or more than one object was found, FALSE
380 */
381 protected function findObjectByUid($uid) {
382 $query = $this->queryFactory->create($this->dataType);
383 $result = $query->matching($query->withUid($uid))->execute();
384 $object = NULL;
385 if (count($result) > 0) {
386 $object = current($result);
387 }
388 return $object;
389 }
390
391 /**
392 * Returns the value of this argument
393 *
394 * @return object The value of this argument - if none was set, NULL is returned
395 * @api
396 */
397 public function getValue() {
398 if ($this->value === NULL) {
399 return $this->defaultValue;
400 } else {
401 return $this->value;
402 }
403 }
404
405 /**
406 * Checks if this argument has a value set.
407 *
408 * @return boolean TRUE if a value was set, otherwise FALSE
409 */
410 public function isValue() {
411 return $this->value !== NULL;
412 }
413
414 /**
415 * Returns a string representation of this argument's value
416 *
417 * @return string
418 * @api
419 */
420 public function __toString() {
421 return (string)$this->value;
422 }
423 }
424 ?>