|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Charcoal\App\ServiceProvider; |
|
4
|
|
|
|
|
5
|
|
|
use Exception; |
|
6
|
|
|
use LogicException; |
|
7
|
|
|
use InvalidArgumentException; |
|
8
|
|
|
use UnexpectedValueException; |
|
9
|
|
|
|
|
10
|
|
|
// Dependencies from `pimple/pimple` |
|
11
|
|
|
use Pimple\ServiceProviderInterface; |
|
12
|
|
|
use Pimple\Container; |
|
13
|
|
|
|
|
14
|
|
|
// Dependencies from AWS S3 SDK |
|
15
|
|
|
use Aws\S3\S3Client; |
|
16
|
|
|
|
|
17
|
|
|
// Dependencies from Dropbox |
|
18
|
|
|
use Dropbox\Client as DropboxClient; |
|
19
|
|
|
|
|
20
|
|
|
// Dependencies from `league/flysystem` |
|
21
|
|
|
use League\Flysystem\MountManager; |
|
22
|
|
|
use League\Flysystem\Filesystem; |
|
23
|
|
|
use League\Flysystem\Adapter\Local as LocalAdapter; |
|
24
|
|
|
use League\Flysystem\Adapter\Ftp as FtpAdapter; |
|
25
|
|
|
use League\Flysystem\Adapter\NullAdapter; |
|
26
|
|
|
|
|
27
|
|
|
// Dependency from `league/flysystem-aws-s3-v3` |
|
28
|
|
|
use League\Flysystem\AwsS3v3\AwsS3Adapter; |
|
29
|
|
|
|
|
30
|
|
|
// Dependency from `league/flysystem-dropbox` |
|
31
|
|
|
use League\Flysystem\Dropbox\DropboxAdapter; |
|
32
|
|
|
|
|
33
|
|
|
// Dependency from `league/flysystem-sftp` |
|
34
|
|
|
use League\Flysystem\Sftp\SftpAdapter; |
|
35
|
|
|
|
|
36
|
|
|
// Dependency from `league/flysystem-memory` |
|
37
|
|
|
use League\Flysystem\Memory\MemoryAdapter; |
|
38
|
|
|
|
|
39
|
|
|
// Local namespace depdency |
|
40
|
|
|
use Charcoal\App\Config\FilesystemConfig; |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* |
|
44
|
|
|
*/ |
|
45
|
|
|
class FilesystemServiceProvider implements ServiceProviderInterface |
|
46
|
|
|
{ |
|
47
|
|
|
/** |
|
48
|
|
|
* @param Container $container Pimple DI Container. |
|
49
|
|
|
* @return void |
|
50
|
|
|
*/ |
|
51
|
|
|
public function register(Container $container) |
|
52
|
|
|
{ |
|
53
|
|
|
/** |
|
54
|
|
|
* @param Container $container Pimple DI Container. |
|
55
|
|
|
* @return FlysystemConfig |
|
56
|
|
|
*/ |
|
57
|
|
View Code Duplication |
$container['filesystem/config'] = function (Container $container) { |
|
|
|
|
|
|
58
|
|
|
$appConfig = isset($container['config']) ? $container['config'] : []; |
|
59
|
|
|
$fsConfig = isset($appConfig['filesystem']) ? $appConfig['filesystem'] : null; |
|
60
|
|
|
return new FilesystemConfig($fsConfig); |
|
61
|
|
|
}; |
|
62
|
|
|
|
|
63
|
|
|
/** |
|
64
|
|
|
* @param Container $container Pimple DI Container. |
|
65
|
|
|
* @return MountManager |
|
66
|
|
|
*/ |
|
67
|
|
|
$container['filesystem/manager'] = function () { |
|
68
|
|
|
return new MountManager(); |
|
69
|
|
|
}; |
|
70
|
|
|
|
|
71
|
|
|
$container['filesystems'] = function (Container $container) { |
|
72
|
|
|
$filesystemConfig = $container['filesystem/config']; |
|
73
|
|
|
$filesystems = new Container(); |
|
74
|
|
|
|
|
75
|
|
|
foreach ($filesystemConfig['connections'] as $ident => $connection) { |
|
76
|
|
|
$fs = $this->createConnection($connection); |
|
77
|
|
|
$filesystems[$ident] = $fs; |
|
78
|
|
|
$container['filesystem/manager']->mountFilesystem($ident, $fs); |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
return $filesystems; |
|
82
|
|
|
}; |
|
83
|
|
|
} |
|
84
|
|
|
|
|
85
|
|
|
/** |
|
86
|
|
|
* @param array $config The driver (adapter) configuration. |
|
87
|
|
|
* @throws Exception If the filesystem type is not defined in config. |
|
88
|
|
|
* @throws UnexpectedValueException If the filesystem type is invalid / unsupported. |
|
89
|
|
|
* @return Filesystem |
|
90
|
|
|
*/ |
|
91
|
|
|
private function createConnection(array $config) |
|
92
|
|
|
{ |
|
93
|
|
|
if (!isset($config['type'])) { |
|
94
|
|
|
throw new Exception( |
|
95
|
|
|
'No filesystem type defined' |
|
96
|
|
|
); |
|
97
|
|
|
} |
|
98
|
|
|
|
|
99
|
|
|
$type = $config['type']; |
|
100
|
|
|
|
|
101
|
|
|
if ($type == 'local') { |
|
102
|
|
|
$adapter = $this->createLocalAdapter($config); |
|
103
|
|
|
} elseif ($type == 's3') { |
|
104
|
|
|
$adapter = $this->createS3Adapter($config); |
|
105
|
|
|
} elseif ($type == 'dropbox') { |
|
106
|
|
|
$adapter = $this->createDropboxAdapter($config); |
|
107
|
|
|
} elseif ($type == 'ftp') { |
|
108
|
|
|
$adapter = $this->createFtpAdapter($config); |
|
109
|
|
|
} elseif ($type == 'sftp') { |
|
110
|
|
|
$adapter = $this->createSftpAdapter($config); |
|
111
|
|
|
} elseif ($type == 'memory') { |
|
112
|
|
|
$adapter = $this->createMemoryAdapter(); |
|
113
|
|
|
} elseif ($type == 'noop') { |
|
114
|
|
|
$adapter = $this->createNullAdapter(); |
|
115
|
|
|
} else { |
|
116
|
|
|
throw new UnexpectedValueException( |
|
117
|
|
|
sprintf('Invalid filesystem type "%s"', $type) |
|
118
|
|
|
); |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
|
|
return new Filesystem($adapter); |
|
122
|
|
|
} |
|
123
|
|
|
|
|
124
|
|
|
/** |
|
125
|
|
|
* @param array $config The driver (adapter) configuration. |
|
126
|
|
|
* @throws InvalidArgumentException If the path is not defined. |
|
127
|
|
|
* @throws LogicException If the path is not accessible. |
|
128
|
|
|
* @return LocalAdapter |
|
129
|
|
|
*/ |
|
130
|
|
|
private function createLocalAdapter(array $config) |
|
131
|
|
|
{ |
|
132
|
|
|
if (!isset($config['path']) || !$config['path']) { |
|
133
|
|
|
throw new InvalidArgumentException( |
|
134
|
|
|
'No "path" configured for local filesystem.' |
|
135
|
|
|
); |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
$path = realpath($config['path']); |
|
139
|
|
|
if ($path === false) { |
|
140
|
|
|
throw new LogicException( |
|
141
|
|
|
'Filesystem "path" does not exist.' |
|
142
|
|
|
); |
|
143
|
|
|
} |
|
144
|
|
|
|
|
145
|
|
|
$defaults = [ |
|
146
|
|
|
'lock' => null, |
|
147
|
|
|
'links' => null, |
|
148
|
|
|
'permissions' => [] |
|
149
|
|
|
]; |
|
150
|
|
|
$config = array_merge($defaults, $config); |
|
151
|
|
|
|
|
152
|
|
|
return new LocalAdapter($config['path'], $config['lock'], $config['links'], $config['permissions']); |
|
153
|
|
|
} |
|
154
|
|
|
|
|
155
|
|
|
/** |
|
156
|
|
|
* @param array $config The driver (adapter) configuration. |
|
157
|
|
|
* @throws InvalidArgumentException If the key, secret or bucket is not defined in config. |
|
158
|
|
|
* @return AwsS3Adapter |
|
159
|
|
|
*/ |
|
160
|
|
|
private function createS3Adapter(array $config) |
|
161
|
|
|
{ |
|
162
|
|
|
if (!isset($config['key']) || !$config['key']) { |
|
163
|
|
|
throw new InvalidArgumentException( |
|
164
|
|
|
'No "key" configured for S3 filesystem.' |
|
165
|
|
|
); |
|
166
|
|
|
} |
|
167
|
|
|
if (!isset($config['secret']) || !$config['secret']) { |
|
168
|
|
|
throw new InvalidArgumentException( |
|
169
|
|
|
'No "secret" configured for S3 filesystem.' |
|
170
|
|
|
); |
|
171
|
|
|
} |
|
172
|
|
|
|
|
173
|
|
|
if (!isset($config['bucket']) || !$config['bucket']) { |
|
174
|
|
|
throw new InvalidArgumentException( |
|
175
|
|
|
'No "bucket" configured for S3 filesystem.' |
|
176
|
|
|
); |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
$defaults = [ |
|
180
|
|
|
'region' => '', |
|
181
|
|
|
'version' => 'latest', |
|
182
|
|
|
'prefix' => null |
|
183
|
|
|
]; |
|
184
|
|
|
$config = array_merge($defaults, $config); |
|
185
|
|
|
|
|
186
|
|
|
$client = S3Client::factory([ |
|
|
|
|
|
|
187
|
|
|
'credentials' => [ |
|
188
|
|
|
'key' => $config['key'], |
|
189
|
|
|
'secret' => $config['secret'], |
|
190
|
|
|
], |
|
191
|
|
|
'region' => $config['region'], |
|
192
|
|
|
'version' => $config['version'], |
|
193
|
|
|
]); |
|
194
|
|
|
|
|
195
|
|
|
if (isset($config['public']) && !$config['public']) { |
|
196
|
|
|
$permissions = null; |
|
197
|
|
|
} else { |
|
198
|
|
|
$permissions = [ |
|
199
|
|
|
'ACL' => 'public-read' |
|
200
|
|
|
]; |
|
201
|
|
|
} |
|
202
|
|
|
|
|
203
|
|
|
return new AwsS3Adapter($client, $config['bucket'], $config['prefix'], $permissions); |
|
|
|
|
|
|
204
|
|
|
} |
|
205
|
|
|
|
|
206
|
|
|
/** |
|
207
|
|
|
* @param array $config The driver (adapter) configuration. |
|
208
|
|
|
* @throws InvalidArgumentException If the token or secret is not defined in config. |
|
209
|
|
|
* @return DropboxAdapter |
|
210
|
|
|
*/ |
|
211
|
|
|
private function createDropboxAdapter(array $config) |
|
212
|
|
|
{ |
|
213
|
|
|
if (!isset($config['token']) || !$config['token']) { |
|
214
|
|
|
throw new InvalidArgumentException( |
|
215
|
|
|
'No access "token" configured for dropbox filesystem adapter.' |
|
216
|
|
|
); |
|
217
|
|
|
} |
|
218
|
|
|
|
|
219
|
|
|
if (!isset($config['secret']) || !$config['secret']) { |
|
220
|
|
|
throw new InvalidArgumentException( |
|
221
|
|
|
'No app "secret" configured for dropbox filesystem adapter.' |
|
222
|
|
|
); |
|
223
|
|
|
} |
|
224
|
|
|
|
|
225
|
|
|
$defaults = [ |
|
226
|
|
|
'prefix' => '' |
|
227
|
|
|
]; |
|
228
|
|
|
$config = array_merge($defaults, $config); |
|
229
|
|
|
|
|
230
|
|
|
$client = new DropboxClient($config['token'], $config['secret']); |
|
231
|
|
|
return new DropboxAdapter($client, $config['prefix']); |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
/** |
|
235
|
|
|
* @param array $config The driver (adapter) configuration. |
|
236
|
|
|
* @throws InvalidArgumentException If the host, username or password is not defined in config. |
|
237
|
|
|
* @return FtpAdapter |
|
238
|
|
|
*/ |
|
239
|
|
View Code Duplication |
private function createFtpAdapter(array $config) |
|
|
|
|
|
|
240
|
|
|
{ |
|
241
|
|
|
if (!$config['host']) { |
|
242
|
|
|
throw new InvalidArgumentException( |
|
243
|
|
|
'No host configured for FTP filesystem adapter.' |
|
244
|
|
|
); |
|
245
|
|
|
} |
|
246
|
|
|
if (!$config['username']) { |
|
247
|
|
|
throw new InvalidArgumentException( |
|
248
|
|
|
'No username configured for FTP filesystem adapter.' |
|
249
|
|
|
); |
|
250
|
|
|
} |
|
251
|
|
|
if (!$config['password']) { |
|
252
|
|
|
throw new InvalidArgumentException( |
|
253
|
|
|
'No password configured for FTP filesystem adapter.' |
|
254
|
|
|
); |
|
255
|
|
|
} |
|
256
|
|
|
|
|
257
|
|
|
$defaults = [ |
|
258
|
|
|
'port' => null, |
|
259
|
|
|
'root' => null, |
|
260
|
|
|
'passive' => null, |
|
261
|
|
|
'ssl' => null, |
|
262
|
|
|
'timeout' => null |
|
263
|
|
|
]; |
|
264
|
|
|
$config = array_merge($defaults, $config); |
|
265
|
|
|
|
|
266
|
|
|
return new FtpAdapter($config); |
|
267
|
|
|
} |
|
268
|
|
|
|
|
269
|
|
|
/** |
|
270
|
|
|
* @param array $config The driver (adapter) configuration. |
|
271
|
|
|
* @throws InvalidArgumentException If the host, username or password is not defined in config. |
|
272
|
|
|
* @return SftpAdapter |
|
273
|
|
|
*/ |
|
274
|
|
View Code Duplication |
private function createSftpAdapter(array $config) |
|
|
|
|
|
|
275
|
|
|
{ |
|
276
|
|
|
if (!$config['host']) { |
|
277
|
|
|
throw new InvalidArgumentException( |
|
278
|
|
|
'No host configured for SFTP filesystem adapter.' |
|
279
|
|
|
); |
|
280
|
|
|
} |
|
281
|
|
|
if (!$config['username']) { |
|
282
|
|
|
throw new InvalidArgumentException( |
|
283
|
|
|
'No username configured for SFTP filesystem adapter.' |
|
284
|
|
|
); |
|
285
|
|
|
} |
|
286
|
|
|
if (!$config['password']) { |
|
287
|
|
|
throw new InvalidArgumentException( |
|
288
|
|
|
'No password configured for SFTP filesystem adapter.' |
|
289
|
|
|
); |
|
290
|
|
|
} |
|
291
|
|
|
|
|
292
|
|
|
$defaults = [ |
|
293
|
|
|
'port' => null, |
|
294
|
|
|
'privateKey' => null, |
|
295
|
|
|
'root' => null, |
|
296
|
|
|
'timeout' => null |
|
297
|
|
|
]; |
|
298
|
|
|
$config = array_merge($defaults, $config); |
|
299
|
|
|
|
|
300
|
|
|
return new SftpAdapter($config); |
|
301
|
|
|
} |
|
302
|
|
|
|
|
303
|
|
|
/** |
|
304
|
|
|
* @return MemoryAdapter |
|
305
|
|
|
*/ |
|
306
|
|
|
private function createMemoryAdapter() |
|
307
|
|
|
{ |
|
308
|
|
|
return new MemoryAdapter(); |
|
309
|
|
|
} |
|
310
|
|
|
|
|
311
|
|
|
/** |
|
312
|
|
|
* @return NullAdapter |
|
313
|
|
|
*/ |
|
314
|
|
|
private function createNullAdapter() |
|
315
|
|
|
{ |
|
316
|
|
|
return new NullAdapter(); |
|
317
|
|
|
} |
|
318
|
|
|
} |
|
319
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.