2e9dce97db19a0d97d7e7251e78fa00c07fc30d6
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Resource / FileCollector.php
1 <?php
2 namespace TYPO3\CMS\Frontend\Resource;
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 Psr\Log\LoggerAwareInterface;
18 use Psr\Log\LoggerAwareTrait;
19 use TYPO3\CMS\Core\LinkHandling\LinkService;
20 use TYPO3\CMS\Core\Resource\Exception;
21 use TYPO3\CMS\Core\Resource\FileCollectionRepository;
22 use TYPO3\CMS\Core\Resource\FileInterface;
23 use TYPO3\CMS\Core\Resource\FileRepository;
24 use TYPO3\CMS\Core\Resource\Folder;
25 use TYPO3\CMS\Core\Resource\ResourceFactory;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27
28 /**
29 * Object to collect files from various sources during runtime
30 * Sources can be file references, file collections or folders
31 *
32 * Use in FILES Content Object or for a Fluid Data Processor
33 *
34 * Is not persisted, use only in FE.
35 */
36 class FileCollector implements \Countable, LoggerAwareInterface
37 {
38 use LoggerAwareTrait;
39
40 /**
41 * The files
42 *
43 * @var array
44 */
45 protected $files = [];
46
47 /**
48 * The file repository
49 *
50 * @var \TYPO3\CMS\Core\Resource\FileRepository
51 */
52 protected $fileRepository;
53
54 /**
55 * The file collection repository
56 *
57 * @var \TYPO3\CMS\Core\Resource\FileCollectionRepository
58 */
59 protected $fileCollectionRepository;
60
61 /**
62 * The resource factory
63 *
64 * @var \TYPO3\CMS\Core\Resource\ResourceFactory
65 */
66 protected $resourceFactory;
67
68 /**
69 * Add files
70 *
71 * @param array $fileUids
72 */
73 public function addFiles(array $fileUids = [])
74 {
75 if (!empty($fileUids)) {
76 foreach ($fileUids as $fileUid) {
77 try {
78 $this->addFileObject($this->getResourceFactory()->getFileObject($fileUid));
79 } catch (Exception $e) {
80 $this->logger->warning(
81 'The file with uid "' . $fileUid
82 . '" could not be found and won\'t be included in frontend output',
83 ['exception' => $e]
84 );
85 }
86 }
87 }
88 }
89
90 /**
91 * Add files to the collection from a relation
92 *
93 * @param string $relationTable The table of the relation (e.g. tt_content or pages)
94 * @param string $relationField The field which holds the files (e.g. media or images)
95 * @param array $referenceRecord the record which is referencing the files
96 */
97 public function addFilesFromRelation($relationTable, $relationField, array $referenceRecord)
98 {
99 if (is_object($GLOBALS['TSFE']) && is_object($GLOBALS['TSFE']->sys_page)) {
100 $fileReferences = $GLOBALS['TSFE']->sys_page->getFileReferences($relationTable, $relationField, $referenceRecord);
101 } else {
102 $fileReferences = $this->getFileRepository()->findByRelation($relationTable, $relationField, $referenceRecord['uid']);
103 }
104
105 if (!empty($fileReferences)) {
106 $this->addFileObjects($fileReferences);
107 }
108 }
109
110 /**
111 * Add files from UIDs of a reference
112 *
113 * @param array $fileReferenceUids
114 */
115 public function addFileReferences(array $fileReferenceUids = [])
116 {
117 foreach ($fileReferenceUids as $fileReferenceUid) {
118 $fileObject = $this->getFileRepository()->findFileReferenceByUid($fileReferenceUid);
119 $this->addFileObject($fileObject);
120 }
121 }
122
123 /**
124 * Add files to the collection from multiple file collections
125 *
126 * @param array $fileCollectionUids The file collections uids
127 */
128 public function addFilesFromFileCollections(array $fileCollectionUids = [])
129 {
130 foreach ($fileCollectionUids as $fileCollectionUid) {
131 $this->addFilesFromFileCollection($fileCollectionUid);
132 }
133 }
134
135 /**
136 * Add files to the collection from one single file collection
137 *
138 * @param int $fileCollectionUid The file collections uid
139 */
140 public function addFilesFromFileCollection($fileCollectionUid = null)
141 {
142 if (!empty($fileCollectionUid)) {
143 try {
144 $fileCollection = $this->getFileCollectionRepository()->findByUid($fileCollectionUid);
145
146 if ($fileCollection instanceof \TYPO3\CMS\Core\Resource\Collection\AbstractFileCollection) {
147 $fileCollection->loadContents();
148 $files = $fileCollection->getItems();
149
150 $this->addFileObjects($files);
151 }
152 } catch (Exception $e) {
153 $this->logger->warning(
154 'The file-collection with uid "' . $fileCollectionUid
155 . '" could not be found or contents could not be loaded and won\'t be included in frontend output.',
156 ['exception' => $e]
157 );
158 }
159 }
160 }
161
162 /**
163 * Add files to the collection from multiple folders
164 *
165 * @param array $folderIdentifiers The folder identifiers
166 * @param bool $recursive Add files recursive from given folders
167 */
168 public function addFilesFromFolders(array $folderIdentifiers = [], $recursive = false)
169 {
170 foreach ($folderIdentifiers as $folderIdentifier) {
171 $this->addFilesFromFolder($folderIdentifier, $recursive);
172 }
173 }
174
175 /**
176 * Add files to the collection from one single folder
177 *
178 * @param string $folderIdentifier The folder identifier
179 * @param bool $recursive Add files recursive from given folders
180 */
181 public function addFilesFromFolder($folderIdentifier, $recursive = false)
182 {
183 if ($folderIdentifier) {
184 try {
185 if (strpos($folderIdentifier, 't3://folder') === 0) {
186 // a t3://folder link to a folder in FAL
187 $linkService = GeneralUtility::makeInstance(LinkService::class);
188 $data = $linkService->resolveByStringRepresentation($folderIdentifier);
189 $folder = $data['folder'];
190 } else {
191 $folder = $this->getResourceFactory()->getFolderObjectFromCombinedIdentifier($folderIdentifier);
192 }
193 if ($folder instanceof Folder) {
194 $files = $folder->getFiles(0, 0, Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, $recursive);
195 $this->addFileObjects(array_values($files));
196 }
197 } catch (Exception $e) {
198 $this->logger->warning(
199 'The folder with identifier "' . $folderIdentifier
200 . '" could not be found and won\'t be included in frontend output',
201 ['exception' => $e]
202 );
203 }
204 }
205 }
206
207 /**
208 * Sort the file objects based on a property
209 *
210 * @param string $sortingProperty The sorting property
211 * @param string $sortingOrder can be ascending or descending or "random"
212 */
213 public function sort($sortingProperty = '', $sortingOrder = 'ascending')
214 {
215 if ($sortingProperty !== '' && count($this->files) > 1) {
216 @usort(
217 $this->files,
218 function (
219 FileInterface $a,
220 FileInterface $b
221 ) use ($sortingProperty) {
222 if ($a->hasProperty($sortingProperty) && $b->hasProperty($sortingProperty)) {
223 return strnatcasecmp($a->getProperty($sortingProperty), $b->getProperty($sortingProperty));
224 }
225 return 0;
226 }
227 );
228
229 switch (strtolower($sortingOrder)) {
230 case 'descending':
231 case 'desc':
232 $this->files = array_reverse($this->files);
233 break;
234 case 'random':
235 case 'rand':
236 shuffle($this->files);
237 break;
238 }
239 }
240 }
241
242 /**
243 * Add a file object to the collection
244 *
245 * @param FileInterface $file The file object
246 */
247 public function addFileObject(FileInterface $file)
248 {
249 $this->files[] = $file;
250 }
251
252 /**
253 * Add multiple file objects to the collection
254 *
255 * @param FileInterface[] $files The file objects
256 */
257 public function addFileObjects($files)
258 {
259 $this->files = array_merge($this->files, $files);
260 }
261
262 /**
263 * Final getter method to fetch the accumulated data
264 *
265 * @return array
266 */
267 public function getFiles()
268 {
269 return $this->files;
270 }
271
272 /**
273 * @return int
274 */
275 public function count()
276 {
277 return count($this->files);
278 }
279
280 /**
281 * @return ResourceFactory
282 */
283 protected function getResourceFactory()
284 {
285 if ($this->resourceFactory === null) {
286 $this->resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
287 }
288 return $this->resourceFactory;
289 }
290
291 /**
292 * @return FileCollectionRepository
293 */
294 protected function getFileCollectionRepository()
295 {
296 if ($this->fileCollectionRepository === null) {
297 $this->fileCollectionRepository = GeneralUtility::makeInstance(FileCollectionRepository::class);
298 }
299 return $this->fileCollectionRepository;
300 }
301
302 /**
303 * @return FileRepository
304 */
305 protected function getFileRepository()
306 {
307 if ($this->fileRepository === null) {
308 $this->fileRepository = GeneralUtility::makeInstance(FileRepository::class);
309 }
310 return $this->fileRepository;
311 }
312 }