21dd8d92430bcab78ddc66bc37c8820ee348ddc3
[Packages/TYPO3.CMS.git] / typo3 / sysext / recordlist / Classes / LinkHandler / FileLinkHandler.php
1 <?php
2 namespace TYPO3\CMS\Recordlist\LinkHandler;
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\Http\Message\ServerRequestInterface;
18 use TYPO3\CMS\Backend\Tree\View\ElementBrowserFolderTreeView;
19 use TYPO3\CMS\Core\Imaging\Icon;
20 use TYPO3\CMS\Core\LinkHandling\LinkService;
21 use TYPO3\CMS\Core\Page\PageRenderer;
22 use TYPO3\CMS\Core\Resource\File;
23 use TYPO3\CMS\Core\Resource\FileInterface;
24 use TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter;
25 use TYPO3\CMS\Core\Resource\Folder;
26 use TYPO3\CMS\Core\Resource\ResourceFactory;
27 use TYPO3\CMS\Core\Resource\ResourceInterface;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29 use TYPO3\CMS\Recordlist\Tree\View\LinkParameterProviderInterface;
30 use TYPO3\CMS\Recordlist\View\FolderUtilityRenderer;
31
32 /**
33 * Link handler for files
34 */
35 class FileLinkHandler extends AbstractLinkHandler implements LinkHandlerInterface, LinkParameterProviderInterface
36 {
37 /**
38 * Parts of the current link
39 *
40 * @var array
41 */
42 protected $linkParts = [];
43
44 /**
45 * @var string
46 */
47 protected $expectedClass = File::class;
48
49 /**
50 * @var string
51 */
52 protected $mode = 'file';
53
54 /**
55 * @var string
56 */
57 protected $expandFolder;
58
59 /**
60 * Checks if this is the handler for the given link
61 *
62 * The handler may store this information locally for later usage.
63 *
64 * @param array $linkParts Link parts as returned from TypoLinkCodecService
65 *
66 * @return bool
67 */
68 public function canHandleLink(array $linkParts)
69 {
70 if (!$linkParts['url']) {
71 return false;
72 }
73 if (isset($linkParts['url'][$this->mode]) && $linkParts['url'][$this->mode] instanceof $this->expectedClass) {
74 $this->linkParts = $linkParts;
75 return true;
76 }
77 return false;
78 }
79
80 /**
81 * Format the current link for HTML output
82 *
83 * @return string
84 */
85 public function formatCurrentUrl()
86 {
87 return $this->linkParts['url'][$this->mode]->getName();
88 }
89
90 /**
91 * Render the link handler
92 *
93 * @param ServerRequestInterface $request
94 *
95 * @return string
96 */
97 public function render(ServerRequestInterface $request)
98 {
99 GeneralUtility::makeInstance(PageRenderer::class)->loadRequireJsModule('TYPO3/CMS/Recordlist/FileLinkHandler');
100
101 /** @var ElementBrowserFolderTreeView $folderTree */
102 $folderTree = GeneralUtility::makeInstance(ElementBrowserFolderTreeView::class);
103 $folderTree->setLinkParameterProvider($this);
104 $this->view->assign('tree', $folderTree->getBrowsableTree());
105
106 $this->expandFolder = isset($request->getQueryParams()['expandFolder']) ? $request->getQueryParams()['expandFolder'] : null;
107 if (!empty($this->linkParts) && !isset($this->expandFolder)) {
108 $this->expandFolder = $this->linkParts['url'][$this->mode];
109 if ($this->expandFolder instanceof File) {
110 $this->expandFolder = $this->expandFolder->getParentFolder();
111 }
112 if ($this->expandFolder instanceof Folder) {
113 $this->expandFolder = $this->expandFolder->getCombinedIdentifier();
114 }
115 }
116
117 // Create upload/create folder forms, if a path is given
118 $selectedFolder = $this->getSelectedFolder($this->expandFolder);
119
120 // Build the file upload and folder creation form
121 if ($selectedFolder) {
122 $folderUtilityRenderer = GeneralUtility::makeInstance(FolderUtilityRenderer::class, $this);
123 $uploadForm = $this->mode === 'file' ? $folderUtilityRenderer->uploadForm($selectedFolder, []) : '';
124 $createFolder = $folderUtilityRenderer->createFolder($selectedFolder);
125
126 // Insert the upload form on top, if so configured
127 $positionOfUploadFieldsOnTop = $this->getBackendUser()->getTSConfigVal('options.uploadFieldsInTopOfEB');
128 $this->view->assign('positionOfUploadFields', $positionOfUploadFieldsOnTop ? 'top' : 'bottom');
129 $this->view->assign('uploadFileForm', $uploadForm);
130 $this->view->assign('createFolderForm', $createFolder);
131
132 // Render the file or folderlist
133 if ($selectedFolder->checkActionPermission('read')) {
134 $this->view->assign('selectedFolder', $selectedFolder);
135 $parameters = $this->linkBrowser->getUrlParameters();
136 $allowedExtensions = isset($parameters['allowedExtensions']) ? $parameters['allowedExtensions'] : '';
137 $this->expandFolder($selectedFolder, $allowedExtensions);
138 }
139 }
140
141 return $this->view->render(ucfirst($this->mode));
142 }
143
144 /**
145 * For RTE: This displays all files from folder. No thumbnails shown
146 *
147 * @param Folder $folder The folder path to expand
148 * @param string $extensionList List of file extensions to show
149 * @return string HTML output
150 */
151 public function expandFolder(Folder $folder, $extensionList = '')
152 {
153 // Create header element; The folder from which files are listed.
154 $folderIcon = $this->iconFactory->getIconForResource($folder, Icon::SIZE_SMALL)->render();
155 $this->view->assign('selectedFolderIcon', $folderIcon);
156 $this->view->assign('selectedFolderTitle', GeneralUtility::fixed_lgd_cs($folder->getIdentifier(), (int)$this->getBackendUser()->uc['titleLen']));
157 if ($this->mode === 'file') {
158 $this->view->assign('currentIdentifier', !empty($this->linkParts) ? $this->linkParts['url']['file']->getUid() : '');
159 } else {
160 $this->view->assign('currentIdentifier', !empty($this->linkParts) ? $this->linkParts['url']['folder']->getCombinedIdentifier() : '');
161 }
162
163 // Get files from the folder:
164 $fileObjects = $this->getFolderContent($folder, $extensionList);
165 $itemsInSelectedFolder = [];
166 if (!empty($fileObjects)) {
167 foreach ($fileObjects as $fileOrFolderObject) {
168 $itemsInSelectedFolder[] = $this->renderItem($fileOrFolderObject);
169 }
170 }
171 $this->view->assign('itemsInSelectedFolder', $itemsInSelectedFolder);
172 }
173
174 /**
175 * @param Folder $folder
176 * @param string $extensionList
177 *
178 * @return FileInterface[]|Folder[]
179 */
180 protected function getFolderContent(Folder $folder, $extensionList)
181 {
182 if ($extensionList !== '') {
183 /** @var FileExtensionFilter $filter */
184 $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
185 $filter->setAllowedFileExtensions($extensionList);
186 $folder->setFileAndFolderNameFilters([[$filter, 'filterFileList']]);
187 }
188 return $folder->getFiles();
189 }
190
191 /**
192 * Renders a single item displayed in the current folder
193 *
194 * @param ResourceInterface $fileOrFolderObject
195 *
196 * @return array
197 * @throws \InvalidArgumentException
198 */
199 protected function renderItem(ResourceInterface $fileOrFolderObject)
200 {
201 if (!$fileOrFolderObject instanceof File) {
202 throw new \InvalidArgumentException('Expected File object, got "' . get_class($fileOrFolderObject) . '" object.', 1443651368);
203 }
204 // Get size and icon:
205 $size = GeneralUtility::formatSize(
206 $fileOrFolderObject->getSize(),
207 $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_common.xlf:byteSizeUnits')
208 );
209
210 return [
211 'icon' => $this->iconFactory->getIconForResource($fileOrFolderObject, Icon::SIZE_SMALL)->render(),
212 'uid' => $fileOrFolderObject->getUid(),
213 'size' => $size,
214 'name' => $fileOrFolderObject->getName(),
215 'url' => GeneralUtility::makeInstance(LinkService::class)->asString(['type' => LinkService::TYPE_FILE, 'file' => $fileOrFolderObject]),
216 'title' => GeneralUtility::fixed_lgd_cs($fileOrFolderObject->getName(), (int)$this->getBackendUser()->uc['titleLen'])
217 ];
218 }
219
220 /**
221 * @return string[] Array of body-tag attributes
222 */
223 public function getBodyTagAttributes()
224 {
225 return [
226 'data-current-link' => GeneralUtility::makeInstance(LinkService::class)->asString(['type' => LinkService::TYPE_FILE, 'file' => $this->linkParts['url']['file']])
227 ];
228 }
229
230 /**
231 * @param array $values Array of values to include into the parameters or which might influence the parameters
232 *
233 * @return string[] Array of parameters which have to be added to URLs
234 */
235 public function getUrlParameters(array $values)
236 {
237 $parameters = [
238 'expandFolder' => $values['identifier'] ?? $this->expandFolder
239 ];
240 return array_merge($this->linkBrowser->getUrlParameters($values), $parameters);
241 }
242
243 /**
244 * @param array $values Values to be checked
245 *
246 * @return bool Returns TRUE if the given values match the currently selected item
247 */
248 public function isCurrentlySelectedItem(array $values)
249 {
250 return false;
251 }
252
253 /**
254 * Returns the URL of the current script
255 *
256 * @return string
257 */
258 public function getScriptUrl()
259 {
260 return $this->linkBrowser->getScriptUrl();
261 }
262
263 /**
264 * Returns the currently selected folder, or th default upload folder
265 *
266 * @param string $folderIdentifier
267 * @return mixed the folder object or false if nothing was found
268 */
269 protected function getSelectedFolder($folderIdentifier = '')
270 {
271 $selectedFolder = false;
272 if ($folderIdentifier) {
273 try {
274 $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($folderIdentifier);
275 if ($fileOrFolderObject instanceof Folder) {
276 // It's a folder
277 $selectedFolder = $fileOrFolderObject;
278 } elseif ($fileOrFolderObject instanceof FileInterface) {
279 // It's a file
280 try {
281 $selectedFolder = $fileOrFolderObject->getParentFolder();
282 } catch (\Exception $e) {
283 // Accessing the parent folder failed for some reason. e.g. permissions
284 }
285 }
286 } catch (\Exception $e) {
287 // No path is selected
288 }
289 }
290
291 // If no folder is selected, get the user's default upload folder
292 if (!$selectedFolder) {
293 try {
294 $selectedFolder = $this->getBackendUser()->getDefaultUploadFolder();
295 } catch (\Exception $e) {
296 // The configured default user folder does not exist
297 }
298 }
299 return $selectedFolder;
300 }
301 }