Total Complexity | 55 |
Total Lines | 454 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like StoragesService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use StoragesService, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
50 | abstract class StoragesService { |
||
51 | |||
52 | /** @var BackendService */ |
||
53 | protected $backendService; |
||
54 | |||
55 | /** |
||
56 | * @var DBConfigService |
||
57 | */ |
||
58 | protected $dbConfig; |
||
59 | |||
60 | /** |
||
61 | * @var IUserMountCache |
||
62 | */ |
||
63 | protected $userMountCache; |
||
64 | |||
65 | /** |
||
66 | * @param BackendService $backendService |
||
67 | * @param DBConfigService $dbConfigService |
||
68 | * @param IUserMountCache $userMountCache |
||
69 | */ |
||
70 | public function __construct(BackendService $backendService, DBConfigService $dbConfigService, IUserMountCache $userMountCache) { |
||
71 | $this->backendService = $backendService; |
||
72 | $this->dbConfig = $dbConfigService; |
||
73 | $this->userMountCache = $userMountCache; |
||
74 | } |
||
75 | |||
76 | protected function readDBConfig() { |
||
77 | return $this->dbConfig->getAdminMounts(); |
||
78 | } |
||
79 | |||
80 | protected function getStorageConfigFromDBMount(array $mount) { |
||
81 | $applicableUsers = array_filter($mount['applicable'], function ($applicable) { |
||
82 | return $applicable['type'] === DBConfigService::APPLICABLE_TYPE_USER; |
||
83 | }); |
||
84 | $applicableUsers = array_map(function ($applicable) { |
||
85 | return $applicable['value']; |
||
86 | }, $applicableUsers); |
||
87 | |||
88 | $applicableGroups = array_filter($mount['applicable'], function ($applicable) { |
||
89 | return $applicable['type'] === DBConfigService::APPLICABLE_TYPE_GROUP; |
||
90 | }); |
||
91 | $applicableGroups = array_map(function ($applicable) { |
||
92 | return $applicable['value']; |
||
93 | }, $applicableGroups); |
||
94 | |||
95 | try { |
||
96 | $config = $this->createStorage( |
||
97 | $mount['mount_point'], |
||
98 | $mount['storage_backend'], |
||
99 | $mount['auth_backend'], |
||
100 | $mount['config'], |
||
101 | $mount['options'], |
||
102 | array_values($applicableUsers), |
||
103 | array_values($applicableGroups), |
||
104 | $mount['priority'] |
||
105 | ); |
||
106 | $config->setType($mount['type']); |
||
107 | $config->setId((int)$mount['mount_id']); |
||
108 | return $config; |
||
109 | } catch (\UnexpectedValueException $e) { |
||
110 | // don't die if a storage backend doesn't exist |
||
111 | \OC::$server->getLogger()->logException($e, [ |
||
112 | 'message' => 'Could not load storage.', |
||
113 | 'level' => ILogger::ERROR, |
||
|
|||
114 | 'app' => 'files_external', |
||
115 | ]); |
||
116 | return null; |
||
117 | } catch (\InvalidArgumentException $e) { |
||
118 | \OC::$server->getLogger()->logException($e, [ |
||
119 | 'message' => 'Could not load storage.', |
||
120 | 'level' => ILogger::ERROR, |
||
121 | 'app' => 'files_external', |
||
122 | ]); |
||
123 | return null; |
||
124 | } |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * Read the external storages config |
||
129 | * |
||
130 | * @return array map of storage id to storage config |
||
131 | */ |
||
132 | protected function readConfig() { |
||
133 | $mounts = $this->readDBConfig(); |
||
134 | $configs = array_map([$this, 'getStorageConfigFromDBMount'], $mounts); |
||
135 | $configs = array_filter($configs, function ($config) { |
||
136 | return $config instanceof StorageConfig; |
||
137 | }); |
||
138 | |||
139 | $keys = array_map(function (StorageConfig $config) { |
||
140 | return $config->getId(); |
||
141 | }, $configs); |
||
142 | |||
143 | return array_combine($keys, $configs); |
||
144 | } |
||
145 | |||
146 | /** |
||
147 | * Get a storage with status |
||
148 | * |
||
149 | * @param int $id storage id |
||
150 | * |
||
151 | * @return StorageConfig |
||
152 | * @throws NotFoundException if the storage with the given id was not found |
||
153 | */ |
||
154 | public function getStorage($id) { |
||
155 | $mount = $this->dbConfig->getMountById($id); |
||
156 | |||
157 | if (!is_array($mount)) { |
||
158 | throw new NotFoundException('Storage with ID "' . $id . '" not found'); |
||
159 | } |
||
160 | |||
161 | $config = $this->getStorageConfigFromDBMount($mount); |
||
162 | if ($this->isApplicable($config)) { |
||
163 | return $config; |
||
164 | } else { |
||
165 | throw new NotFoundException('Storage with ID "' . $id . '" not found'); |
||
166 | } |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Check whether this storage service should provide access to a storage |
||
171 | * |
||
172 | * @param StorageConfig $config |
||
173 | * @return bool |
||
174 | */ |
||
175 | abstract protected function isApplicable(StorageConfig $config); |
||
176 | |||
177 | /** |
||
178 | * Gets all storages, valid or not |
||
179 | * |
||
180 | * @return StorageConfig[] array of storage configs |
||
181 | */ |
||
182 | public function getAllStorages() { |
||
183 | return $this->readConfig(); |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Gets all valid storages |
||
188 | * |
||
189 | * @return StorageConfig[] |
||
190 | */ |
||
191 | public function getStorages() { |
||
192 | return array_filter($this->getAllStorages(), [$this, 'validateStorage']); |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * Validate storage |
||
197 | * FIXME: De-duplicate with StoragesController::validate() |
||
198 | * |
||
199 | * @param StorageConfig $storage |
||
200 | * @return bool |
||
201 | */ |
||
202 | protected function validateStorage(StorageConfig $storage) { |
||
203 | /** @var Backend */ |
||
204 | $backend = $storage->getBackend(); |
||
205 | /** @var AuthMechanism */ |
||
206 | $authMechanism = $storage->getAuthMechanism(); |
||
207 | |||
208 | if (!$backend->isVisibleFor($this->getVisibilityType())) { |
||
209 | // not permitted to use backend |
||
210 | return false; |
||
211 | } |
||
212 | if (!$authMechanism->isVisibleFor($this->getVisibilityType())) { |
||
213 | // not permitted to use auth mechanism |
||
214 | return false; |
||
215 | } |
||
216 | |||
217 | return true; |
||
218 | } |
||
219 | |||
220 | /** |
||
221 | * Get the visibility type for this controller, used in validation |
||
222 | * |
||
223 | * @return string BackendService::VISIBILITY_* constants |
||
224 | */ |
||
225 | abstract public function getVisibilityType(); |
||
226 | |||
227 | /** |
||
228 | * @return integer |
||
229 | */ |
||
230 | protected function getType() { |
||
231 | return DBConfigService::MOUNT_TYPE_ADMIN; |
||
232 | } |
||
233 | |||
234 | /** |
||
235 | * Add new storage to the configuration |
||
236 | * |
||
237 | * @param StorageConfig $newStorage storage attributes |
||
238 | * |
||
239 | * @return StorageConfig storage config, with added id |
||
240 | */ |
||
241 | public function addStorage(StorageConfig $newStorage) { |
||
242 | $allStorages = $this->readConfig(); |
||
243 | |||
244 | $configId = $this->dbConfig->addMount( |
||
245 | $newStorage->getMountPoint(), |
||
246 | $newStorage->getBackend()->getIdentifier(), |
||
247 | $newStorage->getAuthMechanism()->getIdentifier(), |
||
248 | $newStorage->getPriority(), |
||
249 | $this->getType() |
||
250 | ); |
||
251 | |||
252 | $newStorage->setId($configId); |
||
253 | |||
254 | foreach ($newStorage->getApplicableUsers() as $user) { |
||
255 | $this->dbConfig->addApplicable($configId, DBConfigService::APPLICABLE_TYPE_USER, $user); |
||
256 | } |
||
257 | foreach ($newStorage->getApplicableGroups() as $group) { |
||
258 | $this->dbConfig->addApplicable($configId, DBConfigService::APPLICABLE_TYPE_GROUP, $group); |
||
259 | } |
||
260 | foreach ($newStorage->getBackendOptions() as $key => $value) { |
||
261 | $this->dbConfig->setConfig($configId, $key, $value); |
||
262 | } |
||
263 | foreach ($newStorage->getMountOptions() as $key => $value) { |
||
264 | $this->dbConfig->setOption($configId, $key, $value); |
||
265 | } |
||
266 | |||
267 | if (count($newStorage->getApplicableUsers()) === 0 && count($newStorage->getApplicableGroups()) === 0) { |
||
268 | $this->dbConfig->addApplicable($configId, DBConfigService::APPLICABLE_TYPE_GLOBAL, null); |
||
269 | } |
||
270 | |||
271 | // add new storage |
||
272 | $allStorages[$configId] = $newStorage; |
||
273 | |||
274 | $this->triggerHooks($newStorage, Filesystem::signal_create_mount); |
||
275 | |||
276 | $newStorage->setStatus(StorageNotAvailableException::STATUS_SUCCESS); |
||
277 | return $newStorage; |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Create a storage from its parameters |
||
282 | * |
||
283 | * @param string $mountPoint storage mount point |
||
284 | * @param string $backendIdentifier backend identifier |
||
285 | * @param string $authMechanismIdentifier authentication mechanism identifier |
||
286 | * @param array $backendOptions backend-specific options |
||
287 | * @param array|null $mountOptions mount-specific options |
||
288 | * @param array|null $applicableUsers users for which to mount the storage |
||
289 | * @param array|null $applicableGroups groups for which to mount the storage |
||
290 | * @param int|null $priority priority |
||
291 | * |
||
292 | * @return StorageConfig |
||
293 | */ |
||
294 | public function createStorage( |
||
295 | $mountPoint, |
||
296 | $backendIdentifier, |
||
297 | $authMechanismIdentifier, |
||
298 | $backendOptions, |
||
299 | $mountOptions = null, |
||
300 | $applicableUsers = null, |
||
301 | $applicableGroups = null, |
||
302 | $priority = null |
||
303 | ) { |
||
304 | $backend = $this->backendService->getBackend($backendIdentifier); |
||
305 | if (!$backend) { |
||
306 | $backend = new InvalidBackend($backendIdentifier); |
||
307 | } |
||
308 | $authMechanism = $this->backendService->getAuthMechanism($authMechanismIdentifier); |
||
309 | if (!$authMechanism) { |
||
310 | $authMechanism = new InvalidAuth($authMechanismIdentifier); |
||
311 | } |
||
312 | $newStorage = new StorageConfig(); |
||
313 | $newStorage->setMountPoint($mountPoint); |
||
314 | $newStorage->setBackend($backend); |
||
315 | $newStorage->setAuthMechanism($authMechanism); |
||
316 | $newStorage->setBackendOptions($backendOptions); |
||
317 | if (isset($mountOptions)) { |
||
318 | $newStorage->setMountOptions($mountOptions); |
||
319 | } |
||
320 | if (isset($applicableUsers)) { |
||
321 | $newStorage->setApplicableUsers($applicableUsers); |
||
322 | } |
||
323 | if (isset($applicableGroups)) { |
||
324 | $newStorage->setApplicableGroups($applicableGroups); |
||
325 | } |
||
326 | if (isset($priority)) { |
||
327 | $newStorage->setPriority($priority); |
||
328 | } |
||
329 | |||
330 | return $newStorage; |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Triggers the given hook signal for all the applicables given |
||
335 | * |
||
336 | * @param string $signal signal |
||
337 | * @param string $mountPoint hook mount pount param |
||
338 | * @param string $mountType hook mount type param |
||
339 | * @param array $applicableArray array of applicable users/groups for which to trigger the hook |
||
340 | */ |
||
341 | protected function triggerApplicableHooks($signal, $mountPoint, $mountType, $applicableArray) { |
||
350 | ] |
||
351 | ); |
||
352 | } |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * Triggers $signal for all applicable users of the given |
||
357 | * storage |
||
358 | * |
||
359 | * @param StorageConfig $storage storage data |
||
360 | * @param string $signal signal to trigger |
||
361 | */ |
||
362 | abstract protected function triggerHooks(StorageConfig $storage, $signal); |
||
363 | |||
364 | /** |
||
365 | * Triggers signal_create_mount or signal_delete_mount to |
||
366 | * accommodate for additions/deletions in applicableUsers |
||
367 | * and applicableGroups fields. |
||
368 | * |
||
369 | * @param StorageConfig $oldStorage old storage data |
||
370 | * @param StorageConfig $newStorage new storage data |
||
371 | */ |
||
372 | abstract protected function triggerChangeHooks(StorageConfig $oldStorage, StorageConfig $newStorage); |
||
373 | |||
374 | /** |
||
375 | * Update storage to the configuration |
||
376 | * |
||
377 | * @param StorageConfig $updatedStorage storage attributes |
||
378 | * |
||
379 | * @return StorageConfig storage config |
||
380 | * @throws NotFoundException if the given storage does not exist in the config |
||
381 | */ |
||
382 | public function updateStorage(StorageConfig $updatedStorage) { |
||
460 | } |
||
461 | |||
462 | /** |
||
463 | * Delete the storage with the given id. |
||
464 | * |
||
465 | * @param int $id storage id |
||
466 | * |
||
467 | * @throws NotFoundException if no storage was found with the given id |
||
468 | */ |
||
469 | public function removeStorage($id) { |
||
483 | } |
||
484 | |||
485 | /** |
||
486 | * Construct the storage implementation |
||
487 | * |
||
488 | * @param StorageConfig $storageConfig |
||
489 | * @return int |
||
490 | */ |
||
491 | private function getStorageId(StorageConfig $storageConfig) { |
||
507 |
This class constant has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the constant will be removed from the class and what other constant to use instead.