[TASK] Streamline PageRepository->getRawRecord
[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
39 $fileCollector = $this->findAndSortFiles($conf);
40 $fileObjects = $fileCollector->getFiles();
41 $availableFileObjectCount = count($fileObjects);
42
43 // optionSplit applied to conf to allow different settings per file
44 $splitConf = GeneralUtility::makeInstance(TypoScriptService::class)
45 ->explodeConfigurationForOptionSplit($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, !empty($conf['folders.']['recursive']));
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
165 // 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
166 $referencesFieldName = $this->cObj->stdWrapValue('fieldName', $configuration['references.']);
167
168 // If no reference fieldName is set, there's nothing to do
169 if (empty($referencesFieldName)) {
170 return;
171 }
172
173 $currentId = !empty($element['uid']) ? $element['uid'] : 0;
174 $tableName = $this->cObj->getCurrentTable();
175
176 // Fetch the references of the default element
177 $referencesForeignTable = $this->cObj->stdWrapValue('table', $configuration['references.'], $tableName);
178 $referencesForeignUid = $this->cObj->stdWrapValue('uid', $configuration['references.'], $currentId);
179
180 $pageRepository = $this->getPageRepository();
181 // Fetch element if definition has been modified via TypoScript
182 if ($referencesForeignTable !== $tableName || $referencesForeignUid !== $currentId) {
183 $element = $pageRepository->getRawRecord($referencesForeignTable, $referencesForeignUid);
184
185 $pageRepository->versionOL($referencesForeignTable, $element, true);
186 if ($referencesForeignTable === 'pages') {
187 $element = $pageRepository->getPageOverlay($element);
188 } else {
189 $element = $pageRepository->getRecordOverlay(
190 $referencesForeignTable,
191 $element,
192 $GLOBALS['TSFE']->sys_language_content,
193 $GLOBALS['TSFE']->sys_language_contentOL
194 );
195 }
196 }
197
198 if (is_array($element)) {
199 $fileCollector->addFilesFromRelation($referencesForeignTable, $referencesFieldName, $element);
200 }
201 }
202
203 /**
204 * @return \TYPO3\CMS\Frontend\Page\PageRepository
205 */
206 protected function getPageRepository()
207 {
208 return $GLOBALS['TSFE']->sys_page;
209 }
210
211 /**
212 * @return FileCollector
213 */
214 protected function getFileCollector()
215 {
216 return GeneralUtility::makeInstance(FileCollector::class);
217 }
218 }