[BUGFIX] Invalid localization overlay of cObject FILES
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / FilesContentObject.php
1 <?php
2 namespace TYPO3\CMS\Frontend\ContentObject;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2012-2013 Ingmar Schlecht <ingmar@typo3.org>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Core\Utility\GeneralUtility;
31 use TYPO3\CMS\Core\Utility\MathUtility;
32
33 /**
34 * Contains FILES content object
35 *
36 * @author Ingmar Schlecht <ingmar@typo3.org>
37 */
38 class FilesContentObject extends \TYPO3\CMS\Frontend\ContentObject\AbstractContentObject {
39
40 /**
41 * @var \TYPO3\CMS\Core\Resource\FileCollectionRepository|NULL
42 */
43 protected $collectionRepository = NULL;
44
45 /**
46 * @var \TYPO3\CMS\Core\Resource\ResourceFactory|NULL
47 */
48 protected $fileFactory = NULL;
49
50 /**
51 * @var \TYPO3\CMS\Core\Resource\FileRepository|NULL
52 */
53 protected $fileRepository = NULL;
54
55 /**
56 * Rendering the cObject FILES
57 *
58 * @param array $conf Array of TypoScript properties
59 * @return string Output
60 */
61 public function render($conf = array()) {
62 $fileObjects = array();
63 // Getting the files
64 if ($conf['references'] || $conf['references.']) {
65 /*
66 The TypoScript could look like this:# all items related to the page.media field:
67 references {
68 table = pages
69 uid.data = page:uid
70 fieldName = media
71 }# or: sys_file_references with uid 27:
72 references = 27
73 */
74 $referencesUid = $this->cObj->stdWrapValue('references', $conf);
75 $referencesUidArray = GeneralUtility::intExplode(',', $referencesUid, TRUE);
76 foreach ($referencesUidArray as $referenceUid) {
77 try {
78 $this->addToArray(
79 $this->getFileFactory()->getFileReferenceObject($referenceUid),
80 $fileObjects
81 );
82 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
83 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
84 $logger = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Log\\LogManager')->getLogger(__CLASS__);
85 $logger->warning('The file-reference with uid "' . $referenceUid . '" could not be found and won\'t be included in frontend output');
86 }
87 }
88
89 $this->handleFileReferences($conf, (array)$this->cObj->data, $fileObjects);
90 }
91 if ($conf['files'] || $conf['files.']) {
92 /*
93 The TypoScript could look like this:
94 # with sys_file UIDs:
95 files = 12,14,15# using stdWrap:
96 files.field = some_field
97 */
98 $fileUids = GeneralUtility::intExplode(',', $this->cObj->stdWrapValue('files', $conf), TRUE);
99 foreach ($fileUids as $fileUid) {
100 try {
101 $this->addToArray($this->getFileFactory()->getFileObject($fileUid), $fileObjects);
102 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
103 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
104 $logger = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Log\\LogManager')->getLogger(__CLASS__);
105 $logger->warning('The file with uid "' . $fileUid . '" could not be found and won\'t be included in frontend output');
106 }
107 }
108 }
109 if ($conf['collections'] || $conf['collections.']) {
110 $collectionUids = GeneralUtility::intExplode(',', $this->cObj->stdWrapValue('collections', $conf), TRUE);
111 foreach ($collectionUids as $collectionUid) {
112 try {
113 $fileCollection = $this->getCollectionRepository()->findByUid($collectionUid);
114 if ($fileCollection instanceof \TYPO3\CMS\Core\Resource\Collection\AbstractFileCollection) {
115 $fileCollection->loadContents();
116 $this->addToArray($fileCollection->getItems(), $fileObjects);
117 }
118 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
119 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
120 $logger = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Log\\LogManager')->getLogger(__CLASS__);
121 $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');
122 }
123 }
124 }
125 if ($conf['folders'] || $conf['folders.']) {
126 $folderIdentifiers = GeneralUtility::trimExplode(',', $this->cObj->stdWrapValue('folders', $conf));
127 foreach ($folderIdentifiers as $folderIdentifier) {
128 if ($folderIdentifier) {
129 try {
130 $folder = $this->getFileFactory()->getFolderObjectFromCombinedIdentifier($folderIdentifier);
131 if ($folder instanceof \TYPO3\CMS\Core\Resource\Folder) {
132 $this->addToArray(array_values($folder->getFiles()), $fileObjects);
133 }
134 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
135 /** @var \TYPO3\CMS\Core\Log\Logger $logger */
136 $logger = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Log\\LogManager')->getLogger(__CLASS__);
137 $logger->warning('The folder with identifier "' . $folderIdentifier . '" could not be found and won\'t be included in frontend output');
138 }
139 }
140 }
141 }
142 // Rendering the files
143 $content = '';
144 // optionSplit applied to conf to allow differnt settings per file
145 $splitConf = $GLOBALS['TSFE']->tmpl->splitConfArray($conf, count($fileObjects));
146
147 // Enable sorting for multiple fileObjects
148 $sortingProperty = '';
149 if ($conf['sorting'] || $conf['sorting.']) {
150 $sortingProperty = $this->cObj->stdWrapValue('sorting', $conf);
151 }
152 if ($sortingProperty !== '' && count($fileObjects) > 1) {
153 @usort($fileObjects, function(\TYPO3\CMS\Core\Resource\FileInterface $a, \TYPO3\CMS\Core\Resource\FileInterface $b) use($sortingProperty) {
154 if ($a->hasProperty($sortingProperty) && $b->hasProperty($sortingProperty)) {
155 return strnatcasecmp($a->getProperty($sortingProperty), $b->getProperty($sortingProperty));
156 } else {
157 return 0;
158 }
159 });
160 if (is_array($conf['sorting.']) && isset($conf['sorting.']['direction']) && strtolower($conf['sorting.']['direction']) === 'desc') {
161 $fileObjects = array_reverse($fileObjects);
162 }
163 }
164
165 $availableFileObjectCount = count($fileObjects);
166
167 $start = 0;
168 if (!empty($conf['begin'])) {
169 $start = (int)$conf['begin'];
170 }
171 if (!empty($conf['begin.'])) {
172 $start = (int)$this->cObj->stdWrap($start, $conf['begin.']);
173 }
174 $start = MathUtility::forceIntegerInRange($start, 0, $availableFileObjectCount);
175
176 $limit = $availableFileObjectCount;
177 if (!empty($conf['maxItems'])) {
178 $limit = (int)$conf['maxItems'];
179 }
180 if (!empty($conf['maxItems.'])) {
181 $limit = (int)$this->cObj->stdWrap($limit, $conf['maxItems.']);
182 }
183
184 $end = MathUtility::forceIntegerInRange($start + $limit, $start, $availableFileObjectCount);
185
186 $GLOBALS['TSFE']->register['FILES_COUNT'] = min($limit, $availableFileObjectCount);
187 $fileObjectCounter = 0;
188 $keys = array_keys($fileObjects);
189 for ($i = $start; $i < $end; $i++) {
190 $key = $keys[$i];
191 $fileObject = $fileObjects[$key];
192
193 $GLOBALS['TSFE']->register['FILE_NUM_CURRENT'] = $fileObjectCounter;
194 $this->cObj->setCurrentFile($fileObject);
195 $content .= $this->cObj->cObjGetSingle($splitConf[$key]['renderObj'], $splitConf[$key]['renderObj.']);
196 $fileObjectCounter++;
197 }
198 $content = $this->cObj->stdWrap($content, $conf['stdWrap.']);
199 return $content;
200 }
201
202 /**
203 * Sets the file factory.
204 *
205 * @param \TYPO3\CMS\Core\Resource\ResourceFactory $fileFactory
206 * @return void
207 */
208 public function setFileFactory($fileFactory) {
209 $this->fileFactory = $fileFactory;
210 }
211
212 /**
213 * Returns the file factory.
214 *
215 * @return \TYPO3\CMS\Core\Resource\ResourceFactory
216 */
217 public function getFileFactory() {
218 if ($this->fileFactory === NULL) {
219 $this->fileFactory = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\ResourceFactory');
220 }
221
222 return $this->fileFactory;
223 }
224
225 /**
226 * Sets the file repository.
227 *
228 * @param \TYPO3\CMS\Core\Resource\FileRepository $fileRepository
229 * @return void
230 */
231 public function setFileRepository($fileRepository) {
232 $this->fileRepository = $fileRepository;
233 }
234
235 /**
236 * Returns the file repository.
237 *
238 * @return \TYPO3\CMS\Core\Resource\FileRepository
239 */
240 public function getFileRepository() {
241 if ($this->fileRepository === NULL) {
242 $this->fileRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileRepository');
243 }
244
245 return $this->fileRepository;
246 }
247
248 /**
249 * Sets the collection repository.
250 *
251 * @param \TYPO3\CMS\Core\Resource\FileCollectionRepository $collectionRepository
252 * @return void
253 */
254 public function setCollectionRepository($collectionRepository) {
255 $this->collectionRepository = $collectionRepository;
256 }
257
258 /**
259 * Returns the collection repository.
260 *
261 * @return \TYPO3\CMS\Core\Resource\FileCollectionRepository
262 */
263 public function getCollectionRepository() {
264 if ($this->collectionRepository === NULL) {
265 $this->collectionRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileCollectionRepository');
266 }
267
268 return $this->collectionRepository;
269 }
270
271 /**
272 * Handles and resolves file references.
273 *
274 * @param array $configuration TypoScript configuration
275 * @param array $element The parent element referencing to files
276 * @param array $fileObjects Collection of file objects
277 * @return void
278 */
279 protected function handleFileReferences(array $configuration, array $element, array &$fileObjects) {
280 if (empty($configuration['references.'])) {
281 return;
282 }
283
284 // 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
285 $referencesFieldName = $this->cObj->stdWrapValue('fieldName', $configuration['references.']);
286
287 // If no reference fieldName is set, there's nothing to do
288 if (empty($referencesFieldName)) {
289 return;
290 }
291
292 $currentId = !empty($element['uid']) ? $element['uid'] : 0;
293 $tableName = $this->cObj->getCurrentTable();
294
295 // Fetch the references of the default element
296 $referencesForeignTable = $this->cObj->stdWrapValue('table', $configuration['references.'], $tableName);
297 $referencesForeignUid = $this->cObj->stdWrapValue('uid', $configuration['references.'], $currentId);
298
299 $pageRepository = $this->getPageRepository();
300 // Fetch element if definition has been modified via TypoScript
301 if ($referencesForeignTable !== $tableName || $referencesForeignUid !== $currentId) {
302 $element = $pageRepository->getRawRecord(
303 $referencesForeignTable,
304 $referencesForeignUid,
305 '*',
306 FALSE
307 );
308
309 $pageRepository->versionOL($referencesForeignTable, $element, TRUE);
310 if ($referencesForeignTable === 'pages') {
311 $element = $pageRepository->getPageOverlay($element);
312 } else {
313 $element = $pageRepository->getRecordOverlay(
314 $referencesForeignTable,
315 $element,
316 $GLOBALS['TSFE']->sys_language_content,
317 $GLOBALS['TSFE']->sys_language_contentOL
318 );
319 }
320 }
321
322 $references = $pageRepository->getFileReferences(
323 $referencesForeignTable,
324 $referencesFieldName,
325 $element
326 );
327
328 $this->addToArray($references, $fileObjects);
329 }
330
331 /**
332 * Adds $newItems to $theArray, which is passed by reference. Array must only consist of numerical keys.
333 *
334 * @param mixed $newItems Array with new items or single object that's added.
335 * @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).
336 */
337 protected function addToArray($newItems, array &$theArray) {
338 if (is_array($newItems)) {
339 $theArray = array_merge($theArray, $newItems);
340 } elseif (is_object($newItems)) {
341 $theArray[] = $newItems;
342 }
343 }
344
345 /**
346 * Gets a configuration value by passing them through stdWrap first and taking a default value if stdWrap doesn't yield a result.
347 *
348 * @param string $key The config variable key (from TS array).
349 * @param array $config The TypoScript array.
350 * @param string $defaultValue Optional default value.
351 * @return string Value of the config variable
352 * @deprecated since TYPO3 CMS 6.2, use ContentObjectRenderer::stdWrapValue() instead. Will be removed two versions later.
353 */
354 protected function stdWrapValue($key, array $config, $defaultValue = '') {
355 return $this->cObj->stdWrapValue($key, $config, $defaultValue);
356 }
357
358 /**
359 * @return \TYPO3\CMS\Frontend\Page\PageRepository
360 */
361 protected function getPageRepository() {
362 return $GLOBALS['TSFE']->sys_page;
363 }
364
365 }