[!!!][BUGFIX] Skip cache hash for URIs to non-cacheable actions
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Mvc / Web / Routing / UriBuilder.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Mvc\Web\Routing;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Utility\ArrayUtility;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20
21 /**
22 * An URI Builder
23 *
24 * @api
25 */
26 class UriBuilder {
27
28 /**
29 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
30 * @inject
31 */
32 protected $configurationManager;
33
34 /**
35 * @var \TYPO3\CMS\Extbase\Service\ExtensionService
36 * @inject
37 */
38 protected $extensionService;
39
40 /**
41 * An instance of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
42 *
43 * @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
44 */
45 protected $contentObject;
46
47 /**
48 * @var \TYPO3\CMS\Extbase\Mvc\Web\Request
49 */
50 protected $request;
51
52 /**
53 * @var array
54 */
55 protected $arguments = array();
56
57 /**
58 * Arguments which have been used for building the last URI
59 *
60 * @var array
61 */
62 protected $lastArguments = array();
63
64 /**
65 * @var string
66 */
67 protected $section = '';
68
69 /**
70 * @var bool
71 */
72 protected $createAbsoluteUri = FALSE;
73
74 /**
75 * @var string
76 */
77 protected $absoluteUriScheme = NULL;
78
79 /**
80 * @var bool
81 */
82 protected $addQueryString = FALSE;
83
84 /**
85 * @var string
86 */
87 protected $addQueryStringMethod = NULL;
88
89 /**
90 * @var array
91 */
92 protected $argumentsToBeExcludedFromQueryString = array();
93
94 /**
95 * @var bool
96 */
97 protected $linkAccessRestrictedPages = FALSE;
98
99 /**
100 * @var int
101 */
102 protected $targetPageUid = NULL;
103
104 /**
105 * @var int
106 */
107 protected $targetPageType = 0;
108
109 /**
110 * @var bool
111 */
112 protected $noCache = FALSE;
113
114 /**
115 * @var bool
116 */
117 protected $useCacheHash = TRUE;
118
119 /**
120 * @var string
121 */
122 protected $format = '';
123
124 /**
125 * @var string
126 */
127 protected $argumentPrefix = NULL;
128
129 /**
130 * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
131 * @inject
132 */
133 protected $environmentService;
134
135 /**
136 * Life-cycle method that is called by the DI container as soon as this object is completely built
137 *
138 * @return void
139 */
140 public function initializeObject() {
141 $this->contentObject = $this->configurationManager->getContentObject();
142 }
143
144 /**
145 * Sets the current request
146 *
147 * @param \TYPO3\CMS\Extbase\Mvc\Request $request
148 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
149 */
150 public function setRequest(\TYPO3\CMS\Extbase\Mvc\Request $request) {
151 $this->request = $request;
152 return $this;
153 }
154
155 /**
156 * @return \TYPO3\CMS\Extbase\Mvc\Web\Request
157 */
158 public function getRequest() {
159 return $this->request;
160 }
161
162 /**
163 * Additional query parameters.
164 * If you want to "prefix" arguments, you can pass in multidimensional arrays:
165 * array('prefix1' => array('foo' => 'bar')) gets "&prefix1[foo]=bar"
166 *
167 * @param array $arguments
168 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
169 * @api
170 */
171 public function setArguments(array $arguments) {
172 $this->arguments = $arguments;
173 return $this;
174 }
175
176 /**
177 * @return array
178 * @api
179 */
180 public function getArguments() {
181 return $this->arguments;
182 }
183
184 /**
185 * If specified, adds a given HTML anchor to the URI (#...)
186 *
187 * @param string $section
188 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
189 * @api
190 */
191 public function setSection($section) {
192 $this->section = $section;
193 return $this;
194 }
195
196 /**
197 * @return string
198 * @api
199 */
200 public function getSection() {
201 return $this->section;
202 }
203
204 /**
205 * Specifies the format of the target (e.g. "html" or "xml")
206 *
207 * @param string $format
208 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
209 * @api
210 */
211 public function setFormat($format) {
212 $this->format = $format;
213 return $this;
214 }
215
216 /**
217 * @return string
218 * @api
219 */
220 public function getFormat() {
221 return $this->format;
222 }
223
224 /**
225 * If set, the URI is prepended with the current base URI. Defaults to FALSE.
226 *
227 * @param bool $createAbsoluteUri
228 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
229 * @api
230 */
231 public function setCreateAbsoluteUri($createAbsoluteUri) {
232 $this->createAbsoluteUri = $createAbsoluteUri;
233 return $this;
234 }
235
236 /**
237 * @return bool
238 * @api
239 */
240 public function getCreateAbsoluteUri() {
241 return $this->createAbsoluteUri;
242 }
243
244 /**
245 * @return string
246 */
247 public function getAbsoluteUriScheme() {
248 return $this->absoluteUriScheme;
249 }
250
251 /**
252 * Sets the scheme that should be used for absolute URIs in FE mode
253 *
254 * @param string $absoluteUriScheme the scheme to be used for absolute URIs
255 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
256 */
257 public function setAbsoluteUriScheme($absoluteUriScheme) {
258 $this->absoluteUriScheme = $absoluteUriScheme;
259 return $this;
260 }
261
262 /**
263 * If set, the current query parameters will be merged with $this->arguments. Defaults to FALSE.
264 *
265 * @param bool $addQueryString
266 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
267 * @api
268 * @see TSref/typolink.addQueryString
269 */
270 public function setAddQueryString($addQueryString) {
271 $this->addQueryString = (bool)$addQueryString;
272 return $this;
273 }
274
275 /**
276 * @return bool
277 * @api
278 */
279 public function getAddQueryString() {
280 return $this->addQueryString;
281 }
282
283 /**
284 * Sets the method to get the addQueryString parameters. Defaults undefined
285 * which results in using QUERY_STRING.
286 *
287 * @param string $addQueryStringMethod
288 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
289 * @api
290 * @see TSref/typolink.addQueryString.method
291 */
292 public function setAddQueryStringMethod($addQueryStringMethod) {
293 $this->addQueryStringMethod = $addQueryStringMethod;
294 return $this;
295 }
296
297 /**
298 * @return string
299 * @api
300 */
301 public function getAddQueryStringMethod() {
302 return (string)$this->addQueryStringMethod;
303 }
304
305 /**
306 * A list of arguments to be excluded from the query parameters
307 * Only active if addQueryString is set
308 *
309 * @param array $argumentsToBeExcludedFromQueryString
310 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
311 * @api
312 * @see TSref/typolink.addQueryString.exclude
313 * @see setAddQueryString()
314 */
315 public function setArgumentsToBeExcludedFromQueryString(array $argumentsToBeExcludedFromQueryString) {
316 $this->argumentsToBeExcludedFromQueryString = $argumentsToBeExcludedFromQueryString;
317 return $this;
318 }
319
320 /**
321 * @return array
322 * @api
323 */
324 public function getArgumentsToBeExcludedFromQueryString() {
325 return $this->argumentsToBeExcludedFromQueryString;
326 }
327
328 /**
329 * Specifies the prefix to be used for all arguments.
330 *
331 * @param string $argumentPrefix
332 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
333 */
334 public function setArgumentPrefix($argumentPrefix) {
335 $this->argumentPrefix = (string)$argumentPrefix;
336 return $this;
337 }
338
339 /**
340 * @return string
341 */
342 public function getArgumentPrefix() {
343 return $this->argumentPrefix;
344 }
345
346 /**
347 * If set, URIs for pages without access permissions will be created
348 *
349 * @param bool $linkAccessRestrictedPages
350 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
351 * @api
352 */
353 public function setLinkAccessRestrictedPages($linkAccessRestrictedPages) {
354 $this->linkAccessRestrictedPages = (bool)$linkAccessRestrictedPages;
355 return $this;
356 }
357
358 /**
359 * @return bool
360 * @api
361 */
362 public function getLinkAccessRestrictedPages() {
363 return $this->linkAccessRestrictedPages;
364 }
365
366 /**
367 * Uid of the target page
368 *
369 * @param int $targetPageUid
370 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
371 * @api
372 */
373 public function setTargetPageUid($targetPageUid) {
374 $this->targetPageUid = $targetPageUid;
375 return $this;
376 }
377
378 /**
379 * returns $this->targetPageUid.
380 *
381 * @return int
382 * @api
383 */
384 public function getTargetPageUid() {
385 return $this->targetPageUid;
386 }
387
388 /**
389 * Sets the page type of the target URI. Defaults to 0
390 *
391 * @param int $targetPageType
392 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
393 * @api
394 */
395 public function setTargetPageType($targetPageType) {
396 $this->targetPageType = (int)$targetPageType;
397 return $this;
398 }
399
400 /**
401 * @return int
402 */
403 public function getTargetPageType() {
404 return $this->targetPageType;
405 }
406
407 /**
408 * by default FALSE; if TRUE, &no_cache=1 will be appended to the URI
409 * This overrules the useCacheHash setting
410 *
411 * @param bool $noCache
412 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
413 * @api
414 */
415 public function setNoCache($noCache) {
416 $this->noCache = (bool)$noCache;
417 return $this;
418 }
419
420 /**
421 * @return bool
422 * @api
423 */
424 public function getNoCache() {
425 return $this->noCache;
426 }
427
428 /**
429 * by default TRUE; if FALSE, no cHash parameter will be appended to the URI
430 * If noCache is set, this setting will be ignored.
431 *
432 * @param bool $useCacheHash
433 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
434 * @api
435 */
436 public function setUseCacheHash($useCacheHash) {
437 $this->useCacheHash = (bool)$useCacheHash;
438 return $this;
439 }
440
441 /**
442 * @return bool
443 * @api
444 */
445 public function getUseCacheHash() {
446 return $this->useCacheHash;
447 }
448
449 /**
450 * Returns the arguments being used for the last URI being built.
451 * This is only set after build() / uriFor() has been called.
452 *
453 * @return array The last arguments
454 */
455 public function getLastArguments() {
456 return $this->lastArguments;
457 }
458
459 /**
460 * Resets all UriBuilder options to their default value
461 *
462 * @return \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder the current UriBuilder to allow method chaining
463 * @api
464 */
465 public function reset() {
466 $this->arguments = array();
467 $this->section = '';
468 $this->format = '';
469 $this->createAbsoluteUri = FALSE;
470 $this->addQueryString = FALSE;
471 $this->addQueryStringMethod = NULL;
472 $this->argumentsToBeExcludedFromQueryString = array();
473 $this->linkAccessRestrictedPages = FALSE;
474 $this->targetPageUid = NULL;
475 $this->targetPageType = 0;
476 $this->noCache = FALSE;
477 $this->useCacheHash = TRUE;
478 $this->argumentPrefix = NULL;
479 return $this;
480 }
481
482 /**
483 * Creates an URI used for linking to an Extbase action.
484 * Works in Frontend and Backend mode of TYPO3.
485 *
486 * @param string $actionName Name of the action to be called
487 * @param array $controllerArguments Additional query parameters. Will be "namespaced" and merged with $this->arguments.
488 * @param string $controllerName Name of the target controller. If not set, current ControllerName is used.
489 * @param string $extensionName Name of the target extension, without underscores. If not set, current ExtensionName is used.
490 * @param string $pluginName Name of the target plugin. If not set, current PluginName is used.
491 * @return string the rendered URI
492 * @api
493 * @see build()
494 */
495 public function uriFor($actionName = NULL, $controllerArguments = array(), $controllerName = NULL, $extensionName = NULL, $pluginName = NULL) {
496 if ($actionName !== NULL) {
497 $controllerArguments['action'] = $actionName;
498 }
499 if ($controllerName !== NULL) {
500 $controllerArguments['controller'] = $controllerName;
501 } else {
502 $controllerArguments['controller'] = $this->request->getControllerName();
503 }
504 if ($extensionName === NULL) {
505 $extensionName = $this->request->getControllerExtensionName();
506 }
507 if ($pluginName === NULL && $this->environmentService->isEnvironmentInFrontendMode()) {
508 $pluginName = $this->extensionService->getPluginNameByAction($extensionName, $controllerArguments['controller'], $controllerArguments['action']);
509 }
510 if ($pluginName === NULL) {
511 $pluginName = $this->request->getPluginName();
512 }
513
514 $this->disableCacheHashForNonCacheableAction($controllerArguments);
515
516 if ($this->environmentService->isEnvironmentInFrontendMode() && $this->configurationManager->isFeatureEnabled('skipDefaultArguments')) {
517 $controllerArguments = $this->removeDefaultControllerAndAction($controllerArguments, $extensionName, $pluginName);
518 }
519 if ($this->targetPageUid === NULL && $this->environmentService->isEnvironmentInFrontendMode()) {
520 $this->targetPageUid = $this->extensionService->getTargetPidByPlugin($extensionName, $pluginName);
521 }
522 if ($this->format !== '') {
523 $controllerArguments['format'] = $this->format;
524 }
525 if ($this->argumentPrefix !== NULL) {
526 $prefixedControllerArguments = array($this->argumentPrefix => $controllerArguments);
527 } else {
528 $pluginNamespace = $this->extensionService->getPluginNamespace($extensionName, $pluginName);
529 $prefixedControllerArguments = array($pluginNamespace => $controllerArguments);
530 }
531 ArrayUtility::mergeRecursiveWithOverrule($this->arguments, $prefixedControllerArguments);
532 return $this->build();
533 }
534
535 /**
536 * Disable cache hash if the action is not cacheable
537 * and pointed to from an already uncached request
538 *
539 * @param array $controllerArguments the current controller arguments
540 * @return void
541 */
542 protected function disableCacheHashForNonCacheableAction(array $controllerArguments) {
543 if (isset($controllerArguments['action']) && $this->getUseCacheHash()) {
544 $actionIsCacheable = $this->extensionService->isActionCacheable(
545 NULL,
546 NULL,
547 $controllerArguments['controller'],
548 $controllerArguments['action']
549 );
550 $this->setUseCacheHash($this->request->isCached() || $actionIsCacheable);
551 }
552 }
553
554 /**
555 * This removes controller and/or action arguments from given controllerArguments
556 * if they are equal to the default controller/action of the target plugin.
557 * Note: This is only active in FE mode and if feature "skipDefaultArguments" is enabled
558 *
559 * @see \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::isFeatureEnabled()
560 * @param array $controllerArguments the current controller arguments to be modified
561 * @param string $extensionName target extension name
562 * @param string $pluginName target plugin name
563 * @return array
564 */
565 protected function removeDefaultControllerAndAction(array $controllerArguments, $extensionName, $pluginName) {
566 $defaultControllerName = $this->extensionService->getDefaultControllerNameByPlugin($extensionName, $pluginName);
567 if (isset($controllerArguments['action'])) {
568 $defaultActionName = $this->extensionService->getDefaultActionNameByPluginAndController($extensionName, $pluginName, $controllerArguments['controller']);
569 if ($controllerArguments['action'] === $defaultActionName) {
570 unset($controllerArguments['action']);
571 }
572 }
573 if ($controllerArguments['controller'] === $defaultControllerName) {
574 unset($controllerArguments['controller']);
575 }
576 return $controllerArguments;
577 }
578
579 /**
580 * Builds the URI
581 * Depending on the current context this calls buildBackendUri() or buildFrontendUri()
582 *
583 * @return string The URI
584 * @api
585 * @see buildBackendUri()
586 * @see buildFrontendUri()
587 */
588 public function build() {
589 if ($this->environmentService->isEnvironmentInBackendMode()) {
590 return $this->buildBackendUri();
591 } else {
592 return $this->buildFrontendUri();
593 }
594 }
595
596 /**
597 * Builds the URI, backend flavour
598 * The resulting URI is relative and starts with "mod.php".
599 * The settings pageUid, pageType, noCache, useCacheHash & linkAccessRestrictedPages
600 * will be ignored in the backend.
601 *
602 * @return string The URI
603 */
604 public function buildBackendUri() {
605 if ($this->addQueryString === TRUE) {
606 if ($this->addQueryStringMethod) {
607 switch ($this->addQueryStringMethod) {
608 case 'GET':
609 $arguments = GeneralUtility::_GET();
610 break;
611 case 'POST':
612 $arguments = GeneralUtility::_POST();
613 break;
614 case 'GET,POST':
615 $arguments = array_replace_recursive(GeneralUtility::_GET(), GeneralUtility::_POST());
616 break;
617 case 'POST,GET':
618 $arguments = array_replace_recursive(GeneralUtility::_POST(), GeneralUtility::_GET());
619 break;
620 default:
621 $arguments = GeneralUtility::explodeUrl2Array(GeneralUtility::getIndpEnv('QUERY_STRING'), TRUE);
622 }
623 } else {
624 $arguments = GeneralUtility::_GET();
625 }
626 foreach ($this->argumentsToBeExcludedFromQueryString as $argumentToBeExcluded) {
627 $argumentToBeExcluded = GeneralUtility::explodeUrl2Array($argumentToBeExcluded, TRUE);
628 $arguments = ArrayUtility::arrayDiffAssocRecursive($arguments, $argumentToBeExcluded);
629 }
630 } else {
631 $arguments = array(
632 'M' => GeneralUtility::_GP('M'),
633 'id' => GeneralUtility::_GP('id')
634 );
635 }
636 ArrayUtility::mergeRecursiveWithOverrule($arguments, $this->arguments);
637 $arguments = $this->convertDomainObjectsToIdentityArrays($arguments);
638 $this->lastArguments = $arguments;
639 $moduleName = $arguments['M'];
640 unset($arguments['M'], $arguments['moduleToken']);
641 $uri = BackendUtility::getModuleUrl($moduleName, $arguments, '');
642 if ($this->section !== '') {
643 $uri .= '#' . $this->section;
644 }
645 if ($this->createAbsoluteUri === TRUE) {
646 $uri = $this->request->getBaseUri() . $uri;
647 }
648 return $uri;
649 }
650
651 /**
652 * Builds the URI, frontend flavour
653 *
654 * @return string The URI
655 * @see buildTypolinkConfiguration()
656 */
657 public function buildFrontendUri() {
658 $typolinkConfiguration = $this->buildTypolinkConfiguration();
659 if ($this->createAbsoluteUri === TRUE) {
660 $typolinkConfiguration['forceAbsoluteUrl'] = TRUE;
661 if ($this->absoluteUriScheme !== NULL) {
662 $typolinkConfiguration['forceAbsoluteUrl.']['scheme'] = $this->absoluteUriScheme;
663 }
664 }
665 $uri = $this->contentObject->typoLink_URL($typolinkConfiguration);
666 return $uri;
667 }
668
669 /**
670 * Builds a TypoLink configuration array from the current settings
671 *
672 * @return array typolink configuration array
673 * @see TSref/typolink
674 */
675 protected function buildTypolinkConfiguration() {
676 $typolinkConfiguration = array();
677 $typolinkConfiguration['parameter'] = $this->targetPageUid !== NULL ? $this->targetPageUid : $GLOBALS['TSFE']->id;
678 if ($this->targetPageType !== 0) {
679 $typolinkConfiguration['parameter'] .= ',' . $this->targetPageType;
680 } elseif ($this->format !== '') {
681 $targetPageType = $this->extensionService->getTargetPageTypeByFormat($this->request->getControllerExtensionKey(), $this->format);
682 $typolinkConfiguration['parameter'] .= ',' . $targetPageType;
683 }
684 if (count($this->arguments) > 0) {
685 $arguments = $this->convertDomainObjectsToIdentityArrays($this->arguments);
686 $this->lastArguments = $arguments;
687 $typolinkConfiguration['additionalParams'] = GeneralUtility::implodeArrayForUrl(NULL, $arguments);
688 }
689 if ($this->addQueryString === TRUE) {
690 $typolinkConfiguration['addQueryString'] = 1;
691 if (count($this->argumentsToBeExcludedFromQueryString) > 0) {
692 $typolinkConfiguration['addQueryString.'] = array(
693 'exclude' => implode(',', $this->argumentsToBeExcludedFromQueryString)
694 );
695 }
696 if ($this->addQueryStringMethod) {
697 $typolinkConfiguration['addQueryString.']['method'] = $this->addQueryStringMethod;
698 }
699 }
700 if ($this->noCache === TRUE) {
701 $typolinkConfiguration['no_cache'] = 1;
702 } elseif ($this->useCacheHash) {
703 $typolinkConfiguration['useCacheHash'] = 1;
704 }
705 if ($this->section !== '') {
706 $typolinkConfiguration['section'] = $this->section;
707 }
708 if ($this->linkAccessRestrictedPages === TRUE) {
709 $typolinkConfiguration['linkAccessRestrictedPages'] = 1;
710 }
711 return $typolinkConfiguration;
712 }
713
714 /**
715 * Recursively iterates through the specified arguments and turns instances of type \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
716 * into an arrays containing the uid of the domain object.
717 *
718 * @param array $arguments The arguments to be iterated
719 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException
720 * @return array The modified arguments array
721 */
722 protected function convertDomainObjectsToIdentityArrays(array $arguments) {
723 foreach ($arguments as $argumentKey => $argumentValue) {
724 // if we have a LazyLoadingProxy here, make sure to get the real instance for further processing
725 if ($argumentValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
726 $argumentValue = $argumentValue->_loadRealInstance();
727 // also update the value in the arguments array, because the lazyLoaded object could be
728 // hidden and thus the $argumentValue would be NULL.
729 $arguments[$argumentKey] = $argumentValue;
730 }
731 if ($argumentValue instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject) {
732 if ($argumentValue->getUid() !== NULL) {
733 $arguments[$argumentKey] = $argumentValue->getUid();
734 } elseif ($argumentValue instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject) {
735 $arguments[$argumentKey] = $this->convertTransientObjectToArray($argumentValue);
736 } else {
737 throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentValueException('Could not serialize Domain Object ' . get_class($argumentValue) . '. It is neither an Entity with identity properties set, nor a Value Object.', 1260881688);
738 }
739 } elseif (is_array($argumentValue)) {
740 $arguments[$argumentKey] = $this->convertDomainObjectsToIdentityArrays($argumentValue);
741 }
742 }
743 return $arguments;
744 }
745
746 /**
747 * Converts a given object recursively into an array.
748 *
749 * @param \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject $object
750 * @return array
751 * @todo Refactore this into convertDomainObjectsToIdentityArrays()
752 */
753 public function convertTransientObjectToArray(\TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject $object) {
754 $result = array();
755 foreach ($object->_getProperties() as $propertyName => $propertyValue) {
756 if ($propertyValue instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject) {
757 if ($propertyValue->getUid() !== NULL) {
758 $result[$propertyName] = $propertyValue->getUid();
759 } else {
760 $result[$propertyName] = $this->convertTransientObjectToArray($propertyValue);
761 }
762 } elseif (is_array($propertyValue)) {
763 $result[$propertyName] = $this->convertDomainObjectsToIdentityArrays($propertyValue);
764 } else {
765 $result[$propertyName] = $propertyValue;
766 }
767 }
768 return $result;
769 }
770
771 }