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