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