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