ef370cea270db6222f87ec74e8f8642818905deb
[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\Utility\GeneralUtility;
18 use TYPO3\CMS\Core\Utility\MathUtility;
19
20 /**
21 * Contains FILES content object
22 *
23 * @author Ingmar Schlecht <ingmar@typo3.org>
24 */
25 class FilesContentObject extends AbstractContentObject {
26
27 /**
28 * @var \TYPO3\CMS\Core\Resource\FileCollectionRepository|NULL
29 */
30 protected $collectionRepository = NULL;
31
32 /**
33 * @var \TYPO3\CMS\Core\Resource\ResourceFactory|NULL
34 */
35 protected $fileFactory = NULL;
36
37 /**
38 * @var \TYPO3\CMS\Core\Resource\FileRepository|NULL
39 */
40 protected $fileRepository = NULL;
41
42 /**
43 * Rendering the cObject FILES
44 *
45 * @param array $conf Array of TypoScript properties
46 * @return string Output
47 */
48 public function render($conf = array()) {
49 if (!empty($conf['if.']) && !$this->cObj->checkIf($conf['if.'])) {
50 return '';
51 }
52
53 $fileObjects = array();
54 // Getting the files
55 if ($conf['references'] || $conf['references.']) {
56 /*
57 The TypoScript could look like this:# all items related to the page.media field:
58 references {
59 table = pages
60 uid.data = page:uid
61 fieldName = media
62 }# or: sys_file_references with uid 27:
63 references = 27
64 */
65 $referencesUid = $this->cObj->stdWrapValue('references', $conf);
66 $referencesUidArray = GeneralUtility::intExplode(',', $referencesUid, TRUE);
67 foreach ($referencesUidArray as $referenceUid) {
68 try {
69 $this->addToArray(
70 $this->getFileFactory()->getFileReferenceObject($referenceUid),
71 $fileObjects
72 );
73 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
74 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
75 $logger = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger(__CLASS__);
76 $logger->warning('The file-reference with uid "' . $referenceUid . '" could not be found and won\'t be included in frontend output');
77 }
78 }
79
80 $this->handleFileReferences($conf, (array)$this->cObj->data, $fileObjects);
81 }
82 if ($conf['files'] || $conf['files.']) {
83 /*
84 The TypoScript could look like this:
85 # with sys_file UIDs:
86 files = 12,14,15# using stdWrap:
87 files.field = some_field
88 */
89 $fileUids = GeneralUtility::intExplode(',', $this->cObj->stdWrapValue('files', $conf), TRUE);
90 foreach ($fileUids as $fileUid) {
91 try {
92 $this->addToArray($this->getFileFactory()->getFileObject($fileUid), $fileObjects);
93 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
94 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
95 $logger = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger(__CLASS__);
96 $logger->warning('The file with uid "' . $fileUid . '" could not be found and won\'t be included in frontend output');
97 }
98 }
99 }
100 if ($conf['collections'] || $conf['collections.']) {
101 $collectionUids = GeneralUtility::intExplode(',', $this->cObj->stdWrapValue('collections', $conf), TRUE);
102 foreach ($collectionUids as $collectionUid) {
103 try {
104 $fileCollection = $this->getCollectionRepository()->findByUid($collectionUid);
105 if ($fileCollection instanceof \TYPO3\CMS\Core\Resource\Collection\AbstractFileCollection) {
106 $fileCollection->loadContents();
107 $this->addToArray($fileCollection->getItems(), $fileObjects);
108 }
109 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
110 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
111 $logger = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger(__CLASS__);
112 $logger->warning('The file-collection with uid "' . $collectionUid . '" could not be found or contents could not be loaded and won\'t be included in frontend output');
113 }
114 }
115 }
116 if ($conf['folders'] || $conf['folders.']) {
117 $folderIdentifiers = GeneralUtility::trimExplode(',', $this->cObj->stdWrapValue('folders', $conf));
118 foreach ($folderIdentifiers as $folderIdentifier) {
119 if ($folderIdentifier) {
120 try {
121 $folder = $this->getFileFactory()->getFolderObjectFromCombinedIdentifier($folderIdentifier);
122 if ($folder instanceof \TYPO3\CMS\Core\Resource\Folder) {
123 $this->addToArray(array_values($folder->getFiles()), $fileObjects);
124 }
125 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
126 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
127 $logger = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Log\LogManager::class)->getLogger(__CLASS__);
128 $logger->warning('The folder with identifier "' . $folderIdentifier . '" could not be found and won\'t be included in frontend output');
129 }
130 }
131 }
132 }
133 // Rendering the files
134 $content = '';
135 // optionSplit applied to conf to allow differnt settings per file
136 $splitConf = $GLOBALS['TSFE']->tmpl->splitConfArray($conf, count($fileObjects));
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 !== '' && count($fileObjects) > 1) {
144 @usort($fileObjects, function(\TYPO3\CMS\Core\Resource\FileInterface $a, \TYPO3\CMS\Core\Resource\FileInterface $b) use($sortingProperty) {
145 if ($a->hasProperty($sortingProperty) && $b->hasProperty($sortingProperty)) {
146 return strnatcasecmp($a->getProperty($sortingProperty), $b->getProperty($sortingProperty));
147 } else {
148 return 0;
149 }
150 });
151 $sortingDirection = isset($conf['sorting.']['direction']) ? $conf['sorting.']['direction'] : '';
152 if (isset($conf['sorting.']['direction.'])) {
153 $sortingDirection = $this->cObj->stdWrap($sortingDirection, $conf['sorting.']['direction.']);
154 }
155 if (strtolower($sortingDirection) === 'desc') {
156 $fileObjects = array_reverse($fileObjects);
157 }
158 }
159
160 $availableFileObjectCount = count($fileObjects);
161
162 $start = 0;
163 if (!empty($conf['begin'])) {
164 $start = (int)$conf['begin'];
165 }
166 if (!empty($conf['begin.'])) {
167 $start = (int)$this->cObj->stdWrap($start, $conf['begin.']);
168 }
169 $start = MathUtility::forceIntegerInRange($start, 0, $availableFileObjectCount);
170
171 $limit = $availableFileObjectCount;
172 if (!empty($conf['maxItems'])) {
173 $limit = (int)$conf['maxItems'];
174 }
175 if (!empty($conf['maxItems.'])) {
176 $limit = (int)$this->cObj->stdWrap($limit, $conf['maxItems.']);
177 }
178
179 $end = MathUtility::forceIntegerInRange($start + $limit, $start, $availableFileObjectCount);
180
181 $GLOBALS['TSFE']->register['FILES_COUNT'] = min($limit, $availableFileObjectCount);
182 $fileObjectCounter = 0;
183 $keys = array_keys($fileObjects);
184 for ($i = $start; $i < $end; $i++) {
185 $key = $keys[$i];
186 $fileObject = $fileObjects[$key];
187
188 $GLOBALS['TSFE']->register['FILE_NUM_CURRENT'] = $fileObjectCounter;
189 $this->cObj->setCurrentFile($fileObject);
190 $content .= $this->cObj->cObjGetSingle($splitConf[$key]['renderObj'], $splitConf[$key]['renderObj.']);
191 $fileObjectCounter++;
192 }
193 $content = $this->cObj->stdWrap($content, $conf['stdWrap.']);
194 return $content;
195 }
196
197 /**
198 * Sets the file factory.
199 *
200 * @param \TYPO3\CMS\Core\Resource\ResourceFactory $fileFactory
201 * @return void
202 */
203 public function setFileFactory($fileFactory) {
204 $this->fileFactory = $fileFactory;
205 }
206
207 /**
208 * Returns the file factory.
209 *
210 * @return \TYPO3\CMS\Core\Resource\ResourceFactory
211 */
212 public function getFileFactory() {
213 if ($this->fileFactory === NULL) {
214 $this->fileFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\ResourceFactory::class);
215 }
216
217 return $this->fileFactory;
218 }
219
220 /**
221 * Sets the file repository.
222 *
223 * @param \TYPO3\CMS\Core\Resource\FileRepository $fileRepository
224 * @return void
225 */
226 public function setFileRepository($fileRepository) {
227 $this->fileRepository = $fileRepository;
228 }
229
230 /**
231 * Returns the file repository.
232 *
233 * @return \TYPO3\CMS\Core\Resource\FileRepository
234 */
235 public function getFileRepository() {
236 if ($this->fileRepository === NULL) {
237 $this->fileRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\FileRepository::class);
238 }
239
240 return $this->fileRepository;
241 }
242
243 /**
244 * Sets the collection repository.
245 *
246 * @param \TYPO3\CMS\Core\Resource\FileCollectionRepository $collectionRepository
247 * @return void
248 */
249 public function setCollectionRepository($collectionRepository) {
250 $this->collectionRepository = $collectionRepository;
251 }
252
253 /**
254 * Returns the collection repository.
255 *
256 * @return \TYPO3\CMS\Core\Resource\FileCollectionRepository
257 */
258 public function getCollectionRepository() {
259 if ($this->collectionRepository === NULL) {
260 $this->collectionRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\FileCollectionRepository::class);
261 }
262
263 return $this->collectionRepository;
264 }
265
266 /**
267 * Handles and resolves file references.
268 *
269 * @param array $configuration TypoScript configuration
270 * @param array $element The parent element referencing to files
271 * @param array $fileObjects Collection of file objects
272 * @return void
273 */
274 protected function handleFileReferences(array $configuration, array $element, array &$fileObjects) {
275 if (empty($configuration['references.'])) {
276 return;
277 }
278
279 // 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
280 $referencesFieldName = $this->cObj->stdWrapValue('fieldName', $configuration['references.']);
281
282 // If no reference fieldName is set, there's nothing to do
283 if (empty($referencesFieldName)) {
284 return;
285 }
286
287 $currentId = !empty($element['uid']) ? $element['uid'] : 0;
288 $tableName = $this->cObj->getCurrentTable();
289
290 // Fetch the references of the default element
291 $referencesForeignTable = $this->cObj->stdWrapValue('table', $configuration['references.'], $tableName);
292 $referencesForeignUid = $this->cObj->stdWrapValue('uid', $configuration['references.'], $currentId);
293
294 $pageRepository = $this->getPageRepository();
295 // Fetch element if definition has been modified via TypoScript
296 if ($referencesForeignTable !== $tableName || $referencesForeignUid !== $currentId) {
297 $element = $pageRepository->getRawRecord(
298 $referencesForeignTable,
299 $referencesForeignUid,
300 '*',
301 FALSE
302 );
303
304 $pageRepository->versionOL($referencesForeignTable, $element, TRUE);
305 if ($referencesForeignTable === 'pages') {
306 $element = $pageRepository->getPageOverlay($element);
307 } else {
308 $element = $pageRepository->getRecordOverlay(
309 $referencesForeignTable,
310 $element,
311 $GLOBALS['TSFE']->sys_language_content,
312 $GLOBALS['TSFE']->sys_language_contentOL
313 );
314 }
315 }
316
317 $references = $pageRepository->getFileReferences(
318 $referencesForeignTable,
319 $referencesFieldName,
320 $element
321 );
322
323 $this->addToArray($references, $fileObjects);
324 }
325
326 /**
327 * Adds $newItems to $theArray, which is passed by reference. Array must only consist of numerical keys.
328 *
329 * @param mixed $newItems Array with new items or single object that's added.
330 * @param array $theArray The array the new items should be added to. Must only contain numeric keys (for array_merge() to add items instead of replacing).
331 */
332 protected function addToArray($newItems, array &$theArray) {
333 if (is_array($newItems)) {
334 $theArray = array_merge($theArray, $newItems);
335 } elseif (is_object($newItems)) {
336 $theArray[] = $newItems;
337 }
338 }
339
340 /**
341 * @return \TYPO3\CMS\Frontend\Page\PageRepository
342 */
343 protected function getPageRepository() {
344 return $GLOBALS['TSFE']->sys_page;
345 }
346
347 }