[!!!][TASK] Remove POST option from typolink.addQueryString.method
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / StorageRepository.php
1 <?php
2 namespace TYPO3\CMS\Core\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\Configuration\FlexForm\FlexFormTools;
20 use TYPO3\CMS\Core\Core\Environment;
21 use TYPO3\CMS\Core\Database\ConnectionPool;
22 use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24
25 /**
26 * Repository for accessing the file mounts
27 */
28 class StorageRepository extends AbstractRepository implements LoggerAwareInterface
29 {
30 use LoggerAwareTrait;
31
32 /**
33 * @var array|null
34 */
35 protected $storageRowCache;
36
37 /**
38 * @var string
39 */
40 protected $objectType = ResourceStorage::class;
41
42 /**
43 * @var string
44 */
45 protected $table = 'sys_file_storage';
46
47 /**
48 * @var string
49 */
50 protected $typeField = 'driver';
51
52 /**
53 * @var string
54 */
55 protected $driverField = 'driver';
56
57 /**
58 * @param int $uid
59 *
60 * @return ResourceStorage|null
61 */
62 public function findByUid($uid)
63 {
64 $this->initializeLocalCache();
65 if (isset($this->storageRowCache[$uid])) {
66 return $this->factory->getStorageObject($uid, $this->storageRowCache[$uid]);
67 }
68 return null;
69 }
70
71 /**
72 * Initializes the Storage
73 */
74 protected function initializeLocalCache()
75 {
76 if ($this->storageRowCache === null) {
77 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
78 ->getQueryBuilderForTable($this->table);
79
80 if ($this->getEnvironmentMode() === 'FE') {
81 $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
82 }
83
84 $result = $queryBuilder
85 ->select('*')
86 ->from($this->table)
87 ->orderBy('name')
88 ->execute();
89
90 $this->storageRowCache = [];
91 while ($row = $result->fetch()) {
92 if (!empty($row['uid'])) {
93 $this->storageRowCache[$row['uid']] = $row;
94 }
95 }
96
97 // if no storage is created before or the user has not access to a storage
98 // $this->storageRowCache would have the value array()
99 // so check if there is any record. If no record is found, create the fileadmin/ storage
100 // selecting just one row is enough
101
102 if ($this->storageRowCache === []) {
103 $connection = GeneralUtility::makeInstance(ConnectionPool::class)
104 ->getConnectionForTable($this->table);
105
106 $storageObjectsCount = $connection->count('uid', $this->table, []);
107
108 if ($storageObjectsCount === 0) {
109 if ($this->createLocalStorage(
110 'fileadmin/ (auto-created)',
111 $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'],
112 'relative',
113 'This is the local fileadmin/ directory. This storage mount has been created automatically by TYPO3.',
114 true
115 ) > 0) {
116 // reset to null to force reloading of storages
117 $this->storageRowCache = null;
118 // call self for initialize Cache
119 $this->initializeLocalCache();
120 }
121 }
122 }
123 }
124 }
125
126 /**
127 * Finds storages by type, i.e. the driver used
128 *
129 * @param string $storageType
130 * @return ResourceStorage[]
131 */
132 public function findByStorageType($storageType)
133 {
134 $this->initializeLocalCache();
135
136 /** @var Driver\DriverRegistry $driverRegistry */
137 $driverRegistry = GeneralUtility::makeInstance(Driver\DriverRegistry::class);
138
139 $storageObjects = [];
140 foreach ($this->storageRowCache as $storageRow) {
141 if ($storageRow['driver'] !== $storageType) {
142 continue;
143 }
144 if ($driverRegistry->driverExists($storageRow['driver'])) {
145 $storageObjects[] = $this->factory->getStorageObject($storageRow['uid'], $storageRow);
146 } else {
147 $this->logger->warning(
148 sprintf('Could not instantiate storage "%s" because of missing driver.', [$storageRow['name']]),
149 $storageRow
150 );
151 }
152 }
153 return $storageObjects;
154 }
155
156 /**
157 * Returns a list of mountpoints that are available in the VFS.
158 * In case no storage exists this automatically created a storage for fileadmin/
159 *
160 * @return ResourceStorage[]
161 */
162 public function findAll()
163 {
164 $this->initializeLocalCache();
165
166 /** @var Driver\DriverRegistry $driverRegistry */
167 $driverRegistry = GeneralUtility::makeInstance(Driver\DriverRegistry::class);
168
169 $storageObjects = [];
170 foreach ($this->storageRowCache as $storageRow) {
171 if ($driverRegistry->driverExists($storageRow['driver'])) {
172 $storageObjects[] = $this->factory->getStorageObject($storageRow['uid'], $storageRow);
173 } else {
174 $this->logger->warning(
175 sprintf('Could not instantiate storage "%s" because of missing driver.', [$storageRow['name']]),
176 $storageRow
177 );
178 }
179 }
180 return $storageObjects;
181 }
182
183 /**
184 * Create the initial local storage base e.g. for the fileadmin/ directory.
185 *
186 * @param string $name
187 * @param string $basePath
188 * @param string $pathType
189 * @param string $description
190 * @param bool $default set to default storage
191 * @return int uid of the inserted record
192 */
193 public function createLocalStorage($name, $basePath, $pathType, $description = '', $default = false)
194 {
195 $caseSensitive = $this->testCaseSensitivity($pathType === 'relative' ? Environment::getPublicPath() . '/' . $basePath : $basePath);
196 // create the FlexForm for the driver configuration
197 $flexFormData = [
198 'data' => [
199 'sDEF' => [
200 'lDEF' => [
201 'basePath' => ['vDEF' => rtrim($basePath, '/') . '/'],
202 'pathType' => ['vDEF' => $pathType],
203 'caseSensitive' => ['vDEF' => $caseSensitive]
204 ]
205 ]
206 ]
207 ];
208
209 /** @var FlexFormTools $flexObj */
210 $flexObj = GeneralUtility::makeInstance(FlexFormTools::class);
211 $flexFormXml = $flexObj->flexArray2Xml($flexFormData, true);
212
213 // create the record
214 $field_values = [
215 'pid' => 0,
216 'tstamp' => $GLOBALS['EXEC_TIME'],
217 'crdate' => $GLOBALS['EXEC_TIME'],
218 'name' => $name,
219 'description' => $description,
220 'driver' => 'Local',
221 'configuration' => $flexFormXml,
222 'is_online' => 1,
223 'is_browsable' => 1,
224 'is_public' => 1,
225 'is_writable' => 1,
226 'is_default' => $default ? 1 : 0
227 ];
228
229 $dbConnection = GeneralUtility::makeInstance(ConnectionPool::class)
230 ->getConnectionForTable($this->table);
231 $dbConnection->insert($this->table, $field_values);
232
233 // Flush local resourceStorage cache so the storage can be accessed during the same request right away
234 $this->storageRowCache = null;
235
236 return (int)$dbConnection->lastInsertId($this->table);
237 }
238
239 /**
240 * Creates an object managed by this repository.
241 *
242 * @param array $databaseRow
243 * @return ResourceStorage
244 */
245 protected function createDomainObject(array $databaseRow)
246 {
247 return $this->factory->getStorageObject($databaseRow['uid'], $databaseRow);
248 }
249
250 /**
251 * Test if the local filesystem is case sensitive
252 *
253 * @param string $absolutePath
254 * @return bool
255 */
256 protected function testCaseSensitivity($absolutePath)
257 {
258 $caseSensitive = true;
259 $path = rtrim($absolutePath, '/') . '/aAbB';
260 $testFileExists = @file_exists($path);
261
262 // create test file
263 if (!$testFileExists) {
264 touch($path);
265 }
266
267 // do the actual sensitivity check
268 if (@file_exists(strtoupper($path)) && @file_exists(strtolower($path))) {
269 $caseSensitive = false;
270 }
271
272 // clean filesystem
273 if (!$testFileExists) {
274 unlink($path);
275 }
276
277 return $caseSensitive;
278 }
279 }