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