[TASK] Optimize invocation of cObj::checkIf
[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 \TYPO3\CMS\Frontend\ContentObject\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')->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')->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')->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')->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 if (is_array($conf['sorting.']) && isset($conf['sorting.']['direction']) && strtolower($conf['sorting.']['direction']) === 'desc') {
152 $fileObjects = array_reverse($fileObjects);
153 }
154 }
155
156 $availableFileObjectCount = count($fileObjects);
157
158 $start = 0;
159 if (!empty($conf['begin'])) {
160 $start = (int)$conf['begin'];
161 }
162 if (!empty($conf['begin.'])) {
163 $start = (int)$this->cObj->stdWrap($start, $conf['begin.']);
164 }
165 $start = MathUtility::forceIntegerInRange($start, 0, $availableFileObjectCount);
166
167 $limit = $availableFileObjectCount;
168 if (!empty($conf['maxItems'])) {
169 $limit = (int)$conf['maxItems'];
170 }
171 if (!empty($conf['maxItems.'])) {
172 $limit = (int)$this->cObj->stdWrap($limit, $conf['maxItems.']);
173 }
174
175 $end = MathUtility::forceIntegerInRange($start + $limit, $start, $availableFileObjectCount);
176
177 $GLOBALS['TSFE']->register['FILES_COUNT'] = min($limit, $availableFileObjectCount);
178 $fileObjectCounter = 0;
179 $keys = array_keys($fileObjects);
180 for ($i = $start; $i < $end; $i++) {
181 $key = $keys[$i];
182 $fileObject = $fileObjects[$key];
183
184 $GLOBALS['TSFE']->register['FILE_NUM_CURRENT'] = $fileObjectCounter;
185 $this->cObj->setCurrentFile($fileObject);
186 $content .= $this->cObj->cObjGetSingle($splitConf[$key]['renderObj'], $splitConf[$key]['renderObj.']);
187 $fileObjectCounter++;
188 }
189 $content = $this->cObj->stdWrap($content, $conf['stdWrap.']);
190 return $content;
191 }
192
193 /**
194 * Sets the file factory.
195 *
196 * @param \TYPO3\CMS\Core\Resource\ResourceFactory $fileFactory
197 * @return void
198 */
199 public function setFileFactory($fileFactory) {
200 $this->fileFactory = $fileFactory;
201 }
202
203 /**
204 * Returns the file factory.
205 *
206 * @return \TYPO3\CMS\Core\Resource\ResourceFactory
207 */
208 public function getFileFactory() {
209 if ($this->fileFactory === NULL) {
210 $this->fileFactory = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\ResourceFactory');
211 }
212
213 return $this->fileFactory;
214 }
215
216 /**
217 * Sets the file repository.
218 *
219 * @param \TYPO3\CMS\Core\Resource\FileRepository $fileRepository
220 * @return void
221 */
222 public function setFileRepository($fileRepository) {
223 $this->fileRepository = $fileRepository;
224 }
225
226 /**
227 * Returns the file repository.
228 *
229 * @return \TYPO3\CMS\Core\Resource\FileRepository
230 */
231 public function getFileRepository() {
232 if ($this->fileRepository === NULL) {
233 $this->fileRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileRepository');
234 }
235
236 return $this->fileRepository;
237 }
238
239 /**
240 * Sets the collection repository.
241 *
242 * @param \TYPO3\CMS\Core\Resource\FileCollectionRepository $collectionRepository
243 * @return void
244 */
245 public function setCollectionRepository($collectionRepository) {
246 $this->collectionRepository = $collectionRepository;
247 }
248
249 /**
250 * Returns the collection repository.
251 *
252 * @return \TYPO3\CMS\Core\Resource\FileCollectionRepository
253 */
254 public function getCollectionRepository() {
255 if ($this->collectionRepository === NULL) {
256 $this->collectionRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileCollectionRepository');
257 }
258
259 return $this->collectionRepository;
260 }
261
262 /**
263 * Handles and resolves file references.
264 *
265 * @param array $configuration TypoScript configuration
266 * @param array $element The parent element referencing to files
267 * @param array $fileObjects Collection of file objects
268 * @return void
269 */
270 protected function handleFileReferences(array $configuration, array $element, array &$fileObjects) {
271 if (empty($configuration['references.'])) {
272 return;
273 }
274
275 // 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
276 $referencesFieldName = $this->cObj->stdWrapValue('fieldName', $configuration['references.']);
277
278 // If no reference fieldName is set, there's nothing to do
279 if (empty($referencesFieldName)) {
280 return;
281 }
282
283 $currentId = !empty($element['uid']) ? $element['uid'] : 0;
284 $tableName = $this->cObj->getCurrentTable();
285
286 // Fetch the references of the default element
287 $referencesForeignTable = $this->cObj->stdWrapValue('table', $configuration['references.'], $tableName);
288 $referencesForeignUid = $this->cObj->stdWrapValue('uid', $configuration['references.'], $currentId);
289
290 $pageRepository = $this->getPageRepository();
291 // Fetch element if definition has been modified via TypoScript
292 if ($referencesForeignTable !== $tableName || $referencesForeignUid !== $currentId) {
293 $element = $pageRepository->getRawRecord(
294 $referencesForeignTable,
295 $referencesForeignUid,
296 '*',
297 FALSE
298 );
299
300 $pageRepository->versionOL($referencesForeignTable, $element, TRUE);
301 if ($referencesForeignTable === 'pages') {
302 $element = $pageRepository->getPageOverlay($element);
303 } else {
304 $element = $pageRepository->getRecordOverlay(
305 $referencesForeignTable,
306 $element,
307 $GLOBALS['TSFE']->sys_language_content,
308 $GLOBALS['TSFE']->sys_language_contentOL
309 );
310 }
311 }
312
313 $references = $pageRepository->getFileReferences(
314 $referencesForeignTable,
315 $referencesFieldName,
316 $element
317 );
318
319 $this->addToArray($references, $fileObjects);
320 }
321
322 /**
323 * Adds $newItems to $theArray, which is passed by reference. Array must only consist of numerical keys.
324 *
325 * @param mixed $newItems Array with new items or single object that's added.
326 * @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).
327 */
328 protected function addToArray($newItems, array &$theArray) {
329 if (is_array($newItems)) {
330 $theArray = array_merge($theArray, $newItems);
331 } elseif (is_object($newItems)) {
332 $theArray[] = $newItems;
333 }
334 }
335
336 /**
337 * Gets a configuration value by passing them through stdWrap first and taking a default value if stdWrap doesn't yield a result.
338 *
339 * @param string $key The config variable key (from TS array).
340 * @param array $config The TypoScript array.
341 * @param string $defaultValue Optional default value.
342 * @return string Value of the config variable
343 * @deprecated since TYPO3 CMS 6.2, use ContentObjectRenderer::stdWrapValue() instead. Will be removed two versions later.
344 */
345 protected function stdWrapValue($key, array $config, $defaultValue = '') {
346 return $this->cObj->stdWrapValue($key, $config, $defaultValue);
347 }
348
349 /**
350 * @return \TYPO3\CMS\Frontend\Page\PageRepository
351 */
352 protected function getPageRepository() {
353 return $GLOBALS['TSFE']->sys_page;
354 }
355
356 }