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