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