Revert "[TASK] Rebuild the calcAge functionality"
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / ContentObjectRenderer.php
1 <?php
2 namespace TYPO3\CMS\Frontend\ContentObject;
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\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Core\Versioning\VersionState;
19 use TYPO3\CMS\Frontend\Imaging\GifBuilder;
20
21 /**
22 * This class contains all main TypoScript features.
23 * This includes the rendering of TypoScript content objects (cObjects).
24 * Is the backbone of TypoScript Template rendering.
25 *
26 * There are lots of functions you can use from your include-scripts.
27 * The class is normally instantiated and referred to as "cObj".
28 * When you call your own PHP-code typically through a USER or USER_INT cObject then it is this class that instantiates the object and calls the main method. Before it does so it will set (if you are using classes) a reference to itself in the internal variable "cObj" of the object. Thus you can access all functions and data from this class by $this->cObj->... from within you classes written to be USER or USER_INT content objects.
29 *
30 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
31 */
32 class ContentObjectRenderer {
33
34 /**
35 * @todo Define visibility
36 */
37 public $align = array(
38 'center',
39 'right',
40 'left'
41 );
42
43 /**
44 * stdWrap functions in their correct order
45 *
46 * @see stdWrap()
47 * @todo Define visibility
48 */
49 public $stdWrapOrder = array(
50 'stdWrapPreProcess' => 'hook',
51 // this is a placeholder for the first Hook
52 'cacheRead' => 'hook',
53 // this is a placeholder for checking if the content is available in cache
54 'setContentToCurrent' => 'boolean',
55 'setContentToCurrent.' => 'array',
56 'addPageCacheTags' => 'string',
57 'addPageCacheTags.' => 'array',
58 'setCurrent' => 'string',
59 'setCurrent.' => 'array',
60 'lang.' => 'array',
61 'data' => 'getText',
62 'data.' => 'array',
63 'field' => 'fieldName',
64 'field.' => 'array',
65 'current' => 'boolean',
66 'current.' => 'array',
67 'cObject' => 'cObject',
68 'cObject.' => 'array',
69 'numRows.' => 'array',
70 'filelist' => 'dir',
71 'filelist.' => 'array',
72 'preUserFunc' => 'functionName',
73 'stdWrapOverride' => 'hook',
74 // this is a placeholder for the second Hook
75 'override' => 'string',
76 'override.' => 'array',
77 'preIfEmptyListNum' => 'listNum',
78 'preIfEmptyListNum.' => 'array',
79 'ifNull' => 'string',
80 'ifNull.' => 'array',
81 'ifEmpty' => 'string',
82 'ifEmpty.' => 'array',
83 'ifBlank' => 'string',
84 'ifBlank.' => 'array',
85 'listNum' => 'listNum',
86 'listNum.' => 'array',
87 'trim' => 'boolean',
88 'trim.' => 'array',
89 'strPad.' => 'array',
90 'stdWrap' => 'stdWrap',
91 'stdWrap.' => 'array',
92 'stdWrapProcess' => 'hook',
93 // this is a placeholder for the third Hook
94 'required' => 'boolean',
95 'required.' => 'array',
96 'if.' => 'array',
97 'fieldRequired' => 'fieldName',
98 'fieldRequired.' => 'array',
99 'csConv' => 'string',
100 'csConv.' => 'array',
101 'parseFunc' => 'objectpath',
102 'parseFunc.' => 'array',
103 'HTMLparser' => 'boolean',
104 'HTMLparser.' => 'array',
105 'split.' => 'array',
106 'replacement.' => 'array',
107 'prioriCalc' => 'boolean',
108 'prioriCalc.' => 'array',
109 'char' => 'integer',
110 'char.' => 'array',
111 'intval' => 'boolean',
112 'intval.' => 'array',
113 'hash' => 'string',
114 'hash.' => 'array',
115 'round' => 'boolean',
116 'round.' => 'array',
117 'numberFormat.' => 'array',
118 'expandList' => 'boolean',
119 'expandList.' => 'array',
120 'date' => 'dateconf',
121 'date.' => 'array',
122 'strftime' => 'strftimeconf',
123 'strftime.' => 'array',
124 'age' => 'boolean',
125 'age.' => 'array',
126 'case' => 'case',
127 'case.' => 'array',
128 'bytes' => 'boolean',
129 'bytes.' => 'array',
130 'substring' => 'parameters',
131 'substring.' => 'array',
132 'removeBadHTML' => 'boolean',
133 'removeBadHTML.' => 'array',
134 'cropHTML' => 'crop',
135 'cropHTML.' => 'array',
136 'stripHtml' => 'boolean',
137 'stripHtml.' => 'array',
138 'crop' => 'crop',
139 'crop.' => 'array',
140 'rawUrlEncode' => 'boolean',
141 'rawUrlEncode.' => 'array',
142 'htmlSpecialChars' => 'boolean',
143 'htmlSpecialChars.' => 'array',
144 'encodeForJavaScriptValue' => 'boolean',
145 'encodeForJavaScriptValue.' => 'array',
146 'doubleBrTag' => 'string',
147 'doubleBrTag.' => 'array',
148 'br' => 'boolean',
149 'br.' => 'array',
150 'brTag' => 'string',
151 'brTag.' => 'array',
152 'encapsLines.' => 'array',
153 'keywords' => 'boolean',
154 'keywords.' => 'array',
155 'innerWrap' => 'wrap',
156 'innerWrap.' => 'array',
157 'innerWrap2' => 'wrap',
158 'innerWrap2.' => 'array',
159 'fontTag' => 'wrap',
160 'fontTag.' => 'array',
161 'addParams.' => 'array',
162 'textStyle.' => 'array',
163 'tableStyle.' => 'array',
164 'filelink.' => 'array',
165 'preCObject' => 'cObject',
166 'preCObject.' => 'array',
167 'postCObject' => 'cObject',
168 'postCObject.' => 'array',
169 'wrapAlign' => 'align',
170 'wrapAlign.' => 'array',
171 'typolink.' => 'array',
172 'TCAselectItem.' => 'array',
173 'space' => 'space',
174 'space.' => 'array',
175 'spaceBefore' => 'int',
176 'spaceBefore.' => 'array',
177 'spaceAfter' => 'int',
178 'spaceAfter.' => 'array',
179 'wrap' => 'wrap',
180 'wrap.' => 'array',
181 'noTrimWrap' => 'wrap',
182 'noTrimWrap.' => 'array',
183 'wrap2' => 'wrap',
184 'wrap2.' => 'array',
185 'dataWrap' => 'dataWrap',
186 'dataWrap.' => 'array',
187 'prepend' => 'cObject',
188 'prepend.' => 'array',
189 'append' => 'cObject',
190 'append.' => 'array',
191 'wrap3' => 'wrap',
192 'wrap3.' => 'array',
193 'orderedStdWrap' => 'stdWrap',
194 'orderedStdWrap.' => 'array',
195 'outerWrap' => 'wrap',
196 'outerWrap.' => 'array',
197 'insertData' => 'boolean',
198 'insertData.' => 'array',
199 'offsetWrap' => 'space',
200 'offsetWrap.' => 'array',
201 'postUserFunc' => 'functionName',
202 'postUserFuncInt' => 'functionName',
203 'prefixComment' => 'string',
204 'prefixComment.' => 'array',
205 'editIcons' => 'string',
206 'editIcons.' => 'array',
207 'editPanel' => 'boolean',
208 'editPanel.' => 'array',
209 'cacheStore' => 'hook',
210 // this is a placeholder for storing the content in cache
211 'stdWrapPostProcess' => 'hook',
212 // this is a placeholder for the last Hook
213 'debug' => 'boolean',
214 'debug.' => 'array',
215 'debugFunc' => 'boolean',
216 'debugFunc.' => 'array',
217 'debugData' => 'boolean',
218 'debugData.' => 'array'
219 );
220
221 /**
222 * Class names for accordant content objects
223 *
224 * @var array
225 */
226 protected $contentObjectClassMapping = array(
227 'TEXT' => 'Text',
228 'CASE' => 'Case',
229 'CLEARGIF' => 'ClearGif',
230 'COBJ_ARRAY' => 'ContentObjectArray',
231 'COA' => 'ContentObjectArray',
232 'COA_INT' => 'ContentObjectArrayInternal',
233 'USER' => 'User',
234 'USER_INT' => 'UserInternal',
235 'FILE' => 'File',
236 'FILES' => 'Files',
237 'IMAGE' => 'Image',
238 'IMG_RESOURCE' => 'ImageResource',
239 'IMGTEXT' => 'ImageText',
240 'CONTENT' => 'Content',
241 'RECORDS' => 'Records',
242 'HMENU' => 'HierarchicalMenu',
243 'CTABLE' => 'ContentTable',
244 'OTABLE' => 'OffsetTable',
245 'COLUMNS' => 'Columns',
246 'HRULER' => 'HorizontalRuler',
247 'CASEFUNC' => 'Case',
248 'LOAD_REGISTER' => 'LoadRegister',
249 'RESTORE_REGISTER' => 'RestoreRegister',
250 'FORM' => 'Form',
251 'SEARCHRESULT' => 'SearchResult',
252 'TEMPLATE' => 'Template',
253 'FLUIDTEMPLATE' => 'FluidTemplate',
254 'MULTIMEDIA' => 'Multimedia',
255 'MEDIA' => 'Media',
256 'SWFOBJECT' => 'ShockwaveFlashObject',
257 'FLOWPLAYER' => 'FlowPlayer',
258 'QTOBJECT' => 'QuicktimeObject',
259 'SVG' => 'ScalableVectorGraphics',
260 'EDITPANEL' => 'EditPanel',
261 );
262
263 /**
264 * Holds ImageMagick parameters and extensions used for compression
265 *
266 * @see IMGTEXT()
267 * @todo Define visibility
268 */
269 public $image_compression = array(
270 10 => array(
271 'params' => '',
272 'ext' => 'gif'
273 ),
274 11 => array(
275 'params' => '-colors 128',
276 'ext' => 'gif'
277 ),
278 12 => array(
279 'params' => '-colors 64',
280 'ext' => 'gif'
281 ),
282 13 => array(
283 'params' => '-colors 32',
284 'ext' => 'gif'
285 ),
286 14 => array(
287 'params' => '-colors 16',
288 'ext' => 'gif'
289 ),
290 15 => array(
291 'params' => '-colors 8',
292 'ext' => 'gif'
293 ),
294 20 => array(
295 'params' => '-quality 100',
296 'ext' => 'jpg'
297 ),
298 21 => array(
299 'params' => '-quality 90',
300 'ext' => 'jpg'
301 ),
302 22 => array(
303 'params' => '-quality 80',
304 'ext' => 'jpg'
305 ),
306 23 => array(
307 'params' => '-quality 70',
308 'ext' => 'jpg'
309 ),
310 24 => array(
311 'params' => '-quality 60',
312 'ext' => 'jpg'
313 ),
314 25 => array(
315 'params' => '-quality 50',
316 'ext' => 'jpg'
317 ),
318 26 => array(
319 'params' => '-quality 40',
320 'ext' => 'jpg'
321 ),
322 27 => array(
323 'params' => '-quality 30',
324 'ext' => 'jpg'
325 ),
326 28 => array(
327 'params' => '-quality 20',
328 'ext' => 'jpg'
329 ),
330 30 => array(
331 'params' => '-colors 256',
332 'ext' => 'png'
333 ),
334 31 => array(
335 'params' => '-colors 128',
336 'ext' => 'png'
337 ),
338 32 => array(
339 'params' => '-colors 64',
340 'ext' => 'png'
341 ),
342 33 => array(
343 'params' => '-colors 32',
344 'ext' => 'png'
345 ),
346 34 => array(
347 'params' => '-colors 16',
348 'ext' => 'png'
349 ),
350 35 => array(
351 'params' => '-colors 8',
352 'ext' => 'png'
353 ),
354 39 => array(
355 'params' => '',
356 'ext' => 'png'
357 )
358 );
359
360 /**
361 * ImageMagick parameters for image effects
362 *
363 * @see IMGTEXT()
364 * @todo Define visibility
365 */
366 public $image_effects = array(
367 1 => '-rotate 90',
368 2 => '-rotate 270',
369 3 => '-rotate 180',
370 10 => '-colorspace GRAY',
371 11 => '-sharpen 70',
372 20 => '-normalize',
373 23 => '-contrast',
374 25 => '-gamma 1.3',
375 26 => '-gamma 0.8'
376 );
377
378 /**
379 * Loaded with the current data-record.
380 *
381 * If the instance of this class is used to render records from the database those records are found in this array.
382 * The function stdWrap has TypoScript properties that fetch field-data from this array.
383 *
384 * @see init()
385 * @todo Define visibility
386 */
387 public $data = array();
388
389 protected $table = '';
390
391 // Used for backup...
392 /**
393 * @todo Define visibility
394 */
395 public $oldData = array();
396
397 // If this is set with an array before stdWrap, it's used instead of $this->data in the data-property in stdWrap
398 /**
399 * @todo Define visibility
400 */
401 public $alternativeData = '';
402
403 // Used by the parseFunc function and is loaded with tag-parameters when parsing tags.
404 /**
405 * @todo Define visibility
406 */
407 public $parameters = array();
408
409 /**
410 * @todo Define visibility
411 */
412 public $currentValKey = 'currentValue_kidjls9dksoje';
413
414 // This is set to the [table]:[uid] of the record delivered in the $data-array, if the cObjects CONTENT or RECORD is in operation.
415 // Note that $GLOBALS['TSFE']->currentRecord is set to an equal value but always indicating the latest record rendered.
416 /**
417 * @todo Define visibility
418 */
419 public $currentRecord = '';
420
421 // Set in cObj->RECORDS and cObj->CONTENT to the current number of records selected in a query.
422 /**
423 * @todo Define visibility
424 */
425 public $currentRecordTotal = 0;
426
427 // Incremented in cObj->RECORDS and cObj->CONTENT before each record rendering.
428 /**
429 * @todo Define visibility
430 */
431 public $currentRecordNumber = 0;
432
433 // Incremented in parent cObj->RECORDS and cObj->CONTENT before each record rendering.
434 /**
435 * @todo Define visibility
436 */
437 public $parentRecordNumber = 0;
438
439 // If the ContentObjectRender was started from CONTENT, RECORD or SEARCHRESULT cObject's this array has two keys, 'data' and 'currentRecord' which indicates the record and data for the parent cObj.
440 /**
441 * @todo Define visibility
442 */
443 public $parentRecord = array();
444
445 // This may be set as a reference to the calling object of eg. cObjGetSingle. Anyway, just use it as you like. It's used in productsLib.inc for example.
446 /**
447 * @todo Define visibility
448 */
449 public $regObj;
450
451 // internal
452 // Is set to 1 if the instance of this cObj is executed from a *_INT plugin (see pagegen, bottom of document)
453 /**
454 * @todo Define visibility
455 */
456 public $INT_include = 0;
457
458 // This is used by checkPid, that checks if pages are accessible. The $checkPid_cache['page_uid'] is set TRUE or FALSE upon this check featuring a caching function for the next request.
459 /**
460 * @todo Define visibility
461 */
462 public $checkPid_cache = array();
463
464 /**
465 * @todo Define visibility
466 */
467 public $checkPid_badDoktypeList = '255';
468
469 // This will be set by typoLink() to the url of the most recent link created.
470 /**
471 * @todo Define visibility
472 */
473 public $lastTypoLinkUrl = '';
474
475 // DO. link target.
476 /**
477 * @todo Define visibility
478 */
479 public $lastTypoLinkTarget = '';
480
481 /**
482 * @todo Define visibility
483 */
484 public $lastTypoLinkLD = array();
485
486 // Caching substituteMarkerArrayCached function
487 /**
488 * @todo Define visibility
489 */
490 public $substMarkerCache = array();
491
492 // array that registers rendered content elements (or any table) to make sure they are not rendered recursively!
493 /**
494 * @todo Define visibility
495 */
496 public $recordRegister = array();
497
498 // Containing hooks for userdefined cObjects
499 /**
500 * Additionally registered content object types and class names
501 * @var array
502 */
503 protected $cObjHookObjectsRegistry = array();
504
505 /**
506 * @todo Define visibility
507 */
508 public $cObjHookObjectsArr = array();
509
510 // Containing hook objects for stdWrap
511 protected $stdWrapHookObjects = array();
512
513 // Containing hook objects for getImgResource
514 protected $getImgResourceHookObjects;
515
516 /**
517 * @var \TYPO3\CMS\Core\Resource\File Current file objects (during iterations over files)
518 */
519 protected $currentFile = NULL;
520
521 /**
522 * Set to TRUE by doConvertToUserIntObject() if USER object wants to become USER_INT
523 */
524 public $doConvertToUserIntObject = FALSE;
525
526 /**
527 * Indicates current object type. Can hold one of OBJECTTYPE_ constants or FALSE.
528 * The value is set and reset inside USER() function. Any time outside of
529 * USER() it is FALSE.
530 */
531 protected $userObjectType = FALSE;
532
533 /**
534 * Indicates that object type is USER.
535 *
536 * @see ContentObjectRender::$userObjectType
537 */
538 const OBJECTTYPE_USER_INT = 1;
539 /**
540 * Indicates that object type is USER.
541 *
542 * @see ContentObjectRender::$userObjectType
543 */
544 const OBJECTTYPE_USER = 2;
545 /**
546 * Class constructor.
547 * Well, it has to be called manually since it is not a real constructor function.
548 * So after making an instance of the class, call this function and pass to it a database record and the tablename from where the record is from. That will then become the "current" record loaded into memory and accessed by the .fields property found in eg. stdWrap.
549 *
550 * @param array $data The record data that is rendered.
551 * @param string $table The table that the data record is from.
552 * @return void
553 * @todo Define visibility
554 */
555 public function start($data, $table = '') {
556 global $TYPO3_CONF_VARS;
557 if ($TYPO3_CONF_VARS['FE']['activateContentAdapter'] && is_array($data) && !empty($data) && !empty($table)) {
558 \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService::modifyDBRow($data, $table);
559 }
560 $this->data = $data;
561 $this->table = $table;
562 $this->currentRecord = $table ? $table . ':' . $this->data['uid'] : '';
563 $this->parameters = array();
564 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClass'])) {
565 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClass'] as $classArr) {
566 $this->cObjHookObjectsRegistry[$classArr[0]] = $classArr[1];
567 }
568 }
569 $this->stdWrapHookObjects = array();
570 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap'])) {
571 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_content.php']['stdWrap'] as $classData) {
572 $hookObject = GeneralUtility::getUserObj($classData);
573 if (!$hookObject instanceof \TYPO3\CMS\Frontend\ContentObject\ContentObjectStdWrapHookInterface) {
574 throw new \UnexpectedValueException($classData . ' must implement interface TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectStdWrapHookInterface', 1195043965);
575 }
576 $this->stdWrapHookObjects[] = $hookObject;
577 }
578 }
579 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_content.php']['postInit'])) {
580 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_content.php']['postInit'] as $classData) {
581 $postInitializationProcessor = GeneralUtility::getUserObj($classData);
582 if (!$postInitializationProcessor instanceof \TYPO3\CMS\Frontend\ContentObject\ContentObjectPostInitHookInterface) {
583 throw new \UnexpectedValueException($classData . ' must implement interface TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectPostInitHookInterface', 1274563549);
584 }
585 $postInitializationProcessor->postProcessContentObjectInitialization($this);
586 }
587 }
588 }
589
590 /**
591 * Returns the current table
592 *
593 * @return string
594 */
595 public function getCurrentTable() {
596 return $this->table;
597 }
598
599 /**
600 * Gets the 'getImgResource' hook objects.
601 * The first call initializes the accordant objects.
602 *
603 * @return array The 'getImgResource' hook objects (if any)
604 */
605 protected function getGetImgResourceHookObjects() {
606 if (!isset($this->getImgResourceHookObjects)) {
607 $this->getImgResourceHookObjects = array();
608 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImgResource'])) {
609 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImgResource'] as $classData) {
610 $hookObject = GeneralUtility::getUserObj($classData);
611 if (!$hookObject instanceof \TYPO3\CMS\Frontend\ContentObject\ContentObjectGetImageResourceHookInterface) {
612 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectGetImageResourceHookInterface', 1218636383);
613 }
614 $this->getImgResourceHookObjects[] = $hookObject;
615 }
616 }
617 }
618 return $this->getImgResourceHookObjects;
619 }
620
621 /**
622 * Sets the internal variable parentRecord with information about current record.
623 * If the ContentObjectRender was started from CONTENT, RECORD or SEARCHRESULT cObject's this array has two keys, 'data' and 'currentRecord' which indicates the record and data for the parent cObj.
624 *
625 * @param array $data The record array
626 * @param string $currentRecord This is set to the [table]:[uid] of the record delivered in the $data-array, if the cObjects CONTENT or RECORD is in operation. Note that $GLOBALS['TSFE']->currentRecord is set to an equal value but always indicating the latest record rendered.
627 * @return void
628 * @access private
629 * @todo Define visibility
630 */
631 public function setParent($data, $currentRecord) {
632 $this->parentRecord = array(
633 'data' => $data,
634 'currentRecord' => $currentRecord
635 );
636 }
637
638 /***********************************************
639 *
640 * CONTENT_OBJ:
641 *
642 ***********************************************/
643 /**
644 * Returns the "current" value.
645 * The "current" value is just an internal variable that can be used by functions to pass a single value on to another function later in the TypoScript processing.
646 * It's like "load accumulator" in the good old C64 days... basically a "register" you can use as you like.
647 * The TSref will tell if functions are setting this value before calling some other object so that you know if it holds any special information.
648 *
649 * @return mixed The "current" value
650 * @todo Define visibility
651 */
652 public function getCurrentVal() {
653 return $this->data[$this->currentValKey];
654 }
655
656 /**
657 * Sets the "current" value.
658 *
659 * @param mixed $value The variable that you want to set as "current
660 * @return void
661 * @see getCurrentVal()
662 * @todo Define visibility
663 */
664 public function setCurrentVal($value) {
665 $this->data[$this->currentValKey] = $value;
666 }
667
668 /**
669 * Rendering of a "numerical array" of cObjects from TypoScript
670 * Will call ->cObjGetSingle() for each cObject found and accumulate the output.
671 *
672 * @param array $setup array with cObjects as values.
673 * @param string $addKey A prefix for the debugging information
674 * @return string Rendered output from the cObjects in the array.
675 * @see cObjGetSingle()
676 * @todo Define visibility
677 */
678 public function cObjGet($setup, $addKey = '') {
679 if (is_array($setup)) {
680 $sKeyArray = \TYPO3\CMS\Core\TypoScript\TemplateService::sortedKeyList($setup);
681 $content = '';
682 foreach ($sKeyArray as $theKey) {
683 $theValue = $setup[$theKey];
684 if ((int)$theKey && strpos($theKey, '.') === FALSE) {
685 $conf = $setup[$theKey . '.'];
686 $content .= $this->cObjGetSingle($theValue, $conf, $addKey . $theKey);
687 }
688 }
689 return $content;
690 }
691 }
692
693 /**
694 * Renders a content object
695 *
696 * @param string $name The content object name, eg. "TEXT" or "USER" or "IMAGE
697 * @param array $conf The array with TypoScript properties for the content object
698 * @param string $TSkey A string label used for the internal debugging tracking.
699 * @return string cObject output
700 * @throws \UnexpectedValueException
701 * @todo Define visibility
702 */
703 public function cObjGetSingle($name, $conf, $TSkey = '__') {
704 global $TYPO3_CONF_VARS;
705 $content = '';
706 // Checking that the function is not called eternally. This is done by interrupting at a depth of 100
707 $GLOBALS['TSFE']->cObjectDepthCounter--;
708 if ($GLOBALS['TSFE']->cObjectDepthCounter > 0) {
709 $name = trim($name);
710 if ($GLOBALS['TT']->LR) {
711 $GLOBALS['TT']->push($TSkey, $name);
712 }
713 // Checking if the COBJ is a reference to another object. (eg. name of 'blabla.blabla = < styles.something')
714 if ($name[0] === '<') {
715 $key = trim(substr($name, 1));
716 $cF = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\TypoScript\\Parser\\TypoScriptParser');
717 // $name and $conf is loaded with the referenced values.
718 $old_conf = $conf;
719 list($name, $conf) = $cF->getVal($key, $GLOBALS['TSFE']->tmpl->setup);
720 if (is_array($old_conf) && count($old_conf)) {
721 $conf = array_replace_recursive($conf, $old_conf);
722 }
723 // Getting the cObject
724 $GLOBALS['TT']->incStackPointer();
725 $content .= $this->cObjGetSingle($name, $conf, $key);
726 $GLOBALS['TT']->decStackPointer();
727 } else {
728 $hooked = FALSE;
729 // Application defined cObjects
730 if (!empty($this->cObjHookObjectsRegistry[$name])) {
731 if (empty($this->cObjHookObjectsArr[$name])) {
732 $this->cObjHookObjectsArr[$name] = GeneralUtility::getUserObj($this->cObjHookObjectsRegistry[$name]);
733 }
734 $hookObj = $this->cObjHookObjectsArr[$name];
735 if (method_exists($hookObj, 'cObjGetSingleExt')) {
736 $content .= $hookObj->cObjGetSingleExt($name, $conf, $TSkey, $this);
737 $hooked = TRUE;
738 }
739 }
740 if (!$hooked) {
741 $contentObject = $this->getContentObject($name);
742 if ($contentObject) {
743 $content .= $contentObject->render($conf);
744 } else {
745 // Call hook functions for extra processing
746 if ($name && is_array($TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClassDefault'])) {
747 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_content.php']['cObjTypeAndClassDefault'] as $classData) {
748 $hookObject = GeneralUtility::getUserObj($classData);
749 if (!$hookObject instanceof \TYPO3\CMS\Frontend\ContentObject\ContentObjectGetSingleHookInterface) {
750 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectGetSingleHookInterface', 1195043731);
751 }
752 /** @var $hookObject \TYPO3\CMS\Frontend\ContentObject\ContentObjectGetSingleHookInterface */
753 $content .= $hookObject->getSingleContentObject($name, (array) $conf, $TSkey, $this);
754 }
755 } else {
756 // Log error in AdminPanel
757 $warning = sprintf('Content Object "%s" does not exist', $name);
758 $GLOBALS['TT']->setTSlogMessage($warning, 2);
759 }
760 }
761 }
762 }
763 if ($GLOBALS['TT']->LR) {
764 $GLOBALS['TT']->pull($content);
765 }
766 }
767 // Increasing on exit...
768 $GLOBALS['TSFE']->cObjectDepthCounter++;
769 return $content;
770 }
771
772 /**
773 * Returns a new content object of type $name.
774 *
775 * @param string $name
776 * @return NULL|AbstractContentObject
777 */
778 public function getContentObject($name) {
779 if (!isset($this->contentObjectClassMapping[$name])) {
780 return NULL;
781 }
782 $fullyQualifiedClassName = 'TYPO3\\CMS\\Frontend\\ContentObject\\' . $this->contentObjectClassMapping[$name] . 'ContentObject';
783 return GeneralUtility::makeInstance($fullyQualifiedClassName, $this);
784 }
785
786 /********************************************
787 *
788 * Functions rendering content objects (cObjects)
789 *
790 ********************************************/
791
792 /**
793 * Rendering the cObject, FLOWPLAYER
794 *
795 * @param array $conf Array of TypoScript properties
796 * @return string Output
797 * @todo Define visibility
798 */
799 public function FLOWPLAYER($conf) {
800 return $this->getContentObject('FLOWPLAYER')->render($conf);
801 }
802
803 /**
804 * Rendering the cObject, TEXT
805 *
806 * @param array $conf Array of TypoScript properties
807 * @return string Output
808 * @todo Define visibility
809 */
810 public function TEXT($conf) {
811 return $this->getContentObject('TEXT')->render($conf);
812 }
813
814 /**
815 * Rendering the cObject, CLEARGIF
816 *
817 * @param array $conf Array of TypoScript properties
818 * @return string Output
819 * @todo Define visibility
820 */
821 public function CLEARGIF($conf) {
822 return $this->getContentObject('CLEARGIF')->render($conf);
823 }
824
825 /**
826 * Rendering the cObject, COBJ_ARRAY / COA and COBJ_ARRAY_INT
827 *
828 * @param array $conf Array of TypoScript properties
829 * @param string $ext If "INT" then the cObject is a "COBJ_ARRAY_INT" (non-cached), otherwise just "COBJ_ARRAY" (cached)
830 * @return string Output
831 * @todo Define visibility
832 */
833 public function COBJ_ARRAY($conf, $ext = '') {
834 if ($ext === 'INT') {
835 return $this->getContentObject('COA_INT')->render($conf);
836 } else {
837 return $this->getContentObject('COA')->render($conf);
838 }
839 }
840
841 /**
842 * Rendering the cObject, USER and USER_INT
843 *
844 * @param array $conf Array of TypoScript properties
845 * @param string $ext If "INT" then the cObject is a "USER_INT" (non-cached), otherwise just "USER" (cached)
846 * @return string Output
847 * @todo Define visibility
848 */
849 public function USER($conf, $ext = '') {
850 if ($ext === 'INT') {
851 return $this->getContentObject('USER_INT')->render($conf);
852 } else {
853 return $this->getContentObject('USER')->render($conf);
854 }
855 }
856
857 /**
858 * Retrieves a type of object called as USER or USER_INT. Object can detect their
859 * type by using this call. It returns OBJECTTYPE_USER_INT or OBJECTTYPE_USER depending on the
860 * current object execution. In all other cases it will return FALSE to indicate
861 * a call out of context.
862 *
863 * @return mixed One of OBJECTTYPE_ class constants or FALSE
864 */
865 public function getUserObjectType() {
866 return $this->userObjectType;
867 }
868
869 /**
870 * Sets the user object type
871 *
872 * @param mixed $userObjectType
873 * @return void
874 */
875 public function setUserObjectType($userObjectType) {
876 $this->userObjectType = $userObjectType;
877 }
878
879 /**
880 * Requests the current USER object to be converted to USER_INT.
881 *
882 * @return void
883 */
884 public function convertToUserIntObject() {
885 if ($this->userObjectType !== self::OBJECTTYPE_USER) {
886 $GLOBALS['TT']->setTSlogMessage('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer::convertToUserIntObject() ' . 'is called in the wrong context or for the wrong object type', 2);
887 } else {
888 $this->doConvertToUserIntObject = TRUE;
889 }
890 }
891
892 /**
893 * Rendering the cObject, FILE
894 *
895 * @param array $conf Array of TypoScript properties
896 * @return string Output
897 * @todo Define visibility
898 */
899 public function FILE($conf) {
900 return $this->getContentObject('FILE')->render($conf);
901 }
902
903 /**
904 * Rendering the cObject, FILES
905 *
906 * @param array $conf Array of TypoScript properties
907 * @return string Output
908 * @todo Define visibility
909 */
910 public function FILES($conf) {
911 return $this->getContentObject('FILES')->render($conf);
912 }
913
914 /**
915 * Rendering the cObject, IMAGE
916 *
917 * @param array $conf Array of TypoScript properties
918 * @return string Output
919 * @see cImage()
920 * @todo Define visibility
921 */
922 public function IMAGE($conf) {
923 return $this->getContentObject('IMAGE')->render($conf);
924 }
925
926 /**
927 * Rendering the cObject, IMG_RESOURCE
928 *
929 * @param array $conf Array of TypoScript properties
930 * @return string Output
931 * @see getImgResource()
932 * @todo Define visibility
933 */
934 public function IMG_RESOURCE($conf) {
935 return $this->getContentObject('IMG_RESOURCE')->render($conf);
936 }
937
938 /**
939 * Rendering the cObject, IMGTEXT
940 *
941 * @param array $conf Array of TypoScript properties
942 * @return string Output
943 * @todo Define visibility
944 */
945 public function IMGTEXT($conf) {
946 return $this->getContentObject('IMGTEXT')->render($conf);
947 }
948
949 /**
950 * Rendering the cObject, CONTENT
951 *
952 * @param array $conf Array of TypoScript properties
953 * @return string Output
954 * @todo Define visibility
955 */
956 public function CONTENT($conf) {
957 return $this->getContentObject('CONTENT')->render($conf);
958 }
959
960 /**
961 * Rendering the cObject, RECORDS
962 *
963 * @param array $conf Array of TypoScript properties
964 * @return string Output
965 * @todo Define visibility
966 */
967 public function RECORDS($conf) {
968 return $this->getContentObject('RECORDS')->render($conf);
969 }
970
971 /**
972 * Rendering the cObject, HMENU
973 *
974 * @param array $conf Array of TypoScript properties
975 * @return string Output
976 * @todo Define visibility
977 */
978 public function HMENU($conf) {
979 return $this->getContentObject('HMENU')->render($conf);
980 }
981
982 /**
983 * Rendering the cObject, CTABLE
984 *
985 * @param array $conf Array of TypoScript properties
986 * @return string Output
987 * @todo Define visibility
988 */
989 public function CTABLE($conf) {
990 return $this->getContentObject('CTABLE')->render($conf);
991 }
992
993 /**
994 * Rendering the cObject, OTABLE
995 *
996 * @param array $conf Array of TypoScript properties
997 * @return string Output
998 * @todo Define visibility
999 */
1000 public function OTABLE($conf) {
1001 return $this->getContentObject('OTABLE')->render($conf);
1002 }
1003
1004 /**
1005 * Rendering the cObject, COLUMNS
1006 *
1007 * @param array $conf Array of TypoScript properties
1008 * @return string Output
1009 * @todo Define visibility
1010 */
1011 public function COLUMNS($conf) {
1012 return $this->getContentObject('COLUMNS')->render($conf);
1013 }
1014
1015 /**
1016 * Rendering the cObject, HRULER
1017 *
1018 * @param array $conf Array of TypoScript properties
1019 * @return string Output
1020 * @todo Define visibility
1021 */
1022 public function HRULER($conf) {
1023 return $this->getContentObject('HRULER')->render($conf);
1024 }
1025
1026 /**
1027 * Rendering the cObject, CASE
1028 *
1029 * @param array $conf Array of TypoScript properties
1030 * @return string Output
1031 * @todo Define visibility
1032 */
1033 public function CASEFUNC($conf) {
1034 return $this->getContentObject('CASE')->render($conf);
1035 }
1036
1037 /**
1038 * Rendering the cObject, LOAD_REGISTER and RESTORE_REGISTER
1039 * NOTICE: This cObject does NOT return any content since it just sets internal data based on the TypoScript properties.
1040 *
1041 * @param array $conf Array of TypoScript properties
1042 * @param string $name If "RESTORE_REGISTER" then the cObject rendered is "RESTORE_REGISTER", otherwise "LOAD_REGISTER
1043 * @return string Empty string (the cObject only sets internal data!)
1044 * @todo Define visibility
1045 */
1046 public function LOAD_REGISTER($conf, $name) {
1047 if ($name === 'RESTORE_REGISTER') {
1048 return $this->getContentObject('RESTORE_REGISTER')->render();
1049 } else {
1050 return $this->getContentObject('LOAD_REGISTER')->render($conf);
1051 }
1052 }
1053
1054 /**
1055 * Rendering the cObject, FORM
1056 *
1057 * @param array $conf Array of TypoScript properties
1058 * @param array $formData Alternative formdata overriding whatever comes from TypoScript
1059 * @return string Output
1060 * @todo Define visibility
1061 */
1062 public function FORM($conf, $formData = '') {
1063 return $this->getContentObject('FORM')->render($conf, $formData);
1064 }
1065
1066 /**
1067 * Rendering the cObject, SEARCHRESULT
1068 *
1069 * @param array $conf Array of TypoScript properties
1070 * @return string Output
1071 * @todo Define visibility
1072 */
1073 public function SEARCHRESULT($conf) {
1074 return $this->getContentObject('SEARCHRESULT')->render($conf);
1075 }
1076
1077 /**
1078 * Rendering the cObject, TEMPLATE
1079 *
1080 * @param array $conf Array of TypoScript properties
1081 * @return string Output
1082 * @see substituteMarkerArrayCached()
1083 * @todo Define visibility
1084 */
1085 public function TEMPLATE($conf) {
1086 return $this->getContentObject('TEMPLATE')->render($conf);
1087 }
1088
1089 /**
1090 * Rendering the cObject, FLUIDTEMPLATE
1091 *
1092 * @param array $conf Array of TypoScript properties
1093 * @return string the HTML output
1094 * @author Steffen Ritter <info@steffen-ritter.net>
1095 * @author Benjamin Mack <benni@typo3.org>
1096 */
1097 protected function FLUIDTEMPLATE(array $conf) {
1098 return $this->getContentObject('FLUIDTEMPLATE')->render($conf);
1099 }
1100
1101 /**
1102 * Rendering the cObject, MULTIMEDIA
1103 *
1104 * @param array $conf Array of TypoScript properties
1105 * @return string Output
1106 * @todo Define visibility
1107 */
1108 public function MULTIMEDIA($conf) {
1109 return $this->getContentObject('MULTIMEDIA')->render($conf);
1110 }
1111
1112 /**
1113 * Rendering the cObject, MEDIA
1114 *
1115 * @param array $conf Array of TypoScript properties
1116 * @return string Output
1117 */
1118 public function MEDIA($conf) {
1119 return $this->getContentObject('MEDIA')->render($conf);
1120 }
1121
1122 /**
1123 * Rendering the cObject, SWFOBJECT
1124 *
1125 * @param array $conf Array of TypoScript properties
1126 * @return string Output
1127 */
1128 public function SWFOBJECT($conf) {
1129 return $this->getContentObject('SWFOBJECT')->render($conf);
1130 }
1131
1132 /**
1133 * Rendering the cObject, QTOBJECT
1134 *
1135 * @param array $conf Array of TypoScript properties
1136 * @return string Output
1137 */
1138 public function QTOBJECT($conf) {
1139 return $this->getContentObject('QTOBJECT')->render($conf);
1140 }
1141
1142 /**
1143 * Rendering the cObject, SVG
1144 *
1145 * @param array $conf Array of TypoScript properties
1146 * @return string Output
1147 */
1148 public function SVG($conf) {
1149 return $this->getContentObject('SVG')->render($conf);
1150 }
1151
1152 /************************************
1153 *
1154 * Various helper functions for content objects:
1155 *
1156 ************************************/
1157 /**
1158 * Converts a given config in Flexform to a conf-array
1159 *
1160 * @param string|array $flexData Flexform data
1161 * @param array $conf Array to write the data into, by reference
1162 * @param boolean $recursive Is set if called recursive. Don't call function with this parameter, it's used inside the function only
1163 * @return void
1164 */
1165 public function readFlexformIntoConf($flexData, &$conf, $recursive = FALSE) {
1166 if ($recursive === FALSE && is_string($flexData)) {
1167 $flexData = GeneralUtility::xml2array($flexData, 'T3');
1168 }
1169 if (isset($flexData['data']['sDEF']['lDEF'])) {
1170 $flexData = $flexData['data']['sDEF']['lDEF'];
1171 }
1172 if (!is_array($flexData)) {
1173 return;
1174 }
1175 foreach ($flexData as $key => $value) {
1176 if (!is_array($value)) {
1177 continue;
1178 }
1179 if (isset($value['el'])) {
1180 if (is_array($value['el']) && count($value['el']) > 0) {
1181 foreach ($value['el'] as $ekey => $element) {
1182 if (isset($element['vDEF'])) {
1183 $conf[$ekey] = $element['vDEF'];
1184 } else {
1185 if (is_array($element)) {
1186 $this->readFlexformIntoConf($element, $conf[$key][key($element)][$ekey], TRUE);
1187 } else {
1188 $this->readFlexformIntoConf($element, $conf[$key][$ekey], TRUE);
1189 }
1190 }
1191 }
1192 } else {
1193 $this->readFlexformIntoConf($value['el'], $conf[$key], TRUE);
1194 }
1195 }
1196 if (isset($value['vDEF'])) {
1197 $conf[$key] = $value['vDEF'];
1198 }
1199 }
1200 }
1201
1202 /**
1203 * Returns all parents of the given PID (Page UID) list
1204 *
1205 * @param string $pidList A list of page Content-Element PIDs (Page UIDs) / stdWrap
1206 * @param array $pidConf stdWrap array for the list
1207 * @return string A list of PIDs
1208 * @access private
1209 * @todo Define visibility
1210 */
1211 public function getSlidePids($pidList, $pidConf) {
1212 $pidList = isset($pidConf) ? trim($this->stdWrap($pidList, $pidConf)) : trim($pidList);
1213 if ($pidList === '') {
1214 $pidList = 'this';
1215 }
1216 if (trim($pidList)) {
1217 $listArr = GeneralUtility::intExplode(',', str_replace('this', $GLOBALS['TSFE']->contentPid, $pidList));
1218 $listArr = $this->checkPidArray($listArr);
1219 }
1220 $pidList = array();
1221 if (is_array($listArr) && count($listArr)) {
1222 foreach ($listArr as $uid) {
1223 $page = $GLOBALS['TSFE']->sys_page->getPage($uid);
1224 if (!$page['is_siteroot']) {
1225 $pidList[] = $page['pid'];
1226 }
1227 }
1228 }
1229 return implode(',', $pidList);
1230 }
1231
1232 /**
1233 * Returns a default value for a form field in the FORM cObject.
1234 * Page CANNOT be cached because that would include the inserted value for the current user.
1235 *
1236 * @param boolean $noValueInsert If noValueInsert OR if the no_cache flag for this page is NOT set, the original default value is returned.
1237 * @param string $fieldName The POST var name to get default value for
1238 * @param string $defaultVal The current default value
1239 * @return string The default value, either from INPUT var or the current default, based on whether caching is enabled or not.
1240 * @access private
1241 * @todo Define visibility
1242 */
1243 public function getFieldDefaultValue($noValueInsert, $fieldName, $defaultVal) {
1244 if (!$GLOBALS['TSFE']->no_cache || !isset($_POST[$fieldName]) && !isset($_GET[$fieldName]) || $noValueInsert) {
1245 return $defaultVal;
1246 } else {
1247 return GeneralUtility::_GP($fieldName);
1248 }
1249 }
1250
1251 /**
1252 * Returns a <img> tag with the image file defined by $file and processed according to the properties in the TypoScript array.
1253 * Mostly this function is a sub-function to the IMAGE function which renders the IMAGE cObject in TypoScript.
1254 * This function is called by "$this->cImage($conf['file'], $conf);" from IMAGE().
1255 *
1256 * @param string $file File TypoScript resource
1257 * @param array $conf TypoScript configuration properties
1258 * @return string <img> tag, (possibly wrapped in links and other HTML) if any image found.
1259 * @access private
1260 * @see IMAGE()
1261 * @todo Define visibility
1262 */
1263 public function cImage($file, $conf) {
1264 $info = $this->getImgResource($file, $conf['file.']);
1265 $GLOBALS['TSFE']->lastImageInfo = $info;
1266 if (!is_array($info)) {
1267 return '';
1268 }
1269 if (is_file(PATH_site . $info['3'])) {
1270 $source = GeneralUtility::rawUrlEncodeFP(GeneralUtility::png_to_gif_by_imagemagick($info[3]));
1271 $source = $GLOBALS['TSFE']->absRefPrefix . $source;
1272 } else {
1273 $source = $info[3];
1274 }
1275
1276 $layoutKey = $this->stdWrap($conf['layoutKey'], $conf['layoutKey.']);
1277 $imageTagTemplate = $this->getImageTagTemplate($layoutKey, $conf);
1278 $sourceCollection = $this->getImageSourceCollection($layoutKey, $conf, $file);
1279
1280 // This array is used to collect the image-refs on the page...
1281 $GLOBALS['TSFE']->imagesOnPage[] = $source;
1282 $altParam = $this->getAltParam($conf);
1283 $params = $this->stdWrapValue('params', $conf);
1284 if ($params !== '' && $params{0} !== ' ') {
1285 $params = ' ' . $params;
1286 }
1287
1288 $imageTagValues = array(
1289 'width' => $info[0],
1290 'height' => $info[1],
1291 'src' => htmlspecialchars($source),
1292 'params' => $params,
1293 'altParams' => $altParam,
1294 'border' => $this->getBorderAttr(' border="' . (int)$conf['border'] . '"'),
1295 'sourceCollection' => $sourceCollection,
1296 'selfClosingTagSlash' => (!empty($GLOBALS['TSFE']->xhtmlDoctype) ? ' /' : ''),
1297 );
1298
1299 $theValue = $this->substituteMarkerArray($imageTagTemplate, $imageTagValues, '###|###', TRUE, TRUE);
1300
1301 $linkWrap = isset($conf['linkWrap.']) ? $this->stdWrap($conf['linkWrap'], $conf['linkWrap.']) : $conf['linkWrap'];
1302 if ($linkWrap) {
1303 $theValue = $this->linkWrap($theValue, $linkWrap);
1304 } elseif ($conf['imageLinkWrap']) {
1305 $theValue = $this->imageLinkWrap($theValue, $info['originalFile'], $conf['imageLinkWrap.']);
1306 }
1307 $wrap = isset($conf['wrap.']) ? $this->stdWrap($conf['wrap'], $conf['wrap.']) : $conf['wrap'];
1308 if ($wrap) {
1309 $theValue = $this->wrap($theValue, $conf['wrap']);
1310 }
1311 return $theValue;
1312 }
1313
1314 /**
1315 * Returns the 'border' attribute for an <img> tag only if the doctype is not xhtml_strict, xhtml_11, xhtml_2 or html5
1316 * or if the config parameter 'disableImgBorderAttr' is not set.
1317 *
1318 * @param string $borderAttr The border attribute
1319 * @return string The border attribute
1320 * @todo Define visibility
1321 */
1322 public function getBorderAttr($borderAttr) {
1323 if (!GeneralUtility::inList('xhtml_strict,xhtml_11,xhtml_2', $GLOBALS['TSFE']->xhtmlDoctype) && $GLOBALS['TSFE']->config['config']['doctype'] != 'html5' && !$GLOBALS['TSFE']->config['config']['disableImgBorderAttr']) {
1324 return $borderAttr;
1325 }
1326 }
1327
1328 /**
1329 * Returns the html-template for rendering the image-Tag if no template is defined via typoscript the
1330 * default <img> tag template is returned
1331 *
1332 * @param string $layoutKey rendering key
1333 * @param array $conf TypoScript configuration properties
1334 * @return string
1335 */
1336 public function getImageTagTemplate($layoutKey, $conf) {
1337 if ($layoutKey && isset($conf['layout.']) && isset($conf['layout.'][$layoutKey . '.'])) {
1338 $imageTagLayout = $this->stdWrap($conf['layout.'][$layoutKey . '.']['element'], $conf['layout.'][$layoutKey . '.']['element.']);
1339 } else {
1340 $imageTagLayout = '<img src="###SRC###" width="###WIDTH###" height="###HEIGHT###" ###PARAMS### ###ALTPARAMS### ###BORDER######SELFCLOSINGTAGSLASH###>';
1341 }
1342 return $imageTagLayout;
1343 }
1344
1345 /**
1346 * Render alternate sources for the image tag. If no source collection is given an empty string is returned.
1347 *
1348 * @param string $layoutKey rendering key
1349 * @param array $conf TypoScript configuration properties
1350 * @param string $file
1351 * @throws \UnexpectedValueException
1352 * @return string
1353 */
1354 public function getImageSourceCollection($layoutKey, $conf, $file) {
1355 $sourceCollection = '';
1356 if ($layoutKey && $conf['sourceCollection.'] && ($conf['layout.'][$layoutKey . '.']['source'] || $conf['layout.'][$layoutKey . '.']['source.'])) {
1357
1358 // find active sourceCollection
1359 $activeSourceCollections = array();
1360 foreach ($conf['sourceCollection.'] as $sourceCollectionKey => $sourceCollectionConfiguration) {
1361 if (substr($sourceCollectionKey, -1) == '.') {
1362 if (
1363 (isset($sourceCollectionConfiguration['if.']) && $this->checkIf($sourceCollectionConfiguration['if.']))
1364 || !isset($sourceCollectionConfiguration['if.'])
1365 ) {
1366 $activeSourceCollections[] = $sourceCollectionConfiguration;
1367 }
1368 }
1369 }
1370
1371 // apply option split to configurations
1372 $srcLayoutOptionSplitted = $GLOBALS['TSFE']->tmpl->splitConfArray($conf['layout.'][$layoutKey . '.'], count($activeSourceCollections));
1373
1374 // render sources
1375 foreach ($activeSourceCollections as $key => $sourceConfiguration) {
1376 $sourceLayout = $this->stdWrap($srcLayoutOptionSplitted[$key]['source'], $srcLayoutOptionSplitted[$key]['source.']);
1377
1378 $sourceRenderConfiguration = array (
1379 'file' => $file,
1380 'file.' => $conf['file.']
1381 );
1382
1383 if (isset($sourceConfiguration['pixelDensity'])) {
1384 $pixelDensity = (int)$this->stdWrap($sourceConfiguration['pixelDensity'], $sourceConfiguration['pixelDensity.']);
1385 } else {
1386 $pixelDensity = 1;
1387 }
1388 $dimensionKeys = array('width', 'height', 'maxW', 'minW', 'maxH', 'minH');
1389 foreach ($dimensionKeys as $dimensionKey) {
1390 $dimension = $this->stdWrap($sourceConfiguration[$dimensionKey], $sourceConfiguration[$dimensionKey . '.']);
1391 if (!$dimension) {
1392 $dimension = $this->stdWrap($conf['file.'][$dimensionKey], $conf['file.'][$dimensionKey . '.']);
1393 }
1394 if ($dimension) {
1395 if (strstr($dimension, 'c') !== FALSE && ($dimensionKey === 'width' || $dimensionKey === 'height')) {
1396 $dimensionParts = explode('c', $dimension, 2);
1397 $dimension = (int)($dimensionParts[0] * $pixelDensity) . 'c';
1398 if ($dimensionParts[1]) {
1399 $dimension .= $dimensionParts[1];
1400 }
1401 } else {
1402 $dimension = (int)($dimension * $pixelDensity);
1403 }
1404 $sourceRenderConfiguration['file.'][$dimensionKey] = $dimension;
1405 // Remove the stdWrap properties for dimension as they have been processed already above.
1406 unset($sourceRenderConfiguration['file.'][$dimensionKey . '.']);
1407 }
1408 }
1409 $sourceInfo = $this->getImgResource($sourceRenderConfiguration['file'], $sourceRenderConfiguration['file.']);
1410 if ($sourceInfo) {
1411 $sourceConfiguration['width'] = $sourceInfo[0];
1412 $sourceConfiguration['height'] = $sourceInfo[1];
1413 $sourceConfiguration['src'] = htmlspecialchars($sourceInfo[3]);
1414 $sourceConfiguration['selfClosingTagSlash'] = (!empty($GLOBALS['TSFE']->xhtmlDoctype) ? ' /' : '');
1415
1416 $oneSourceCollection = $this->substituteMarkerArray($sourceLayout, $sourceConfiguration, '###|###', TRUE, TRUE);
1417
1418 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection'])) {
1419 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection'] as $classData) {
1420 $hookObject = GeneralUtility::getUserObj($classData);
1421 if (!$hookObject instanceof ContentObjectOneSourceCollectionHookInterface) {
1422 throw new \UnexpectedValueException(
1423 '$hookObject must implement interface TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectOneSourceCollectionHookInterface',
1424 1380007853
1425 );
1426 }
1427 $oneSourceCollection = $hookObject->getOneSourceCollection((array) $sourceRenderConfiguration, (array) $sourceConfiguration, $oneSourceCollection, $this);
1428 }
1429 }
1430
1431 $sourceCollection .= $oneSourceCollection;
1432 }
1433 }
1434 }
1435 return $sourceCollection;
1436 }
1437
1438 /**
1439 * Wraps the input string in link-tags that opens the image in a new window.
1440 *
1441 * @param string $string String to wrap, probably an <img> tag
1442 * @param string|\TYPO3\CMS\Core\Resource\File|\TYPO3\CMS\Core\Resource\FileReference $imageFile The original image file
1443 * @param array $conf TypoScript properties for the "imageLinkWrap" function
1444 * @return string The input string, $string, wrapped as configured.
1445 * @see cImage()
1446 * @todo Define visibility
1447 */
1448 public function imageLinkWrap($string, $imageFile, $conf) {
1449 $a1 = '';
1450 $a2 = '';
1451 $content = $string;
1452 $enable = isset($conf['enable.']) ? $this->stdWrap($conf['enable'], $conf['enable.']) : $conf['enable'];
1453 if ($enable) {
1454 $content = $this->typolink($string, $conf['typolink.']);
1455 if (isset($conf['file.'])) {
1456 $imageFile = $this->stdWrap($imageFile, $conf['file.']);
1457 }
1458
1459 if ($imageFile instanceof \TYPO3\CMS\Core\Resource\File) {
1460 $file = $imageFile;
1461 } elseif ($imageFile instanceof \TYPO3\CMS\Core\Resource\FileReference) {
1462 $file = $imageFile->getOriginalFile();
1463 } else {
1464 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($imageFile)) {
1465 $file = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFileObject((int)$imageFile);
1466 } else {
1467 $file = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFileObjectFromCombinedIdentifier($imageFile);
1468 }
1469 }
1470
1471 // Create imageFileLink if not created with typolink
1472 if ($content == $string) {
1473 $parameterNames = array('width', 'height', 'effects', 'bodyTag', 'title', 'wrap');
1474 $parameters = array();
1475 $sample = isset($conf['sample.']) ? $this->stdWrap($conf['sample'], $conf['sample.']) : $conf['sample'];
1476 if ($sample) {
1477 $parameters['sample'] = 1;
1478 }
1479 foreach ($parameterNames as $parameterName) {
1480 if (isset($conf[$parameterName . '.'])) {
1481 $conf[$parameterName] = $this->stdWrap($conf[$parameterName], $conf[$parameterName . '.']);
1482 }
1483 if (isset($conf[$parameterName]) && $conf[$parameterName]) {
1484 $parameters[$parameterName] = $conf[$parameterName];
1485 }
1486 }
1487 $parametersEncoded = base64_encode(serialize($parameters));
1488 $hmac = GeneralUtility::hmac(implode('|', array($file->getUid(), $parametersEncoded)));
1489 $params = '&md5=' . $hmac;
1490 foreach (str_split($parametersEncoded, 64) as $index => $chunk) {
1491 $params .= '&parameters' . rawurlencode('[') . $index . rawurlencode(']') . '=' . rawurlencode($chunk);
1492 }
1493 $url = $GLOBALS['TSFE']->absRefPrefix . 'index.php?eID=tx_cms_showpic&file=' . $file->getUid() . $params;
1494 $directImageLink = isset($conf['directImageLink.']) ? $this->stdWrap($conf['directImageLink'], $conf['directImageLink.']) : $conf['directImageLink'];
1495 if ($directImageLink) {
1496 $imgResourceConf = array(
1497 'file' => $imageFile,
1498 'file.' => $conf
1499 );
1500 $url = $this->IMG_RESOURCE($imgResourceConf);
1501 if (!$url) {
1502 // If no imagemagick / gm is available
1503 $url = $imageFile;
1504 }
1505 }
1506 // Create TARGET-attribute only if the right doctype is used
1507 if (!GeneralUtility::inList('xhtml_strict,xhtml_11,xhtml_2', $GLOBALS['TSFE']->xhtmlDoctype)) {
1508 $target = isset($conf['target.']) ? $this->stdWrap($conf['target'], $conf['target.']) : $conf['target'];
1509 if ($target) {
1510 $target = sprintf(' target="%s"', $target);
1511 } else {
1512 $target = ' target="thePicture"';
1513 }
1514 } else {
1515 $target = '';
1516 }
1517 $conf['JSwindow'] = isset($conf['JSwindow.']) ? $this->stdWrap($conf['JSwindow'], $conf['JSwindow.']) : $conf['JSwindow'];
1518 if ($conf['JSwindow']) {
1519 if ($conf['JSwindow.']['altUrl'] || $conf['JSwindow.']['altUrl.']) {
1520 $altUrl = isset($conf['JSwindow.']['altUrl.']) ? $this->stdWrap($conf['JSwindow.']['altUrl'], $conf['JSwindow.']['altUrl.']) : $conf['JSwindow.']['altUrl'];
1521 if ($altUrl) {
1522 $url = $altUrl . ($conf['JSwindow.']['altUrl_noDefaultParams'] ? '' : '?file=' . rawurlencode($imageFile) . $params);
1523 }
1524 }
1525
1526 $processedFile = $file->process('Image.CropScaleMask', $conf);
1527 $JSwindowExpand = isset($conf['JSwindow.']['expand.']) ? $this->stdWrap($conf['JSwindow.']['expand'], $conf['JSwindow.']['expand.']) : $conf['JSwindow.']['expand'];
1528 $offset = GeneralUtility::intExplode(',', $JSwindowExpand . ',');
1529 $newWindow = isset($conf['JSwindow.']['newWindow.']) ? $this->stdWrap($conf['JSwindow.']['newWindow'], $conf['JSwindow.']['newWindow.']) : $conf['JSwindow.']['newWindow'];
1530 $a1 = '<a href="' . htmlspecialchars($url) . '" onclick="' . htmlspecialchars(('openPic(\'' . $GLOBALS['TSFE']->baseUrlWrap($url) . '\',\'' . ($newWindow ? md5($url) : 'thePicture') . '\',\'width=' . ($processedFile->getProperty('width') + $offset[0]) . ',height=' . ($processedFile->getProperty('height') + $offset[1]) . ',status=0,menubar=0\'); return false;')) . '"' . $target . $GLOBALS['TSFE']->ATagParams . '>';
1531 $a2 = '</a>';
1532 $GLOBALS['TSFE']->setJS('openPic');
1533 } else {
1534 $conf['linkParams.']['parameter'] = $url;
1535 $string = $this->typoLink($string, $conf['linkParams.']);
1536 }
1537 if (isset($conf['stdWrap.'])) {
1538 $string = $this->stdWrap($string, $conf['stdWrap.']);
1539 }
1540 $content = $a1 . $string . $a2;
1541 }
1542 }
1543 return $content;
1544 }
1545
1546 /**
1547 * Returns content of a file. If it's an image the content of the file is not returned but rather an image tag is.
1548 *
1549 * @param string $fName The filename, being a TypoScript resource data type
1550 * @param string $addParams Additional parameters (attributes). Default is empty alt and title tags.
1551 * @return string If jpg,gif,jpeg,png: returns image_tag with picture in. If html,txt: returns content string
1552 * @see FILE()
1553 * @todo Define visibility
1554 */
1555 public function fileResource($fName, $addParams = 'alt="" title=""') {
1556 $incFile = $GLOBALS['TSFE']->tmpl->getFileName($fName);
1557 if ($incFile) {
1558 $fileinfo = GeneralUtility::split_fileref($incFile);
1559 if (GeneralUtility::inList('jpg,gif,jpeg,png', $fileinfo['fileext'])) {
1560 $imgFile = $incFile;
1561 $imgInfo = @getImageSize($imgFile);
1562 return '<img src="' . $GLOBALS['TSFE']->absRefPrefix . $imgFile . '" width="' . $imgInfo[0] . '" height="' . $imgInfo[1] . '"' . $this->getBorderAttr(' border="0"') . ' ' . $addParams . ' />';
1563 } elseif (filesize($incFile) < 1024 * 1024) {
1564 return $GLOBALS['TSFE']->tmpl->fileContent($incFile);
1565 }
1566 }
1567 }
1568
1569 /**
1570 * Sets the SYS_LASTCHANGED timestamp if input timestamp is larger than current value.
1571 * The SYS_LASTCHANGED timestamp can be used by various caching/indexing applications to determine if the page has new content.
1572 * Therefore you should call this function with the last-changed timestamp of any element you display.
1573 *
1574 * @param integer $tstamp Unix timestamp (number of seconds since 1970)
1575 * @return void
1576 * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::setSysLastChanged()
1577 * @todo Define visibility
1578 */
1579 public function lastChanged($tstamp) {
1580 $tstamp = (int)$tstamp;
1581 if ($tstamp > (int)$GLOBALS['TSFE']->register['SYS_LASTCHANGED']) {
1582 $GLOBALS['TSFE']->register['SYS_LASTCHANGED'] = $tstamp;
1583 }
1584 }
1585
1586 /**
1587 * Wraps the input string by the $wrap value and implements the "linkWrap" data type as well.
1588 * The "linkWrap" data type means that this function will find any integer encapsulated in {} (curly braces) in the first wrap part and substitute it with the corresponding page uid from the rootline where the found integer is pointing to the key in the rootline. See link below.
1589 *
1590 * @param string $content Input string
1591 * @param string $wrap A string where the first two parts separated by "|" (vertical line) will be wrapped around the input string
1592 * @return string Wrapped output string
1593 * @see wrap(), cImage(), FILE()
1594 * @todo Define visibility
1595 */
1596 public function linkWrap($content, $wrap) {
1597 $wrapArr = explode('|', $wrap);
1598 if (preg_match('/\\{([0-9]*)\\}/', $wrapArr[0], $reg)) {
1599 if ($uid = $GLOBALS['TSFE']->tmpl->rootLine[$reg[1]]['uid']) {
1600 $wrapArr[0] = str_replace($reg[0], $uid, $wrapArr[0]);
1601 }
1602 }
1603 return trim($wrapArr[0]) . $content . trim($wrapArr[1]);
1604 }
1605
1606 /**
1607 * An abstraction method which creates an alt or title parameter for an HTML img, applet, area or input element and the FILE content element.
1608 * From the $conf array it implements the properties "altText", "titleText" and "longdescURL"
1609 *
1610 * @param array $conf TypoScript configuration properties
1611 * @param boolean $longDesc If set, the longdesc attribute will be generated - must only be used for img elements!
1612 * @return string Parameter string containing alt and title parameters (if any)
1613 * @see IMGTEXT(), FILE(), FORM(), cImage(), filelink()
1614 * @todo Define visibility
1615 */
1616 public function getAltParam($conf, $longDesc = TRUE) {
1617 $altText = isset($conf['altText.']) ? trim($this->stdWrap($conf['altText'], $conf['altText.'])) : trim($conf['altText']);
1618 $titleText = isset($conf['titleText.']) ? trim($this->stdWrap($conf['titleText'], $conf['titleText.'])) : trim($conf['titleText']);
1619 if (isset($conf['longdescURL.']) && $GLOBALS['TSFE']->config['config']['doctype'] != 'html5') {
1620 $longDesc = $this->typoLink_URL($conf['longdescURL.']);
1621 } else {
1622 $longDesc = trim($conf['longdescURL']);
1623 }
1624 // "alt":
1625 $altParam = ' alt="' . htmlspecialchars($altText) . '"';
1626 // "title":
1627 $emptyTitleHandling = 'useAlt';
1628 $emptyTitleHandling = isset($conf['emptyTitleHandling.']) ? $this->stdWrap($conf['emptyTitleHandling'], $conf['emptyTitleHandling.']) : $conf['emptyTitleHandling'];
1629 // Choices: 'keepEmpty' | 'useAlt' | 'removeAttr'
1630 if ($titleText || $emptyTitleHandling == 'keepEmpty') {
1631 $altParam .= ' title="' . htmlspecialchars($titleText) . '"';
1632 } elseif (!$titleText && $emptyTitleHandling == 'useAlt') {
1633 $altParam .= ' title="' . htmlspecialchars($altText) . '"';
1634 }
1635 // "longDesc" URL
1636 if ($longDesc) {
1637 $altParam .= ' longdesc="' . htmlspecialchars(strip_tags($longDesc)) . '"';
1638 }
1639 return $altParam;
1640 }
1641
1642 /**
1643 * Removes forbidden characters and spaces from name/id attributes in the form tag and formfields
1644 *
1645 * @param string $name Input string
1646 * @return string the cleaned string
1647 * @see FORM()
1648 * @todo Define visibility
1649 */
1650 public function cleanFormName($name) {
1651 // Turn data[x][y] into data:x:y:
1652 $name = preg_replace('/\\[|\\]\\[?/', ':', trim($name));
1653 // Remove illegal chars like _
1654 return preg_replace('#[^:a-zA-Z0-9]#', '', $name);
1655 }
1656
1657 /**
1658 * An abstraction method to add parameters to an A tag.
1659 * Uses the ATagParams property.
1660 *
1661 * @param array $conf TypoScript configuration properties
1662 * @param boolean $addGlobal If set, will add the global config.ATagParams to the link
1663 * @return string String containing the parameters to the A tag (if non empty, with a leading space)
1664 * @see IMGTEXT(), filelink(), makelinks(), typolink()
1665 * @todo Define visibility
1666 */
1667 public function getATagParams($conf, $addGlobal = 1) {
1668 $aTagParams = '';
1669 if ($conf['ATagParams.']) {
1670 $aTagParams = ' ' . $this->stdWrap($conf['ATagParams'], $conf['ATagParams.']);
1671 } elseif ($conf['ATagParams']) {
1672 $aTagParams = ' ' . $conf['ATagParams'];
1673 }
1674 if ($addGlobal) {
1675 $aTagParams = ' ' . trim(($GLOBALS['TSFE']->ATagParams . $aTagParams));
1676 }
1677 // Extend params
1678 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getATagParamsPostProc']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getATagParamsPostProc'])) {
1679 $_params = array(
1680 'conf' => &$conf,
1681 'aTagParams' => &$aTagParams
1682 );
1683 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getATagParamsPostProc'] as $objRef) {
1684 $processor =& GeneralUtility::getUserObj($objRef);
1685 $aTagParams = $processor->process($_params, $this);
1686 }
1687 }
1688
1689 $aTagParams = trim($aTagParams);
1690 if (!empty($aTagParams)) {
1691 $aTagParams = ' ' . $aTagParams;
1692 }
1693
1694 return $aTagParams;
1695 }
1696
1697 /**
1698 * All extension links should ask this function for additional properties to their tags.
1699 * Designed to add for instance an "onclick" property for site tracking systems.
1700 *
1701 * @param string $URL URL of the website
1702 * @param string $TYPE
1703 * @return string The additional tag properties
1704 * @todo Define visibility
1705 */
1706 public function extLinkATagParams($URL, $TYPE) {
1707 $out = '';
1708 if ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['extLinkATagParamsHandler']) {
1709 $extLinkATagParamsHandler = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['extLinkATagParamsHandler']);
1710 if (method_exists($extLinkATagParamsHandler, 'main')) {
1711 $out .= trim($extLinkATagParamsHandler->main($URL, $TYPE, $this));
1712 }
1713 }
1714 return trim($out) ? ' ' . trim($out) : '';
1715 }
1716
1717 /***********************************************
1718 *
1719 * HTML template processing functions
1720 *
1721 ***********************************************/
1722 /**
1723 * Returns a subpart from the input content stream.
1724 * A subpart is a part of the input stream which is encapsulated in a
1725 * string matching the input string, $marker. If this string is found
1726 * inside of HTML comment tags the start/end points of the content block
1727 * returned will be that right outside that comment block.
1728 * Example: The contennt string is
1729 * "Hello <!--###sub1### begin--> World. How are <!--###sub1### end--> you?"
1730 * If $marker is "###sub1###" then the content returned is
1731 * " World. How are ". The input content string could just as well have
1732 * been "Hello ###sub1### World. How are ###sub1### you?" and the result
1733 * would be the same
1734 * Wrapper for \TYPO3\CMS\Core\Html\HtmlParser::getSubpart which behaves identical
1735 *
1736 * @param string $content The content stream, typically HTML template content.
1737 * @param string $marker The marker string, typically on the form "###[the marker string]###
1738 * @return string The subpart found, if found.
1739 */
1740 public function getSubpart($content, $marker) {
1741 return \TYPO3\CMS\Core\Html\HtmlParser::getSubpart($content, $marker);
1742 }
1743
1744 /**
1745 * Substitute subpart in input template stream.
1746 * This function substitutes a subpart in $content with the content of
1747 * $subpartContent.
1748 * Wrapper for \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart which behaves identical
1749 *
1750 * @param string $content The content stream, typically HTML template content.
1751 * @param string $marker The marker string, typically on the form "###[the marker string]###
1752 * @param mixed $subpartContent The content to insert instead of the subpart found. If a string, then just plain substitution happens (includes removing the HTML comments of the subpart if found). If $subpartContent happens to be an array, it's [0] and [1] elements are wrapped around the EXISTING content of the subpart (fetched by getSubpart()) thereby not removing the original content.
1753 * @param boolean $recursive If $recursive is set, the function calls itself with the content set to the remaining part of the content after the second marker. This means that proceding subparts are ALSO substituted!
1754 * @return string The processed HTML content string.
1755 */
1756 public function substituteSubpart($content, $marker, $subpartContent, $recursive = 1) {
1757 return \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpart($content, $marker, $subpartContent, $recursive);
1758 }
1759
1760 /**
1761 * Substitues multiple subparts at once
1762 *
1763 * @param string $content The content stream, typically HTML template content.
1764 * @param array $subpartsContent The array of key/value pairs being subpart/content values used in the substitution. For each element in this array the function will substitute a subpart in the content stream with the content.
1765 * @return string The processed HTML content string.
1766 */
1767 public function substituteSubpartArray($content, array $subpartsContent) {
1768 return \TYPO3\CMS\Core\Html\HtmlParser::substituteSubpartArray($content, $subpartsContent);
1769 }
1770
1771 /**
1772 * Substitutes a marker string in the input content
1773 * (by a simple str_replace())
1774 *
1775 * @param string $content The content stream, typically HTML template content.
1776 * @param string $marker The marker string, typically on the form "###[the marker string]###
1777 * @param mixed $markContent The content to insert instead of the marker string found.
1778 * @return string The processed HTML content string.
1779 * @see substituteSubpart()
1780 */
1781 public function substituteMarker($content, $marker, $markContent) {
1782 return \TYPO3\CMS\Core\Html\HtmlParser::substituteMarker($content, $marker, $markContent);
1783 }
1784
1785 /**
1786 * Multi substitution function with caching.
1787 *
1788 * This function should be a one-stop substitution function for working
1789 * with HTML-template. It does not substitute by str_replace but by
1790 * splitting. This secures that the value inserted does not themselves
1791 * contain markers or subparts.
1792 *
1793 * Note that the "caching" won't cache the content of the substition,
1794 * but only the splitting of the template in various parts. So if you
1795 * want only one cache-entry per template, make sure you always pass the
1796 * exact same set of marker/subpart keys. Else you will be flooding the
1797 * users cache table.
1798 *
1799 * This function takes three kinds of substitutions in one:
1800 * $markContentArray is a regular marker-array where the 'keys' are
1801 * substituted in $content with their values
1802 *
1803 * $subpartContentArray works exactly like markContentArray only is whole
1804 * subparts substituted and not only a single marker.
1805 *
1806 * $wrappedSubpartContentArray is an array of arrays with 0/1 keys where
1807 * the subparts pointed to by the main key is wrapped with the 0/1 value
1808 * alternating.
1809 *
1810 * @param string $content The content stream, typically HTML template content.
1811 * @param array $markContentArray Regular marker-array where the 'keys' are substituted in $content with their values
1812 * @param array $subpartContentArray Exactly like markContentArray only is whole subparts substituted and not only a single marker.
1813 * @param array $wrappedSubpartContentArray An array of arrays with 0/1 keys where the subparts pointed to by the main key is wrapped with the 0/1 value alternating.
1814 * @return string The output content stream
1815 * @see substituteSubpart(), substituteMarker(), substituteMarkerInObject(), TEMPLATE()
1816 */
1817 public function substituteMarkerArrayCached($content, array $markContentArray = NULL, array $subpartContentArray = NULL, array $wrappedSubpartContentArray = NULL) {
1818 $GLOBALS['TT']->push('substituteMarkerArrayCached');
1819 // If not arrays then set them
1820 if (is_null($markContentArray)) {
1821 // Plain markers
1822 $markContentArray = array();
1823 }
1824 if (is_null($subpartContentArray)) {
1825 // Subparts being directly substituted
1826 $subpartContentArray = array();
1827 }
1828 if (is_null($wrappedSubpartContentArray)) {
1829 // Subparts being wrapped
1830 $wrappedSubpartContentArray = array();
1831 }
1832 // Finding keys and check hash:
1833 $sPkeys = array_keys($subpartContentArray);
1834 $wPkeys = array_keys($wrappedSubpartContentArray);
1835 $aKeys = array_merge(array_keys($markContentArray), $sPkeys, $wPkeys);
1836 if (!count($aKeys)) {
1837 $GLOBALS['TT']->pull();
1838 return $content;
1839 }
1840 asort($aKeys);
1841 $storeKey = md5('substituteMarkerArrayCached_storeKey:' . serialize(array(
1842 $content,
1843 $aKeys
1844 )));
1845 if ($this->substMarkerCache[$storeKey]) {
1846 $storeArr = $this->substMarkerCache[$storeKey];
1847 $GLOBALS['TT']->setTSlogMessage('Cached', 0);
1848 } else {
1849 $storeArrDat = $GLOBALS['TSFE']->sys_page->getHash($storeKey);
1850 if (is_array($storeArrDat)) {
1851 $storeArr = $storeArrDat;
1852 // Setting cache:
1853 $this->substMarkerCache[$storeKey] = $storeArr;
1854 $GLOBALS['TT']->setTSlogMessage('Cached from DB', 0);
1855 } else {
1856 // Initialize storeArr
1857 $storeArr = array();
1858 // Finding subparts and substituting them with the subpart as a marker
1859 foreach ($sPkeys as $sPK) {
1860 $content = $this->substituteSubpart($content, $sPK, $sPK);
1861 }
1862 // Finding subparts and wrapping them with markers
1863 foreach ($wPkeys as $wPK) {
1864 $content = $this->substituteSubpart($content, $wPK, array(
1865 $wPK,
1866 $wPK
1867 ));
1868 }
1869 // Traverse keys and quote them for reg ex.
1870 foreach ($aKeys as $tK => $tV) {
1871 $aKeys[$tK] = preg_quote($tV, '/');
1872 }
1873 $regex = '/' . implode('|', $aKeys) . '/';
1874 // Doing regex's
1875 $storeArr['c'] = preg_split($regex, $content);
1876 preg_match_all($regex, $content, $keyList);
1877 $storeArr['k'] = $keyList[0];
1878 // Setting cache:
1879 $this->substMarkerCache[$storeKey] = $storeArr;
1880 // Storing the cached data:
1881 $GLOBALS['TSFE']->sys_page->storeHash($storeKey, $storeArr, 'substMarkArrayCached');
1882 $GLOBALS['TT']->setTSlogMessage('Parsing', 0);
1883 }
1884 }
1885 // Substitution/Merging:
1886 // Merging content types together, resetting
1887 $valueArr = array_merge($markContentArray, $subpartContentArray, $wrappedSubpartContentArray);
1888 $wSCA_reg = array();
1889 $content = '';
1890 // Traversing the keyList array and merging the static and dynamic content
1891 foreach ($storeArr['k'] as $n => $keyN) {
1892 $content .= $storeArr['c'][$n];
1893 if (!is_array($valueArr[$keyN])) {
1894 $content .= $valueArr[$keyN];
1895 } else {
1896 $content .= $valueArr[$keyN][(int)$wSCA_reg[$keyN] % 2];
1897 $wSCA_reg[$keyN]++;
1898 }
1899 }
1900 $content .= $storeArr['c'][count($storeArr['k'])];
1901 $GLOBALS['TT']->pull();
1902 return $content;
1903 }
1904
1905 /**
1906 * Traverses the input $markContentArray array and for each key the marker
1907 * by the same name (possibly wrapped and in upper case) will be
1908 * substituted with the keys value in the array.
1909 *
1910 * This is very useful if you have a data-record to substitute in some
1911 * content. In particular when you use the $wrap and $uppercase values to
1912 * pre-process the markers. Eg. a key name like "myfield" could effectively
1913 * be represented by the marker "###MYFIELD###" if the wrap value
1914 * was "###|###" and the $uppercase boolean TRUE.
1915 *
1916 * @param string $content The content stream, typically HTML template content.
1917 * @param array $markContentArray The array of key/value pairs being marker/content values used in the substitution. For each element in this array the function will substitute a marker in the content stream with the content.
1918 * @param string $wrap A wrap value - [part 1] | [part 2] - for the markers before substitution
1919 * @param boolean $uppercase If set, all marker string substitution is done with upper-case markers.
1920 * @param boolean $deleteUnused If set, all unused marker are deleted.
1921 * @return string The processed output stream
1922 * @see substituteMarker(), substituteMarkerInObject(), TEMPLATE()
1923 */
1924 public function substituteMarkerArray($content, array $markContentArray, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
1925 return \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerArray($content, $markContentArray, $wrap, $uppercase, $deleteUnused);
1926 }
1927
1928 /**
1929 * Substitute marker array in an array of values
1930 *
1931 * @param mixed $tree If string, then it just calls substituteMarkerArray. If array(and even multi-dim) then for each key/value pair the marker array will be substituted (by calling this function recursively)
1932 * @param array $markContentArray The array of key/value pairs being marker/content values used in the substitution. For each element in this array the function will substitute a marker in the content string/array values.
1933 * @return mixed The processed input variable.
1934 * @see substituteMarker()
1935 */
1936 public function substituteMarkerInObject(&$tree, array $markContentArray) {
1937 if (is_array($tree)) {
1938 foreach ($tree as $key => $value) {
1939 $this->substituteMarkerInObject($tree[$key], $markContentArray);
1940 }
1941 } else {
1942 $tree = $this->substituteMarkerArray($tree, $markContentArray);
1943 }
1944 return $tree;
1945 }
1946
1947 /**
1948 * Replaces all markers and subparts in a template with the content provided in the structured array.
1949 *
1950 * @param string $content
1951 * @param array $markersAndSubparts
1952 * @param string $wrap
1953 * @param boolean $uppercase
1954 * @param boolean $deleteUnused
1955 * @return string
1956 */
1957 public function substituteMarkerAndSubpartArrayRecursive($content, array $markersAndSubparts, $wrap = '', $uppercase = FALSE, $deleteUnused = FALSE) {
1958 return \TYPO3\CMS\Core\Html\HtmlParser::substituteMarkerAndSubpartArrayRecursive($content, $markersAndSubparts, $wrap, $uppercase, $deleteUnused);
1959 }
1960
1961 /**
1962 * Adds elements to the input $markContentArray based on the values from
1963 * the fields from $fieldList found in $row
1964 *
1965 * @param array $markContentArray Array with key/values being marker-strings/substitution values.
1966 * @param array $row An array with keys found in the $fieldList (typically a record) which values should be moved to the $markContentArray
1967 * @param string $fieldList A list of fields from the $row array to add to the $markContentArray array. If empty all fields from $row will be added (unless they are integers)
1968 * @param boolean $nl2br If set, all values added to $markContentArray will be nl2br()'ed
1969 * @param string $prefix Prefix string to the fieldname before it is added as a key in the $markContentArray. Notice that the keys added to the $markContentArray always start and end with "###
1970 * @param boolean $HSC If set, all values are passed through htmlspecialchars() - RECOMMENDED to avoid most obvious XSS and maintain XHTML compliance.
1971 * @return array The modified $markContentArray
1972 */
1973 public function fillInMarkerArray(array $markContentArray, array $row, $fieldList = '', $nl2br = TRUE, $prefix = 'FIELD_', $HSC = FALSE) {
1974 if ($fieldList) {
1975 $fArr = GeneralUtility::trimExplode(',', $fieldList, TRUE);
1976 foreach ($fArr as $field) {
1977 $markContentArray['###' . $prefix . $field . '###'] = $nl2br ? nl2br($row[$field], !empty($GLOBALS['TSFE']->xhtmlDoctype)) : $row[$field];
1978 }
1979 } else {
1980 if (is_array($row)) {
1981 foreach ($row as $field => $value) {
1982 if (!\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($field)) {
1983 if ($HSC) {
1984 $value = htmlspecialchars($value);
1985 }
1986 $markContentArray['###' . $prefix . $field . '###'] = $nl2br ? nl2br($value, !empty($GLOBALS['TSFE']->xhtmlDoctype)) : $value;
1987 }
1988 }
1989 }
1990 }
1991 return $markContentArray;
1992 }
1993
1994 /**
1995 * Sets the current file object during iterations over files.
1996 *
1997 * @param \TYPO3\CMS\Core\Resource\File $fileObject The file object.
1998 */
1999 public function setCurrentFile($fileObject) {
2000 $this->currentFile = $fileObject;
2001 }
2002
2003 /**
2004 * Gets the current file object during iterations over files.
2005 *
2006 * @return \TYPO3\CMS\Core\Resource\File The current file object.
2007 */
2008 public function getCurrentFile() {
2009 return $this->currentFile;
2010 }
2011
2012 /***********************************************
2013 *
2014 * "stdWrap" + sub functions
2015 *
2016 ***********************************************/
2017 /**
2018 * The "stdWrap" function. This is the implementation of what is known as "stdWrap properties" in TypoScript.
2019 * Basically "stdWrap" performs some processing of a value based on properties in the input $conf array(holding the TypoScript "stdWrap properties")
2020 * See the link below for a complete list of properties and what they do. The order of the table with properties found in TSref (the link) follows the actual order of implementation in this function.
2021 *
2022 * If $this->alternativeData is an array it's used instead of the $this->data array in ->getData
2023 *
2024 * @param string $content Input value undergoing processing in this function. Possibly substituted by other values fetched from another source.
2025 * @param array $conf TypoScript "stdWrap properties".
2026 * @return string The processed input value
2027 */
2028 public function stdWrap($content = '', $conf = array()) {
2029 // If there is any hook object, activate all of the process and override functions.
2030 // The hook interface ContentObjectStdWrapHookInterface takes care that all 4 methods exist.
2031 if ($this->stdWrapHookObjects) {
2032 $conf['stdWrapPreProcess'] = 1;
2033 $conf['stdWrapOverride'] = 1;
2034 $conf['stdWrapProcess'] = 1;
2035 $conf['stdWrapPostProcess'] = 1;
2036 }
2037
2038 if (!is_array($conf) || !$conf) {
2039 return $content;
2040 }
2041
2042 // Cache handling
2043 if (is_array($conf['cache.'])) {
2044 $conf['cache.']['key'] = $this->stdWrap($conf['cache.']['key'], $conf['cache.']['key.']);
2045 $conf['cache.']['tags'] = $this->stdWrap($conf['cache.']['tags'], $conf['cache.']['tags.']);
2046 $conf['cache.']['lifetime'] = $this->stdWrap($conf['cache.']['lifetime'], $conf['cache.']['lifetime.']);
2047 $conf['cacheRead'] = 1;
2048 $conf['cacheStore'] = 1;
2049 }
2050 // Check, which of the available stdWrap functions is needed for the current conf Array
2051 // and keep only those but still in the same order
2052 $sortedConf = array_intersect_key($this->stdWrapOrder, $conf);
2053 // Functions types that should not make use of nested stdWrap function calls to avoid conflicts with internal TypoScript used by these functions
2054 $stdWrapDisabledFunctionTypes = 'cObject,functionName,stdWrap';
2055 // Additional Array to check whether a function has already been executed
2056 $isExecuted = array();
2057 // Additional switch to make sure 'required', 'if' and 'fieldRequired'
2058 // will still stop rendering immediately in case they return FALSE
2059 $this->stdWrapRecursionLevel++;
2060 $this->stopRendering[$this->stdWrapRecursionLevel] = FALSE;
2061 // execute each function in the predefined order
2062 foreach ($sortedConf as $stdWrapName => $functionType) {
2063 // eliminate the second key of a pair 'key'|'key.' to make sure functions get called only once and check if rendering has been stopped
2064 if (!$isExecuted[$stdWrapName] && !$this->stopRendering[$this->stdWrapRecursionLevel]) {
2065 $functionName = rtrim($stdWrapName, '.');
2066 $functionProperties = $functionName . '.';
2067 // If there is any code one the next level, check if it contains "official" stdWrap functions
2068 // if yes, execute them first - will make each function stdWrap aware
2069 // so additional stdWrap calls within the functions can be removed, since the result will be the same
2070 // exception: the recursive stdWrap function and cObject will still be using their own stdWrap call, since it modifies the content and not a property
2071 if (count($conf[$functionProperties]) && !GeneralUtility::inList($stdWrapDisabledFunctionTypes, $functionType)) {
2072 if (array_intersect_key($this->stdWrapOrder, $conf[$functionProperties])) {
2073 $conf[$functionName] = $this->stdWrap($conf[$functionName], $conf[$functionProperties]);
2074 }
2075 }
2076 // Get just that part of $conf that is needed for the particular function
2077 $singleConf = array(
2078 $functionName => $conf[$functionName],
2079 $functionProperties => $conf[$functionProperties]
2080 );
2081 // In this special case 'spaceBefore' and 'spaceAfter' need additional stuff from 'space.''
2082 if ($functionName == 'spaceBefore' || $functionName == 'spaceAfter') {
2083 $singleConf['space.'] = $conf['space.'];
2084 }
2085 // Hand over the whole $conf array to the stdWrapHookObjects
2086 if ($functionType === 'hook') {
2087 $singleConf = $conf;
2088 }
2089 // Check if key is still containing something, since it might have been changed by next level stdWrap before
2090 if ((isset($conf[$functionName]) || $conf[$functionProperties]) && !($functionType == 'boolean' && !$conf[$functionName])) {
2091 // Add both keys - with and without the dot - to the set of executed functions
2092 $isExecuted[$functionName] = TRUE;
2093 $isExecuted[$functionProperties] = TRUE;
2094 // Call the function with the prefix stdWrap_ to make sure nobody can execute functions just by adding their name to the TS Array
2095 $functionName = 'stdWrap_' . $functionName;
2096 $content = $this->{$functionName}($content, $singleConf);
2097 } elseif ($functionType == 'boolean' && !$conf[$functionName]) {
2098 $isExecuted[$functionName] = TRUE;
2099 $isExecuted[$functionProperties] = TRUE;
2100 }
2101 }
2102 }
2103 unset($this->stopRendering[$this->stdWrapRecursionLevel]);
2104 $this->stdWrapRecursionLevel--;
2105
2106 return $content;
2107 }
2108
2109 /**
2110 * Gets a configuration value by passing them through stdWrap first and taking a default value if stdWrap doesn't yield a result.
2111 *
2112 * @param string $key The config variable key (from TS array).
2113 * @param array $config The TypoScript array.
2114 * @param string $defaultValue Optional default value.
2115 * @return string Value of the config variable
2116 */
2117 public function stdWrapValue($key, array $config, $defaultValue = '') {
2118 if (isset($config[$key])) {
2119 if (!isset($config[$key . '.'])) {
2120 return $config[$key];
2121 }
2122 } elseif (isset($config[$key . '.'])) {
2123 $config[$key] = '';
2124 } else {
2125 return $defaultValue;
2126 }
2127 $stdWrapped = $this->stdWrap($config[$key], $config[$key . '.']);
2128 return $stdWrapped ?: $defaultValue;
2129 }
2130
2131 /**
2132 * stdWrap pre process hook
2133 * can be used by extensions authors to modify the behaviour of stdWrap functions to their needs
2134 * this hook will execute functions before any other stdWrap function can modify anything
2135 *
2136 * @param string $content Input value undergoing processing in these functions.
2137 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2138 * @return string The processed input value
2139 */
2140 public function stdWrap_stdWrapPreProcess($content = '', $conf = array()) {
2141 foreach ($this->stdWrapHookObjects as $hookObject) {
2142 $content = $hookObject->stdWrapPreProcess($content, $conf, $this);
2143 }
2144 return $content;
2145 }
2146
2147 /**
2148 * Check if content was cached before (depending on the given cache key)
2149 *
2150 * @param string $content Input value undergoing processing in these functions.
2151 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2152 * @return string The processed input value
2153 */
2154 public function stdWrap_cacheRead($content = '', $conf = array()) {
2155 if (!empty($conf['cache.']['key'])) {
2156 /** @var $cacheFrontend \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend */
2157 $cacheFrontend = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('cache_hash');
2158 if ($cacheFrontend && $cacheFrontend->has($conf['cache.']['key'])) {
2159 $content = $cacheFrontend->get($conf['cache.']['key']);
2160 $this->stopRendering[$this->stdWrapRecursionLevel] = TRUE;
2161 }
2162 }
2163 return $content;
2164 }
2165
2166 /**
2167 * Add tags to page cache (comma-separated list)
2168 *
2169 * @param string $content Input value undergoing processing in these functions.
2170 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2171 * @return string The processed input value
2172 */
2173 public function stdWrap_addPageCacheTags($content = '', $conf = array()) {
2174 $tags = isset($conf['addPageCacheTags.'])
2175 ? $this->stdWrap($conf['addPageCacheTags'], $conf['addPageCacheTags.'])
2176 : $conf['addPageCacheTags'];
2177 if (!empty($tags)) {
2178 $cacheTags = GeneralUtility::trimExplode(',', $tags, TRUE);
2179 $GLOBALS['TSFE']->addCacheTags($cacheTags);
2180 }
2181 return $content;
2182 }
2183
2184 /**
2185 * setContentToCurrent
2186 * actually it just does the contrary: Sets the value of 'current' based on current content
2187 *
2188 * @param string $content Input value undergoing processing in this function.
2189 * @param array $conf stdWrap properties for setContentToCurrent.
2190 * @return string The processed input value
2191 */
2192 public function stdWrap_setContentToCurrent($content = '', $conf = array()) {
2193 $this->data[$this->currentValKey] = $content;
2194 return $content;
2195 }
2196
2197 /**
2198 * setCurrent
2199 * Sets the value of 'current' based on the outcome of stdWrap operations
2200 *
2201 * @param string $content Input value undergoing processing in this function.
2202 * @param array $conf stdWrap properties for setCurrent.
2203 * @return string The processed input value
2204 */
2205 public function stdWrap_setCurrent($content = '', $conf = array()) {
2206 $this->data[$this->currentValKey] = $conf['setCurrent'];
2207 return $content;
2208 }
2209
2210 /**
2211 * lang
2212 * Translates content based on the language currently used by the FE
2213 *
2214 * @param string $content Input value undergoing processing in this function.
2215 * @param array $conf stdWrap properties for lang.
2216 * @return string The processed input value
2217 */
2218 public function stdWrap_lang($content = '', $conf = array()) {
2219 if (isset($conf['lang.']) && $GLOBALS['TSFE']->config['config']['language'] && isset($conf['lang.'][$GLOBALS['TSFE']->config['config']['language']])) {
2220 $content = $conf['lang.'][$GLOBALS['TSFE']->config['config']['language']];
2221 }
2222 return $content;
2223 }
2224
2225 /**
2226 * data
2227 * Gets content from different sources based on getText functions, makes use of alternativeData, when set
2228 *
2229 * @param string $content Input value undergoing processing in this function.
2230 * @param array $conf stdWrap properties for data.
2231 * @return string The processed input value
2232 */
2233 public function stdWrap_data($content = '', $conf = array()) {
2234 $content = $this->getData($conf['data'], is_array($this->alternativeData) ? $this->alternativeData : $this->data);
2235 // This must be unset directly after
2236 $this->alternativeData = '';
2237 return $content;
2238 }
2239
2240 /**
2241 * field
2242 * Gets content from a DB field
2243 *
2244 * @param string $content Input value undergoing processing in this function.
2245 * @param array $conf stdWrap properties for field.
2246 * @return string The processed input value
2247 */
2248 public function stdWrap_field($content = '', $conf = array()) {
2249 return $this->getFieldVal($conf['field']);
2250 }
2251
2252 /**
2253 * current
2254 * Gets content that has been perviously set as 'current'
2255 * Can be set via setContentToCurrent or setCurrent or will be set automatically i.e. inside the split function
2256 *
2257 * @param string $content Input value undergoing processing in this function.
2258 * @param array $conf stdWrap properties for current.
2259 * @return string The processed input value
2260 */
2261 public function stdWrap_current($content = '', $conf = array()) {
2262 return $this->data[$this->currentValKey];
2263 }
2264
2265 /**
2266 * cObject
2267 * Will replace the content with the value of a any official TypoScript cObject
2268 * like TEXT, COA, HMENU
2269 *
2270 * @param string $content Input value undergoing processing in this function.
2271 * @param array $conf stdWrap properties for cObject.
2272 * @return string The processed input value
2273 */
2274 public function stdWrap_cObject($content = '', $conf = array()) {
2275 return $this->cObjGetSingle($conf['cObject'], $conf['cObject.'], '/stdWrap/.cObject');
2276 }
2277
2278 /**
2279 * numRows
2280 * Counts the number of returned records of a DB operation
2281 * makes use of select internally
2282 *
2283 * @param string $content Input value undergoing processing in this function.
2284 * @param array $conf stdWrap properties for numRows.
2285 * @return string The processed input value
2286 */
2287 public function stdWrap_numRows($content = '', $conf = array()) {
2288 return $this->numRows($conf['numRows.']);
2289 }
2290
2291 /**
2292 * filelist
2293 * Will create a list of files based on some additional parameters
2294 *
2295 * @param string $content Input value undergoing processing in this function.
2296 * @param array $conf stdWrap properties for filelist.
2297 * @return string The processed input value
2298 */
2299 public function stdWrap_filelist($content = '', $conf = array()) {
2300 return $this->filelist($conf['filelist']);
2301 }
2302
2303 /**
2304 * preUserFunc
2305 * Will execute a user public function before the content will be modified by any other stdWrap function
2306 *
2307 * @param string $content Input value undergoing processing in this function.
2308 * @param array $conf stdWrap properties for preUserFunc.
2309 * @return string The processed input value
2310 */
2311 public function stdWrap_preUserFunc($content = '', $conf = array()) {
2312 return $this->callUserFunction($conf['preUserFunc'], $conf['preUserFunc.'], $content);
2313 }
2314
2315 /**
2316 * stdWrap override hook
2317 * can be used by extensions authors to modify the behaviour of stdWrap functions to their needs
2318 * this hook will execute functions on existing content but still before the content gets modified or replaced
2319 *
2320 * @param string $content Input value undergoing processing in these functions.
2321 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2322 * @return string The processed input value
2323 */
2324 public function stdWrap_stdWrapOverride($content = '', $conf = array()) {
2325 foreach ($this->stdWrapHookObjects as $hookObject) {
2326 $content = $hookObject->stdWrapOverride($content, $conf, $this);
2327 }
2328 return $content;
2329 }
2330
2331 /**
2332 * override
2333 * Will override the current value of content with its own value'
2334 *
2335 * @param string $content Input value undergoing processing in this function.
2336 * @param array $conf stdWrap properties for override.
2337 * @return string The processed input value
2338 */
2339 public function stdWrap_override($content = '', $conf = array()) {
2340 if (trim($conf['override'])) {
2341 $content = $conf['override'];
2342 }
2343 return $content;
2344 }
2345
2346 /**
2347 * preIfEmptyListNum
2348 * Gets a value off a CSV list before the following ifEmpty check
2349 * Makes sure that the result of ifEmpty will be TRUE in case the CSV does not contain a value at the position given by preIfEmptyListNum
2350 *
2351 * @param string $content Input value undergoing processing in this function.
2352 * @param array $conf stdWrap properties for preIfEmptyListNum.
2353 * @return string The processed input value
2354 */
2355 public function stdWrap_preIfEmptyListNum($content = '', $conf = array()) {
2356 return $this->listNum($content, $conf['preIfEmptyListNum'], $conf['preIfEmptyListNum.']['splitChar']);
2357 }
2358
2359 /**
2360 * ifNull
2361 * Will set content to a replacement value in case the value of content is NULL
2362 *
2363 * @param string|NULL $content Input value undergoing processing in this function.
2364 * @param array $conf stdWrap properties for ifNull.
2365 * @return string|NULL The processed input value
2366 */
2367 public function stdWrap_ifNull($content = '', $conf = array()) {
2368 if ($content === NULL) {
2369 $content = $conf['ifNull'];
2370 }
2371 return $content;
2372 }
2373
2374 /**
2375 * ifEmpty
2376 * Will set content to a replacement value in case the trimmed value of content returns FALSE
2377 * 0 (zero) will be replaced as well
2378 *
2379 * @param string $content Input value undergoing processing in this function.
2380 * @param array $conf stdWrap properties for ifEmpty.
2381 * @return string The processed input value
2382 */
2383 public function stdWrap_ifEmpty($content = '', $conf = array()) {
2384 if (!trim($content)) {
2385 $content = $conf['ifEmpty'];
2386 }
2387 return $content;
2388 }
2389
2390 /**
2391 * ifBlank
2392 * Will set content to a replacement value in case the trimmed value of content has no length
2393 * 0 (zero) will not be replaced
2394 *
2395 * @param string $content Input value undergoing processing in this function.
2396 * @param array $conf stdWrap properties for ifBlank.
2397 * @return string The processed input value
2398 */
2399 public function stdWrap_ifBlank($content = '', $conf = array()) {
2400 if (!strlen(trim($content))) {
2401 $content = $conf['ifBlank'];
2402 }
2403 return $content;
2404 }
2405
2406 /**
2407 * listNum
2408 * Gets a value off a CSV list after ifEmpty check
2409 * Might return an empty value in case the CSV does not contain a value at the position given by listNum
2410 * Use preIfEmptyListNum to avoid that behaviour
2411 *
2412 * @param string $content Input value undergoing processing in this function.
2413 * @param array $conf stdWrap properties for listNum.
2414 * @return string The processed input value
2415 */
2416 public function stdWrap_listNum($content = '', $conf = array()) {
2417 return $this->listNum($content, $conf['listNum'], $conf['listNum.']['splitChar']);
2418 }
2419
2420 /**
2421 * trim
2422 * Cuts off any whitespace at the beginning and the end of the content
2423 *
2424 * @param string $content Input value undergoing processing in this function.
2425 * @param array $conf stdWrap properties for trim.
2426 * @return string The processed input value
2427 */
2428 public function stdWrap_trim($content = '', $conf = array()) {
2429 return trim($content);
2430 }
2431
2432 /**
2433 * strPad
2434 * Will return a string padded left/right/on both sides, based on configuration given as stdWrap properties
2435 *
2436 * @param string $content Input value undergoing processing in this function.
2437 * @param array $conf stdWrap properties for strPad.
2438 * @return string The processed input value
2439 */
2440 public function stdWrap_strPad($content = '', $conf = array()) {
2441 // Must specify a length in conf for this to make sense
2442 $length = 0;
2443 // Padding with space is PHP-default
2444 $padWith = ' ';
2445 // Padding on the right side is PHP-default
2446 $padType = STR_PAD_RIGHT;
2447 if (!empty($conf['strPad.']['length'])) {
2448 $length = isset($conf['strPad.']['length.']) ? $this->stdWrap($conf['strPad.']['length'], $conf['strPad.']['length.']) : $conf['strPad.']['length'];
2449 $length = (int)$length;
2450 }
2451 if (isset($conf['strPad.']['padWith']) && strlen($conf['strPad.']['padWith']) > 0) {
2452 $padWith = isset($conf['strPad.']['padWith.']) ? $this->stdWrap($conf['strPad.']['padWith'], $conf['strPad.']['padWith.']) : $conf['strPad.']['padWith'];
2453 }
2454 if (!empty($conf['strPad.']['type'])) {
2455 $type = isset($conf['strPad.']['type.']) ? $this->stdWrap($conf['strPad.']['type'], $conf['strPad.']['type.']) : $conf['strPad.']['type'];
2456 if (strtolower($type) === 'left') {
2457 $padType = STR_PAD_LEFT;
2458 } elseif (strtolower($type) === 'both') {
2459 $padType = STR_PAD_BOTH;
2460 }
2461 }
2462 $content = str_pad($content, $length, $padWith, $padType);
2463 return $content;
2464 }
2465
2466 /**
2467 * stdWrap
2468 * A recursive call of the stdWrap function set
2469 * This enables the user to execute stdWrap functions in another than the predefined order
2470 * It modifies the content, not the property
2471 * while the new feature of chained stdWrap functions modifies the property and not the content
2472 *
2473 * @param string $content Input value undergoing processing in this function.
2474 * @param array $conf stdWrap properties for stdWrap.
2475 * @return string The processed input value
2476 */
2477 public function stdWrap_stdWrap($content = '', $conf = array()) {
2478 return $this->stdWrap($content, $conf['stdWrap.']);
2479 }
2480
2481 /**
2482 * stdWrap process hook
2483 * can be used by extensions authors to modify the behaviour of stdWrap functions to their needs
2484 * this hook executes functions directly after the recursive stdWrap function call but still before the content gets modified
2485 *
2486 * @param string $content Input value undergoing processing in these functions.
2487 * @param array $conf All stdWrap properties, not just the ones for a particular function.
2488 * @return string The processed input value
2489 */
2490 public function stdWrap_stdWrapProcess($content = '', $conf = array()) {
2491 foreach ($this->stdWrapHookObjects as $hookObject) {
2492 $content = $hookObject->stdWrapProcess($content, $conf, $this);
2493 }
2494 return $content;
2495 }
2496
2497 /**
2498 * required
2499 * Will immediately stop rendering and return an empty value
2500 * when there is no content at this point
2501 *
2502 * @param string $content Input value undergoing processing in this function.
2503 * @param array $conf stdWrap properties for required.
2504 * @return string The processed input value
2505 */
2506 public function stdWrap_required($content = '', $conf = array()) {
2507 if ((string) $content === '') {
2508 $content = '';
2509 $this->stopRendering[$this->stdWrapRecursionLevel] = TRUE;
2510 }
2511 return $content;
2512 }
2513
2514 /**
2515 * if
2516 * Will immediately stop rendering and return an empty value
2517 * when the result of the checks returns FALSE
2518 *
2519 * @param string $content Input value undergoing processing in this function.
2520 * @param array $conf stdWrap properties for if.
2521 * @return string The processed input value
2522 */
2523 public function stdWrap_if($content = '', $conf = array()) {
2524 if (!$this->checkIf($conf['if.'])) {
2525 $content = '';
2526 $this->stopRendering[$this->stdWrapRecursionLevel] = TRUE;
2527 }
2528 return $content;
2529 }
2530
2531 /**
2532 * fieldRequired
2533 * Will immediately stop rendering and return an empty value
2534 * when there is no content in the field given by fieldRequired
2535 *
2536 * @param string $content Input value undergoing processing in this function.
2537 * @param array $conf stdWrap properties for fieldRequired.
2538 * @return string The processed input value
2539 */
2540 public function stdWrap_fieldRequired($content = '', $conf = array()) {
2541 if (!trim($this->data[$conf['fieldRequired']])) {
2542 $content = '';
2543 $this->stopRendering[$this->stdWrapRecursionLevel] = TRUE;
2544 }
2545 return $content;
2546 }
2547
2548 /**
2549 * csConv
2550 * Will convert the current chracter set of the content to the one given in csConv
2551 *
2552 * @param string $content Input value undergoing processing in this function.
2553 * @param array $conf stdWrap properties for csConv.
2554 * @return string The processed input value
2555 */
2556 public function stdWrap_csConv($content = '', $conf = array()) {
2557 return $GLOBALS['TSFE']->csConv($content, $conf['csConv']);
2558 }
2559
2560 /**
2561 * parseFunc
2562 * Will parse the content based on functions given as stdWrap properties
2563 * Heavily used together with RTE based content
2564 *
2565 * @param string $content Input value undergoing processing in this function.
2566 * @param array $conf stdWrap properties for parseFunc.
2567 * @return string The processed input value
2568 */
2569 public function stdWrap_parseFunc($content = '', $conf = array()) {
2570 return $this->parseFunc($content, $conf['parseFunc.'], $conf['parseFunc']);
2571 }
2572
2573 /**
2574 * HTMLparser
2575 * Will parse HTML content based on functions given as stdWrap properties
2576 * Heavily used together with RTE based content
2577 *
2578 * @param string $content Input value undergoing processing in this function.
2579 * @param array $conf stdWrap properties for HTMLparser.
2580 * @return string The processed input value
2581 */
2582 public function stdWrap_HTMLparser($content = '', $conf = array()) {
2583 if (is_array($conf['HTMLparser.'])) {
2584 $content = $this->HTMLparser_TSbridge($content, $conf['HTMLparser.']);
2585 }
2586 return $content;
2587 }
2588
2589 /**
2590 * split
2591 * Will split the content by a given token and treat the results separately
2592 * Automatically fills 'current' with a single result
2593 *
2594 * @param string $content Input value undergoing processing in this function.
2595 * @param array $conf stdWrap properties for split.
2596 * @return string The processed input value
2597 */
2598 public function stdWrap_split($content = '', $conf = array()) {
2599 return $this->splitObj($content, $conf['split.']);
2600 }
2601
2602 /**
2603 * replacement
2604 * Will execute replacements on the content (optionally with preg-regex)
2605 *
2606 * @param string $content Input value undergoing processing in this function.
2607 * @param array $conf stdWrap properties for replacement.
2608 * @return string The processed input value
2609 */
2610 public function stdWrap_replacement($content = '', $conf = array()) {
2611 return $this->replacement($content, $conf['replacement.']);
2612 }
2613
2614 /**
2615 * prioriCalc
2616 * Will use the content as a mathematical term and calculate the result
2617 * Can be set to 1 to just get a calculated value or 'intval' to get the integer of the result
2618 *
2619 * @param string $content Input value undergoing processing in this function.
2620 * @param array $conf stdWrap properties for prioriCalc.
2621 * @return string The processed input value
2622 */
2623 public function stdWrap_prioriCalc($content = '', $conf = array()) {
2624 $content = \TYPO3\CMS\Core\Utility\MathUtility::calculateWithParentheses($content);
2625 if ($conf['prioriCalc'] == 'intval') {
2626 $content = (int)$content;
2627 }
2628 return $content;
2629 }
2630
2631 /**
2632 * char
2633 * Will return a character based on its position within the current character set
2634 *
2635 * @param string $content Input value undergoing processing in this function.
2636 * @param array $conf stdWrap properties for char.
2637 * @return string The processed input value
2638 */
2639 public function stdWrap_char($content = '', $conf = array()) {
2640 return chr((int)$conf['char']);
2641 }
2642
2643 /**
2644 * intval
2645 * Will return an integer value of the current content
2646 *
2647 * @param string $content Input value undergoing processing in this function.
2648 * @param array $conf stdWrap properties for intval.
2649 * @return string The processed input value
2650 */
2651 public function stdWrap_intval($content = '', $conf = array()) {
2652 return (int)$content;
2653 }
2654
2655 /**
2656 * Will return a hashed value of the current content
2657 *
2658 * @param string $content Input value undergoing processing in this function.
2659 * @param array $conf stdWrap properties for hash.
2660 * @return string The processed input value
2661 * @link http://php.net/manual/de/function.hash-algos.php for a list of supported hash algorithms
2662 */
2663 public function stdWrap_hash($content = '', array $conf = array()) {
2664 $algorithm = isset($conf['hash.']) ? $this->stdWrap($conf['hash'], $conf['hash.']) : $conf['hash'];
2665 if (function_exists('hash') && in_array($algorithm, hash_algos())) {
2666 $content = hash($algorithm, $content);
2667 } else {
2668 // Non-existing hashing algorithm
2669 $content = '';
2670 }
2671 return $content;
2672 }
2673
2674 /**
2675 * stdWrap_round will return a rounded number with ceil(), floor() or round(), defaults to round()
2676 * Only the english number format is supported . (dot) as decimal point
2677 *
2678 * @param string $content Input value undergoing processing in this function.
2679 * @param array $conf stdWrap properties for round.
2680 * @return string The processed input value
2681 */
2682 public function stdWrap_round($content = '', $conf = array()) {
2683 return $this->round($content, $conf['round.']);
2684 }
2685
2686 /**
2687 * numberFormat
2688 * Will return a formatted number based on configuration given as stdWrap properties
2689 *
2690 * @param string $content Input value undergoing processing in this function.
2691 * @param array $conf stdWrap properties for numberFormat.
2692 * @return string The processed input value
2693 */
2694 public function stdWrap_numberFormat($content = '', $conf = array()) {
2695 return $this->numberFormat($content, $conf['numberFormat.']);
2696 }
2697
2698 /**
2699 * expandList
2700 * Will return a formatted number based on configuration given as stdWrap properties
2701 *
2702 * @param string $content Input value undergoing processing in this function.
2703 * @param array $conf stdWrap properties for expandList.
2704 * @return string The processed input value
2705 */
2706 public function stdWrap_expandList($content = '', $conf = array()) {
2707 return GeneralUtility::expandList($content);
2708 }
2709
2710 /**
2711 * date
2712 * Will return a formatted date based on configuration given according to PHP date/gmdate properties
2713 * Will return gmdate when the property GMT returns TRUE
2714 *
2715 * @param string $content Input value undergoing processing in this function.
2716 * @param array $conf stdWrap properties for date.
2717 * @return string The processed input value
2718 */
2719 public function stdWrap_date($content = '', $conf = array()) {
2720 // Check for zero length string to mimic default case of date/gmdate.
2721 $content = $content == '' ? $GLOBALS['EXEC_TIME'] : (int)$content;
2722 $content = $conf['date.']['GMT'] ? gmdate($conf['date'], $content) : date($conf['date'], $content);
2723 return $content;
2724 }
2725
2726 /**
2727 * strftime
2728 * Will return a formatted date based on configuration given according to PHP strftime/gmstrftime properties
2729 * Will return gmstrftime when the property GMT returns TRUE
2730 *
2731 * @param string $content Input value undergoing processing in this function.
2732 * @param array $conf stdWrap properties for strftime.
2733 * @return string The processed input value
2734 */
2735 public function stdWrap_strftime($content = '', $conf = array()) {
2736 // Check for zero length string to mimic default case of strtime/gmstrftime
2737 $content = $content == '' ? $GLOBALS['EXEC_TIME'] : (int)$content;
2738 $content = $conf['strftime.']['GMT'] ? gmstrftime($conf['strftime'], $content) : strftime($conf['strftime'], $content);
2739 $tmp_charset = $conf['strftime.']['charset'] ? $conf['strftime.']['charset'] : $GLOBALS['TSFE']->localeCharset;
2740 if ($tmp_charset) {
2741 $content = $GLOBALS['TSFE']->csConv($content, $tmp_charset);
2742 }
2743 return $content;
2744 }
2745
2746 /**
2747 * age
2748 * Will return the age of a given timestamp based on configuration given by stdWrap properties
2749 *
2750 * @param string $content Input value undergoing processing in this function.
2751 * @param array $conf stdWrap properties for age.
2752 * @return string The processed input value
2753 */
2754 public function stdWrap_age($content = '', $conf = array()) {
2755 return $this->calcAge($GLOBALS['EXEC_TIME'] - $content, $conf['age']);
2756 }
2757
2758 /**
2759 * case
2760 * Will transform the content to be upper or lower case only
2761 * Leaves HTML tags untouched
2762 *
2763 * @param string $content Input value undergoing processing in this function.
2764 * @param array $conf stdWrap properties for case.
2765 * @return string The processed input value
2766 */
2767 public function stdWrap_case($content = '', $conf = array()) {
2768 return $this->HTMLcaseshift($content, $conf['case']);
2769 }
2770
2771 /**
2772 * bytes
2773 * Will return the size of a given number in Bytes *
2774 *
2775 * @param string $content Input value undergoing processing in this function.
2776 * @param array $conf stdWrap properties for bytes.
2777 * @return string The processed input value
2778 */
2779 public function stdWrap_bytes($content = '', $conf = array()) {
2780 return GeneralUtility::formatSize($content, $conf['bytes.']['labels']);
2781 }
2782
2783 /**
2784 * substring
2785 * Will return a substring based on position information given by stdWrap properties
2786 *
2787 * @param string $content Input value undergoing processing in this function.
2788 * @param array $conf stdWrap properties for substring.
2789 * @return string The processed input value
2790 */
2791 public function stdWrap_substring($content = '', $conf = array()) {
2792 return $this->substring($content, $conf['substring']);
2793 }
2794
2795 /**
2796 * removeBadHTML
2797 * Removes HTML tags based on stdWrap properties
2798 *
2799 * @param string $content Input value undergoing processing in this function.
2800 * @param array $conf stdWrap properties for removeBadHTML.
2801 * @return string The processed input value
2802 */
2803 public function stdWrap_removeBadHTML($content = '', $conf = array()) {
2804 return $this->removeBadHTML($content, $conf['removeBadHTML.']);
2805 }
2806
2807 /**
2808 * cropHTML
2809 * Crops content to a given size while leaving HTML tags untouched
2810 *
2811 * @param string $content Input value undergoing processing in this function.
2812 * @param array $conf stdWrap properties for cropHTML.
2813 * @return string The processed input value
2814 */
2815 public function stdWrap_cropHTML($content = '', $conf = array()) {
2816 return $this->cropHTML($content, $conf['cropHTML']);
2817 }
2818
2819 /**
2820 * stripHtml
2821 * Copmletely removes HTML tags from content
2822 *
2823 * @param string $content Input value undergoing processing in this function.
2824 * @param array $conf stdWrap properties for stripHtml.
2825 * @return string The processed input value
2826 */
2827 public function stdWrap_stripHtml($content = '', $conf = array()) {
2828 return strip_tags($content);
2829 }
2830
2831 /**
2832 * crop
2833 * Crops content to a given size without caring about HTML tags
2834 *
2835 * @param string $content Input value undergoing processing in this function.
2836 * @param array $conf stdWrap properties for crop.
2837 * @return string The processed input value
2838 */
2839 public function stdWrap_crop($content = '', $conf = array()) {
2840 return $this->crop($content, $conf['crop']);
2841 }
2842
2843 /**
2844 * rawUrlEncode
2845 * Encodes content to be used within URLs
2846 *
2847 * @param string $content Input value undergoing processing in this function.
2848 * @param array $conf stdWrap properties for rawUrlEncode.
2849 * @return string The processed input value
2850 */
2851 public function stdWrap_rawUrlEncode($content = '', $conf = array()) {
2852 return rawurlencode($content);
2853 }
2854
2855 /**
2856 * htmlSpecialChars
2857 * Transforms HTML tags to readable text by replacing special characters with their HTML entity
2858 * When preserveEntities returns TRUE, existing entities will be left untouched
2859 *
2860 * @param string $content Input value undergoing processing in this function.
2861 * @param array $conf stdWrap properties for htmlSpecalChars.
2862 * @return string The processed input value
2863 */
2864 public function stdWrap_htmlSpecialChars($content = '', $conf = array()) {
2865 if (!empty($conf['htmlSpecialChars.']['preserveEntities'])) {
2866 $content = htmlspecialchars($content, ENT_COMPAT, 'UTF-8', FALSE);
2867 } else {
2868 $content = htmlspecialchars($content);
2869 }
2870 return $content;
2871 }
2872
2873 /**
2874 * encodeForJavaScriptValue
2875 * Escapes content to be used inside JavaScript strings. No quotes are added around the value
2876 * as this can easily be done in TypoScript
2877 *
2878 * @param string $content Input value undergoing processing in this function
2879 * @param array $conf stdWrap properties for encodeForJavaScriptValue
2880 * @return string The processed input value
2881 */
2882 public function stdWrap_encodeForJavaScriptValue($content = '', $conf = array()) {
2883 return GeneralUtility::quoteJSvalue($content);
2884 }
2885
2886 /**
2887 * doubleBrTag
2888 * Searches for double line breaks and replaces them with the given value