be49f8eb357c6d09be7d0fedfcd5149aa689069c
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Controller / Argument.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Mvc\Controller;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2013 Extbase Team (http://forge.typo3.org/projects/typo3v4-mvc)
8 * Extbase is a backport of TYPO3 Flow. All credits go to the TYPO3 Flow team.
9 * All rights reserved
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 * A copy is found in the textfile GPL.txt and important notices to the license
20 * from the author is found in LICENSE.txt distributed with these scripts.
21 *
22 *
23 * This script is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /**
31 * A controller argument
32 *
33 * @api
34 */
35 class Argument {
36
37 /**
38 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
39 */
40 protected $objectManager;
41
42 /**
43 * @var \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactory
44 */
45 protected $queryFactory;
46
47 /**
48 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
49 */
50 protected $configurationManager;
51
52 /**
53 * This is the old property mapper, which has been completely rewritten for 1.4.
54 *
55 * @var \TYPO3\CMS\Extbase\Property\Mapper
56 */
57 protected $deprecatedPropertyMapper;
58
59 /**
60 * The new, completely rewritten property mapper since Extbase 1.4.
61 *
62 * @var \TYPO3\CMS\Extbase\Property\PropertyMapper
63 */
64 protected $propertyMapper;
65
66 /**
67 * @var \TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfiguration
68 */
69 protected $propertyMappingConfiguration;
70
71 /**
72 * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
73 */
74 protected $reflectionService;
75
76 /**
77 * @var \TYPO3\CMS\Extbase\Service\TypeHandlingService
78 */
79 protected $typeHandlingService;
80
81 /**
82 * Name of this argument
83 *
84 * @var string
85 */
86 protected $name = '';
87
88 /**
89 * Short name of this argument
90 *
91 * @var string
92 */
93 protected $shortName = NULL;
94
95 /**
96 * Data type of this argument's value
97 *
98 * @var string
99 */
100 protected $dataType = NULL;
101
102 /**
103 * If the data type is an object, the class schema of the data type class is resolved
104 *
105 * @var \TYPO3\CMS\Extbase\Reflection\ClassSchema
106 */
107 protected $dataTypeClassSchema;
108
109 /**
110 * TRUE if this argument is required
111 *
112 * @var boolean
113 */
114 protected $isRequired = FALSE;
115
116 /**
117 * Actual value of this argument
118 *
119 * @var object
120 */
121 protected $value = NULL;
122
123 /**
124 * Default value. Used if argument is optional.
125 *
126 * @var mixed
127 */
128 protected $defaultValue = NULL;
129
130 /**
131 * A custom validator, used supplementary to the base validation
132 *
133 * @var \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface
134 */
135 protected $validator = NULL;
136
137 /**
138 * The validation results. This can be asked if the argument has errors.
139 *
140 * @var \TYPO3\CMS\Extbase\Error\Result
141 */
142 protected $validationResults = NULL;
143
144 /**
145 * Uid for the argument, if it has one
146 *
147 * @var string
148 */
149 protected $uid = NULL;
150
151 const ORIGIN_CLIENT = 0;
152 const ORIGIN_PERSISTENCE = 1;
153 const ORIGIN_PERSISTENCE_AND_MODIFIED = 2;
154 const ORIGIN_NEWLY_CREATED = 3;
155
156 /**
157 * The origin of the argument value. This is only meaningful after argument mapping.
158 *
159 * One of the ORIGIN_* constants above
160 *
161 * @var integer
162 */
163 protected $origin = 0;
164
165 /**
166 * @var \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface
167 */
168 protected $persistenceManager;
169
170 /**
171 * Constructs this controller argument
172 *
173 * @param string $name Name of this argument
174 * @param string $dataType The data type of this argument
175 * @throws \InvalidArgumentException if $name is not a string or empty
176 * @api
177 */
178 public function __construct($name, $dataType) {
179 if (!is_string($name)) {
180 throw new \InvalidArgumentException('$name must be of type string, ' . gettype($name) . ' given.', 1187951688);
181 }
182 if (strlen($name) === 0) {
183 throw new \InvalidArgumentException('$name must be a non-empty string, ' . strlen($name) . ' characters given.', 1232551853);
184 }
185 $this->name = $name;
186 $this->dataType = $dataType;
187 }
188
189 /**
190 * Injects the object manager
191 *
192 * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
193 * @return void
194 */
195 public function injectObjectManager(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager) {
196 $this->objectManager = $objectManager;
197 }
198
199 /**
200 * @param \TYPO3\CMS\Extbase\Property\Mapper $deprecatedPropertyMapper
201 * @return void
202 */
203 public function injectDeprecatedPropertyMapper(\TYPO3\CMS\Extbase\Property\Mapper $deprecatedPropertyMapper) {
204 $this->deprecatedPropertyMapper = $deprecatedPropertyMapper;
205 }
206
207 /**
208 * @param \TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper
209 * @return void
210 */
211 public function injectPropertyMapper(\TYPO3\CMS\Extbase\Property\PropertyMapper $propertyMapper) {
212 $this->propertyMapper = $propertyMapper;
213 }
214
215 /**
216 * @param \TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService
217 * @return void
218 */
219 public function injectReflectionService(\TYPO3\CMS\Extbase\Reflection\ReflectionService $reflectionService) {
220 $this->reflectionService = $reflectionService;
221 // Check for classnames (which have at least one underscore or backslash)
222 $this->dataTypeClassSchema = strpbrk($this->dataType, '_\\') !== FALSE ? $this->reflectionService->getClassSchema($this->dataType) : NULL;
223 }
224
225 /**
226 * Injects the Persistence Manager
227 *
228 * @param \TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager
229 * @return void
230 */
231 public function injectPersistenceManager(\TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface $persistenceManager) {
232 $this->persistenceManager = $persistenceManager;
233 }
234
235 /**
236 * Injects a QueryFactory instance
237 *
238 * @param \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory
239 * @return void
240 */
241 public function injectQueryFactory(\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface $queryFactory) {
242 $this->queryFactory = $queryFactory;
243 }
244
245 /**
246 * @param \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager
247 * @return void
248 */
249 public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager) {
250 $this->configurationManager = $configurationManager;
251 }
252
253 /**
254 * @param \TYPO3\CMS\Extbase\Service\TypeHandlingService $typeHandlingService
255 * @return void
256 */
257 public function injectTypeHandlingService(\TYPO3\CMS\Extbase\Service\TypeHandlingService $typeHandlingService) {
258 $this->typeHandlingService = $typeHandlingService;
259 $this->dataType = $this->typeHandlingService->normalizeType($this->dataType);
260 }
261
262 /**
263 * @param \TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfiguration $mvcPropertyMappingConfiguration
264 * @return void
265 */
266 public function injectPropertyMappingConfiguration(\TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfiguration $mvcPropertyMappingConfiguration) {
267 $this->propertyMappingConfiguration = $mvcPropertyMappingConfiguration;
268 }
269
270 /**
271 * Returns the name of this argument
272 *
273 * @return string This argument's name
274 * @api
275 */
276 public function getName() {
277 return $this->name;
278 }
279
280 /**
281 * Sets the short name of this argument.
282 *
283 * @param string $shortName A "short name" - a single character
284 * @throws \InvalidArgumentException if $shortName is not a character
285 * @return \TYPO3\CMS\Extbase\Mvc\Controller\Argument $this
286 * @api
287 */
288 public function setShortName($shortName) {
289 if ($shortName !== NULL && (!is_string($shortName) || strlen($shortName) !== 1)) {
290 throw new \InvalidArgumentException('$shortName must be a single character or NULL', 1195824959);
291 }
292 $this->shortName = $shortName;
293 return $this;
294 }
295
296 /**
297 * Returns the short name of this argument
298 *
299 * @return string This argument's short name
300 * @api
301 */
302 public function getShortName() {
303 return $this->shortName;
304 }
305
306 /**
307 * Sets the data type of this argument's value
308 *
309 * @param string $dataType The data type. Can be either a built-in type such as "Text" or "Integer" or a fully qualified object name
310 * @return \TYPO3\CMS\Extbase\Mvc\Controller\Argument $this
311 * @api
312 */
313 public function setDataType($dataType) {
314 $this->dataType = $dataType;
315 $this->dataTypeClassSchema = $this->reflectionService->getClassSchema($dataType);
316 return $this;
317 }
318
319 /**
320 * Returns the data type of this argument's value
321 *
322 * @return string The data type
323 * @api
324 */
325 public function getDataType() {
326 return $this->dataType;
327 }
328
329 /**
330 * Marks this argument to be required
331 *
332 * @param boolean $required TRUE if this argument should be required
333 * @return \TYPO3\CMS\Extbase\Mvc\Controller\Argument $this
334 * @api
335 */
336 public function setRequired($required) {
337 $this->isRequired = (boolean) $required;
338 return $this;
339 }
340
341 /**
342 * Returns TRUE if this argument is required
343 *
344 * @return boolean TRUE if this argument is required
345 * @api
346 */
347 public function isRequired() {
348 return $this->isRequired;
349 }
350
351 /**
352 * Sets the default value of the argument
353 *
354 * @param mixed $defaultValue Default value
355 * @return \TYPO3\CMS\Extbase\Mvc\Controller\Argument $this
356 * @api
357 */
358 public function setDefaultValue($defaultValue) {
359 $this->defaultValue = $defaultValue;
360 return $this;
361 }
362
363 /**
364 * Returns the default value of this argument
365 *
366 * @return mixed The default value
367 * @api
368 */
369 public function getDefaultValue() {
370 return $this->defaultValue;
371 }
372
373 /**
374 * Sets a custom validator which is used supplementary to the base validation
375 *
376 * @param \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface $validator The actual validator object
377 * @return \TYPO3\CMS\Extbase\Mvc\Controller\Argument Returns $this (used for fluent interface)
378 * @api
379 */
380 public function setValidator(\TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface $validator) {
381 $this->validator = $validator;
382 return $this;
383 }
384
385 /**
386 * Create and set a validator chain
387 *
388 * @param array $objectNames Object names of the validators
389 * @return \TYPO3\CMS\Extbase\Mvc\Controller\Argument Returns $this (used for fluent interface)
390 * @api
391 * @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
392 */
393 public function setNewValidatorConjunction(array $objectNames) {
394 if ($this->validator === NULL) {
395 $this->validator = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Validation\\Validator\\ConjunctionValidator');
396 }
397 foreach ($objectNames as $objectName) {
398 if (!class_exists($objectName)) {
399 $objectName = 'Tx_Extbase_Validation_Validator_' . $objectName;
400 }
401 $this->validator->addValidator($this->objectManager->get($objectName));
402 }
403 return $this;
404 }
405
406 /**
407 * Returns the set validator
408 *
409 * @return \TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface The set validator, NULL if none was set
410 * @api
411 */
412 public function getValidator() {
413 return $this->validator;
414 }
415
416 /**
417 * Get the origin of the argument value. This is only meaningful after argument mapping.
418 *
419 * @return integer one of the ORIGIN_* constants
420 * @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
421 */
422 public function getOrigin() {
423 return $this->origin;
424 }
425
426 /**
427 * Sets the value of this argument.
428 *
429 * @param mixed $rawValue The value of this argument
430 * @return \TYPO3\CMS\Extbase\Mvc\Controller\Argument
431 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException if the argument is not a valid object of type $dataType
432 */
433 public function setValue($rawValue) {
434 if ($this->configurationManager->isFeatureEnabled('rewrittenPropertyMapper')) {
435 if ($rawValue === NULL) {
436 $this->value = NULL;
437 return $this;
438 }
439 if (is_object($rawValue) && $rawValue instanceof $this->dataType) {
440 $this->value = $rawValue;
441 return $this;
442 }
443 $this->value = $this->propertyMapper->convert($rawValue, $this->dataType, $this->propertyMappingConfiguration);
444 $this->validationResults = $this->propertyMapper->getMessages();
445 if ($this->validator !== NULL) {
446 // TODO: Validation API has also changed!!!
447 $validationMessages = $this->validator->validate($this->value);
448 $this->validationResults->merge($validationMessages);
449 }
450 return $this;
451 } else {
452 if ($rawValue === NULL || is_object($rawValue) && $rawValue instanceof $this->dataType) {
453 $this->value = $rawValue;
454 } else {
455 $this->value = $this->transformValue($rawValue);
456 }
457 return $this;
458 }
459 }
460
461 /**
462 * Checks if the value is a UUID or an array but should be an object, i.e.
463 * the argument's data type class schema is set. If that is the case, this
464 * method tries to look up the corresponding object instead.
465 *
466 * Additionally, it maps arrays to objects in case it is a normal object.
467 *
468 * @param mixed $value The value of an argument
469 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException
470 * @return mixed
471 * @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
472 */
473 protected function transformValue($value) {
474 if (!class_exists($this->dataType)) {
475 return $value;
476 }
477 $transformedValue = NULL;
478 if ($this->dataTypeClassSchema !== NULL) {
479 // The target object is an Entity or ValueObject.
480 if (is_numeric($value)) {
481 $this->origin = self::ORIGIN_PERSISTENCE;
482 $transformedValue = $this->findObjectByUid($value);
483 } elseif (is_array($value)) {
484 $this->origin = self::ORIGIN_PERSISTENCE_AND_MODIFIED;
485 $transformedValue = $this->deprecatedPropertyMapper->map(array_keys($value), $value, $this->dataType);
486 }
487 } else {
488 if (!is_array($value)) {
489 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException('The value was a simple type, so we could not map it to an object. Maybe the @entity or @valueobject annotations are missing?', 1251730701);
490 }
491 $this->origin = self::ORIGIN_NEWLY_CREATED;
492 $transformedValue = $this->deprecatedPropertyMapper->map(array_keys($value), $value, $this->dataType);
493 }
494 if (!$transformedValue instanceof $this->dataType && ($transformedValue !== NULL || $this->isRequired())) {
495 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException('The value must be of type "' . $this->dataType . '", but was of type "' . (is_object($transformedValue) ? get_class($transformedValue) : gettype($transformedValue)) . '".' . ($this->deprecatedPropertyMapper->getMappingResults()->hasErrors() ? '<p>' . implode('<br />', $this->deprecatedPropertyMapper->getMappingResults()->getErrors()) . '</p>' : ''), 1251730701);
496 }
497 return $transformedValue;
498 }
499
500 /**
501 * Finds an object from the repository by searching for its technical UID.
502 *
503 * @param integer $uid The object's uid
504 * @return object Either the object matching the uid or, if none or more than one object was found, NULL
505 */
506 protected function findObjectByUid($uid) {
507 $query = $this->queryFactory->create($this->dataType);
508 $query->getQuerySettings()->setRespectSysLanguage(FALSE);
509 $query->getQuerySettings()->setRespectStoragePage(FALSE);
510 return $query->matching($query->equals('uid', $uid))->execute()->getFirst();
511 }
512
513 /**
514 * Returns the value of this argument
515 *
516 * @return object The value of this argument - if none was set, NULL is returned
517 * @api
518 */
519 public function getValue() {
520 if ($this->value === NULL) {
521 return $this->defaultValue;
522 } else {
523 return $this->value;
524 }
525 }
526
527 /**
528 * Checks if this argument has a value set.
529 *
530 * @return boolean TRUE if a value was set, otherwise FALSE
531 * @deprecated since Extbase 1.4.0, will be removed two versions after Extbase 6.1
532 */
533 public function isValue() {
534 return $this->value !== NULL;
535 }
536
537 /**
538 * Return the Property Mapping Configuration used for this argument; can be used by the initialize*action to modify the Property Mapping.
539 *
540 * @return \TYPO3\CMS\Extbase\Mvc\Controller\MvcPropertyMappingConfiguration
541 * @api
542 */
543 public function getPropertyMappingConfiguration() {
544 return $this->propertyMappingConfiguration;
545 }
546
547 /**
548 * @return boolean TRUE if the argument is valid, FALSE otherwise
549 * @api
550 */
551 public function isValid() {
552 return !$this->validationResults->hasErrors();
553 }
554
555 /**
556 * @return array<\TYPO3\CMS\Extbase\Error\Result> Validation errors which have occured.
557 * @api
558 */
559 public function getValidationResults() {
560 return $this->validationResults;
561 }
562
563 /**
564 * Returns a string representation of this argument's value
565 *
566 * @return string
567 * @api
568 */
569 public function __toString() {
570 return (string) $this->value;
571 }
572 }
573
574 ?>