[FEATURE] Introduce Data Processor for Files
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / FilesContentObject.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\Resource\Exception;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Core\Utility\MathUtility;
20 use TYPO3\CMS\Frontend\Resource\FileCollector;
21
22 /**
23 * Contains FILES content object
24 *
25 * @author Ingmar Schlecht <ingmar@typo3.org>
26 */
27 class FilesContentObject extends AbstractContentObject {
28
29 /**
30 * Rendering the cObject FILES
31 *
32 * @param array $conf Array of TypoScript properties
33 * @return string Output
34 */
35 public function render($conf = array()) {
36 if (!empty($conf['if.']) && !$this->cObj->checkIf($conf['if.'])) {
37 return '';
38 }
39
40 $fileCollector = $this->findAndSortFiles($conf);
41 $fileObjects = $fileCollector->getFiles();
42 $availableFileObjectCount = count($fileObjects);
43
44 // optionSplit applied to conf to allow different settings per file
45 $splitConf = $GLOBALS['TSFE']->tmpl->splitConfArray($conf, $availableFileObjectCount);
46
47 $start = 0;
48 if (!empty($conf['begin'])) {
49 $start = (int)$conf['begin'];
50 }
51 if (!empty($conf['begin.'])) {
52 $start = (int)$this->cObj->stdWrap($start, $conf['begin.']);
53 }
54 $start = MathUtility::forceIntegerInRange($start, 0, $availableFileObjectCount);
55
56 $limit = $availableFileObjectCount;
57 if (!empty($conf['maxItems'])) {
58 $limit = (int)$conf['maxItems'];
59 }
60 if (!empty($conf['maxItems.'])) {
61 $limit = (int)$this->cObj->stdWrap($limit, $conf['maxItems.']);
62 }
63
64 $end = MathUtility::forceIntegerInRange($start + $limit, $start, $availableFileObjectCount);
65
66 $GLOBALS['TSFE']->register['FILES_COUNT'] = min($limit, $availableFileObjectCount);
67 $fileObjectCounter = 0;
68 $keys = array_keys($fileObjects);
69
70 $content = '';
71 for ($i = $start; $i < $end; $i++) {
72 $key = $keys[$i];
73 $fileObject = $fileObjects[$key];
74
75 $GLOBALS['TSFE']->register['FILE_NUM_CURRENT'] = $fileObjectCounter;
76 $this->cObj->setCurrentFile($fileObject);
77 $content .= $this->cObj->cObjGetSingle($splitConf[$key]['renderObj'], $splitConf[$key]['renderObj.']);
78 $fileObjectCounter++;
79 }
80
81 return $this->cObj->stdWrap($content, $conf['stdWrap.']);
82 }
83
84 /**
85 * Function to check for references, collections, folders and
86 * accumulates into one etc.
87 *
88 * @param array $conf
89 * @return FileCollector
90 */
91 protected function findAndSortFiles(array $conf) {
92
93 $fileCollector = $this->getFileCollector();
94
95 // Getting the files
96 if ($conf['references'] || $conf['references.']) {
97 /*
98 The TypoScript could look like this:
99 # all items related to the page.media field:
100 references {
101 table = pages
102 uid.data = page:uid
103 fieldName = media
104 }
105 # or: sys_file_references with uid 27:
106 references = 27
107 */
108 $referencesUidList = $this->cObj->stdWrapValue('references', $conf);
109 $referencesUids = GeneralUtility::intExplode(',', $referencesUidList, TRUE);
110 $fileCollector->addFileReferences($referencesUids);
111
112 if (!empty($conf['references.'])) {
113 $this->addFileReferences($conf, (array)$this->cObj->data, $fileCollector);
114 }
115 }
116
117 if ($conf['files'] || $conf['files.']) {
118 /*
119 The TypoScript could look like this:
120 # with sys_file UIDs:
121 files = 12,14,15# using stdWrap:
122 files.field = some_field
123 */
124 $fileUids = GeneralUtility::intExplode(',', $this->cObj->stdWrapValue('files', $conf), TRUE);
125 $fileCollector->addFiles($fileUids);
126 }
127
128 if ($conf['collections'] || $conf['collections.']) {
129 $collectionUids = GeneralUtility::intExplode(',', $this->cObj->stdWrapValue('collections', $conf), TRUE);
130 $fileCollector->addFilesFromFileCollections($collectionUids);
131 }
132
133 if ($conf['folders'] || $conf['folders.']) {
134 $folderIdentifiers = GeneralUtility::trimExplode(',', $this->cObj->stdWrapValue('folders', $conf));
135 $fileCollector->addFilesFromFolders($folderIdentifiers);
136 }
137
138 // Enable sorting for multiple fileObjects
139 $sortingProperty = '';
140 if ($conf['sorting'] || $conf['sorting.']) {
141 $sortingProperty = $this->cObj->stdWrapValue('sorting', $conf);
142 }
143 if ($sortingProperty !== '') {
144 $sortingDirection = isset($conf['sorting.']['direction']) ? $conf['sorting.']['direction'] : '';
145 if (isset($conf['sorting.']['direction.'])) {
146 $sortingDirection = $this->cObj->stdWrap($sortingDirection, $conf['sorting.']['direction.']);
147 }
148 $fileCollector->sort($sortingProperty, $sortingDirection);
149 }
150
151 return $fileCollector;
152 }
153
154 /**
155 * Handles and resolves file references.
156 *
157 * @param array $configuration TypoScript configuration
158 * @param array $element The parent element referencing to files
159 * @param FileCollector $fileCollector
160 * @return array
161 */
162 protected function addFileReferences(array $configuration, array $element, FileCollector $fileCollector) {
163
164 // It's important that this always stays "fieldName" and not be renamed to "field" as it would otherwise collide with the stdWrap key of that name
165 $referencesFieldName = $this->cObj->stdWrapValue('fieldName', $configuration['references.']);
166
167 // If no reference fieldName is set, there's nothing to do
168 if (empty($referencesFieldName)) {
169 return;
170 }
171
172 $currentId = !empty($element['uid']) ? $element['uid'] : 0;
173 $tableName = $this->cObj->getCurrentTable();
174
175 // Fetch the references of the default element
176 $referencesForeignTable = $this->cObj->stdWrapValue('table', $configuration['references.'], $tableName);
177 $referencesForeignUid = $this->cObj->stdWrapValue('uid', $configuration['references.'], $currentId);
178
179 $pageRepository = $this->getPageRepository();
180 // Fetch element if definition has been modified via TypoScript
181 if ($referencesForeignTable !== $tableName || $referencesForeignUid !== $currentId) {
182 $element = $pageRepository->getRawRecord(
183 $referencesForeignTable,
184 $referencesForeignUid,
185 '*',
186 FALSE
187 );
188
189 $pageRepository->versionOL($referencesForeignTable, $element, TRUE);
190 if ($referencesForeignTable === 'pages') {
191 $element = $pageRepository->getPageOverlay($element);
192 } else {
193 $element = $pageRepository->getRecordOverlay(
194 $referencesForeignTable,
195 $element,
196 $GLOBALS['TSFE']->sys_language_content,
197 $GLOBALS['TSFE']->sys_language_contentOL
198 );
199 }
200 }
201
202 if (is_array($element)) {
203 $fileCollector->addFilesFromRelation($referencesForeignTable, $referencesFieldName, $element);
204 }
205 }
206
207 /**
208 * @return \TYPO3\CMS\Frontend\Page\PageRepository
209 */
210 protected function getPageRepository() {
211 return $GLOBALS['TSFE']->sys_page;
212 }
213
214 /**
215 * @return FileCollector
216 */
217 protected function getFileCollector() {
218 return GeneralUtility::makeInstance(FileCollector::class);
219 }
220 }