[+TASK] Extbase (Tests): Fixed Extbase unit tests
[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 * @api
36 */
37 class Tx_Extbase_MVC_Controller_Argument {
38
39 /**
40 * @var Tx_Extbase_Object_ObjectManagerInterface
41 */
42 protected $objectManager;
43
44 /**
45 * @var Tx_Extbase_Persistence_QueryFactory
46 */
47 protected $queryFactory;
48
49 /**
50 * @var Tx_Extbase_Property_Mapper
51 */
52 protected $propertyMapper;
53
54 /**
55 * @var Tx_Extbase_Reflection_Service
56 */
57 protected $reflectionService;
58
59 /**
60 * Name of this argument
61 * @var string
62 */
63 protected $name = '';
64
65 /**
66 * Short name of this argument
67 * @var string
68 */
69 protected $shortName = NULL;
70
71 /**
72 * Data type of this argument's value
73 * @var string
74 */
75 protected $dataType = NULL;
76
77 /**
78 * If the data type is an object, the class schema of the data type class is resolved
79 * @var Tx_Extbase_Reflection_ClassSchema
80 */
81 protected $dataTypeClassSchema;
82
83 /**
84 * TRUE if this argument is required
85 * @var boolean
86 */
87 protected $isRequired = FALSE;
88
89 /**
90 * Actual value of this argument
91 * @var object
92 */
93 protected $value = NULL;
94
95 /**
96 * Default value. Used if argument is optional.
97 * @var mixed
98 */
99 protected $defaultValue = NULL;
100
101 /**
102 * A custom validator, used supplementary to the base validation
103 * @var Tx_Extbase_Validation_Validator_ValidatorInterface
104 */
105 protected $validator = NULL;
106
107 /**
108 * Uid for the argument, if it has one
109 * @var string
110 */
111 protected $uid = NULL;
112
113 const ORIGIN_CLIENT = 0;
114 const ORIGIN_PERSISTENCE = 1;
115 const ORIGIN_PERSISTENCE_AND_MODIFIED = 2;
116 const ORIGIN_NEWLY_CREATED = 3;
117
118 /**
119 * The origin of the argument value. This is only meaningful after argument mapping.
120 *
121 * One of the ORIGIN_* constants above
122 * @var integer
123 */
124 protected $origin = 0;
125
126 /**
127 * Constructs this controller argument
128 *
129 * @param string $name Name of this argument
130 * @param string $dataType The data type of this argument
131 * @throws InvalidArgumentException if $name is not a string or empty
132 * @api
133 */
134 public function __construct($name, $dataType) {
135 if (!is_string($name)) throw new InvalidArgumentException('$name must be of type string, ' . gettype($name) . ' given.', 1187951688);
136 if (strlen($name) === 0) throw new InvalidArgumentException('$name must be a non-empty string, ' . strlen($name) . ' characters given.', 1232551853);
137 $this->name = $name;
138 $this->dataType = $dataType;
139 }
140
141 /**
142 * Injects the object manager
143 *
144 * @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
145 * @return void
146 */
147 public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
148 $this->objectManager = $objectManager;
149 }
150
151 /**
152 * @param Tx_Extbase_Property_Mapper $propertyMapper
153 * @return void
154 */
155 public function injectPropertyMapper(Tx_Extbase_Property_Mapper $propertyMapper) {
156 $this->propertyMapper = $propertyMapper;
157 }
158
159 /**
160 * @param Tx_Extbase_Reflection_Service $reflectionService
161 * @return void
162 */
163 public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
164 $this->reflectionService = $reflectionService;
165 $this->dataTypeClassSchema = (strstr($this->dataType, '_') !== FALSE) ? $this->reflectionService->getClassSchema($this->dataType) : NULL;
166 }
167
168 /**
169 * Injects the Persistence Manager
170 *
171 * @param Tx_Extbase_Persistence_ManagerInterface
172 * @return void
173 */
174 public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface $persistenceManager) {
175 $this->persistenceManager = $persistenceManager;
176 }
177
178 /**
179 * Injects a QueryFactory instance
180 *
181 * @param Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory
182 * @return void
183 */
184 public function injectQueryFactory(Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory) {
185 $this->queryFactory = $queryFactory;
186 }
187
188 /**
189 * Returns the name of this argument
190 *
191 * @return string This argument's name
192 * @api
193 */
194 public function getName() {
195 return $this->name;
196 }
197
198 /**
199 * Sets the short name of this argument.
200 *
201 * @param string $shortName A "short name" - a single character
202 * @return Tx_Extbase_MVC_Controller_Argument $this
203 * @throws InvalidArgumentException if $shortName is not a character
204 * @api
205 */
206 public function setShortName($shortName) {
207 if ($shortName !== NULL && (!is_string($shortName) || strlen($shortName) !== 1)) throw new InvalidArgumentException('$shortName must be a single character or NULL', 1195824959);
208 $this->shortName = $shortName;
209 return $this;
210 }
211
212 /**
213 * Returns the short name of this argument
214 *
215 * @return string This argument's short name
216 * @api
217 */
218 public function getShortName() {
219 return $this->shortName;
220 }
221
222 /**
223 * Sets the data type of this argument's value
224 *
225 * @param string $dataType The data type. Can be either a built-in type such as "Text" or "Integer" or a fully qualified object name
226 * @return Tx_Extbase_MVC_Controller_Argument $this
227 * @api
228 */
229 public function setDataType($dataType) {
230 $this->dataType = $dataType;
231 $this->dataTypeClassSchema = $this->reflectionService->getClassSchema($dataType);
232 return $this;
233 }
234
235 /**
236 * Returns the data type of this argument's value
237 *
238 * @return string The data type
239 * @api
240 */
241 public function getDataType() {
242 return $this->dataType;
243 }
244
245 /**
246 * Marks this argument to be required
247 *
248 * @param boolean $required TRUE if this argument should be required
249 * @return Tx_Extbase_MVC_Controller_Argument $this
250 * @api
251 */
252 public function setRequired($required) {
253 $this->isRequired = (boolean)$required;
254 return $this;
255 }
256
257 /**
258 * Returns TRUE if this argument is required
259 *
260 * @return boolean TRUE if this argument is required
261 * @api
262 */
263 public function isRequired() {
264 return $this->isRequired;
265 }
266
267 /**
268 * Sets the default value of the argument
269 *
270 * @param mixed $defaultValue Default value
271 * @return void
272 * @api
273 */
274 public function setDefaultValue($defaultValue) {
275 $this->defaultValue = $defaultValue;
276 }
277
278 /**
279 * Returns the default value of this argument
280 *
281 * @return mixed The default value
282 * @api
283 */
284 public function getDefaultValue() {
285 return $this->defaultValue;
286 }
287
288 /**
289 * Sets a custom validator which is used supplementary to the base validation
290 *
291 * @param Tx_Extbase_Validation_Validator_ValidatorInterface $validator The actual validator object
292 * @return Tx_Extbase_MVC_Controller_Argument Returns $this (used for fluent interface)
293 * @api
294 */
295 public function setValidator(Tx_Extbase_Validation_Validator_ValidatorInterface $validator) {
296 $this->validator = $validator;
297 return $this;
298 }
299
300 /**
301 * Create and set a validator chain
302 *
303 * @param array Object names of the validators
304 * @return Tx_Extbase_MVC_Controller_Argument Returns $this (used for fluent interface)
305 * @api
306 */
307 public function setNewValidatorConjunction(array $objectNames) {
308 if ($this->validator === NULL) {
309 $this->validator = $this->objectManager->create('Tx_Extbase_Validation_Validator_ConjunctionValidator');
310 }
311 foreach ($objectNames as $objectName) {
312 if (!class_exists($objectName)) {
313 $objectName = 'Tx_Extbase_Validation_Validator_' . $objectName;
314 }
315 $this->validator->addValidator($this->objectManager->get($objectName));
316 }
317 return $this;
318 }
319
320 /**
321 * Returns the set validator
322 *
323 * @return Tx_Extbase_Validation_Validator_ValidatorInterface The set validator, NULL if none was set
324 * @api
325 */
326 public function getValidator() {
327 return $this->validator;
328 }
329
330 /**
331 * Get the origin of the argument value. This is only meaningful after argument mapping.
332 *
333 * @return integer one of the ORIGIN_* constants
334 * @author Sebastian Kurf├╝rst <sebastian@typo3.org>
335 */
336 public function getOrigin() {
337 return $this->origin;
338 }
339
340 /**
341 * Sets the value of this argument.
342 *
343 * @param mixed $value: The value of this argument
344 * @return Tx_Extbase_MVC_Controller_Argument $this
345 * @throws Tx_Extbase_MVC_Exception_InvalidArgumentValue if the argument is not a valid object of type $dataType
346 */
347 public function setValue($value) {
348 $this->value = $this->transformValue($value);
349
350 return $this;
351 }
352
353 /**
354 * Checks if the value is a UUID or an array but should be an object, i.e.
355 * the argument's data type class schema is set. If that is the case, this
356 * method tries to look up the corresponding object instead.
357 *
358 * Additionally, it maps arrays to objects in case it is a normal object.
359 *
360 * @param mixed $value The value of an argument
361 * @return mixed
362 */
363 protected function transformValue($value) {
364 if ($value === NULL) {
365 return NULL;
366 }
367 if (!class_exists($this->dataType)) {
368 return $value;
369 }
370 $transformedValue = NULL;
371 if ($this->dataTypeClassSchema !== NULL) {
372 // The target object is an Entity or ValueObject.
373 if (is_numeric($value)) {
374 $this->origin = self::ORIGIN_PERSISTENCE;
375 $transformedValue = $this->findObjectByUid($value);
376 } elseif (is_array($value)) {
377 $this->origin = self::ORIGIN_PERSISTENCE_AND_MODIFIED;
378 $transformedValue = $this->propertyMapper->map(array_keys($value), $value, $this->dataType);
379 }
380 } else {
381 if (!is_array($value)) {
382 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);
383 }
384 $this->origin = self::ORIGIN_NEWLY_CREATED;
385 $transformedValue = $this->propertyMapper->map(array_keys($value), $value, $this->dataType);
386 }
387
388 if (!($transformedValue instanceof $this->dataType) && !($transformedValue === NULL && !$this->isRequired())) {
389 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);
390 }
391 return $transformedValue;
392 }
393
394 /**
395 * Finds an object from the repository by searching for its technical UID.
396 *
397 * @param int $uid The object's uid
398 * @return object Either the object matching the uid or, if none or more than one object was found, NULL
399 */
400 protected function findObjectByUid($uid) {
401 $query = $this->queryFactory->create($this->dataType);
402 $query->getQuerySettings()->setRespectSysLanguage(FALSE);
403 $query->getQuerySettings()->setRespectStoragePage(FALSE);
404 return $query->matching(
405 $query->equals('uid', $uid))
406 ->execute()
407 ->getFirst();
408 }
409
410 /**
411 * Returns the value of this argument
412 *
413 * @return object The value of this argument - if none was set, NULL is returned
414 * @api
415 */
416 public function getValue() {
417 if ($this->value === NULL) {
418 return $this->defaultValue;
419 } else {
420 return $this->value;
421 }
422 }
423
424 /**
425 * Checks if this argument has a value set.
426 *
427 * @return boolean TRUE if a value was set, otherwise FALSE
428 */
429 public function isValue() {
430 return $this->value !== NULL;
431 }
432
433 /**
434 * Returns a string representation of this argument's value
435 *
436 * @return string
437 * @api
438 */
439 public function __toString() {
440 return (string)$this->value;
441 }
442 }
443 ?>