1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace BePark\Flysystem\ReadOnlyFallback; |
4
|
|
|
|
5
|
|
|
use League\Flysystem\AdapterInterface; |
6
|
|
|
use League\Flysystem\Config; |
7
|
|
|
use League\Flysystem\Util; |
8
|
|
|
|
9
|
|
|
class ReadOnlyFallbackAdapter implements AdapterInterface |
10
|
|
|
{ |
11
|
|
|
protected $_readOnlyAdapter; |
12
|
|
|
|
13
|
|
|
protected $_mainAdapter; |
14
|
|
|
|
15
|
|
|
public function __construct(AdapterInterface $mainAdapter, AdapterInterface $readOnlyAdapter) |
16
|
|
|
{ |
17
|
2 |
|
$this->_mainAdapter = $mainAdapter; |
18
|
2 |
|
$this->_readOnlyAdapter = $readOnlyAdapter; |
19
|
2 |
|
} |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Returns the main adapter |
23
|
|
|
* |
24
|
|
|
* @return AdapterInterface |
25
|
|
|
*/ |
26
|
|
|
public function getMainAdapter() |
27
|
|
|
{ |
28
|
2 |
|
return $this->_mainAdapter; |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Returns the fallback adapter |
33
|
|
|
* |
34
|
|
|
* @return AdapterInterface |
35
|
|
|
*/ |
36
|
|
|
public function getReadOnlyAdapter() |
37
|
2 |
|
{ |
38
|
2 |
|
return $this->_readOnlyAdapter; |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* {@inheritdoc} |
43
|
|
|
*/ |
44
|
|
|
public function write($path, $contents, Config $config) |
45
|
2 |
|
{ |
46
|
2 |
|
return $this->_mainAdapter->write($path, $contents, $config); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* {@inheritdoc} |
51
|
|
|
*/ |
52
|
|
|
public function writeStream($path, $resource, Config $config) |
53
|
|
|
{ |
54
|
2 |
|
return $this->_mainAdapter->writeStream($path, $resource, $config); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* {@inheritdoc} |
59
|
|
|
*/ |
60
|
|
|
public function update($path, $contents, Config $config) |
61
|
|
|
{ |
62
|
2 |
|
$this->_backportFromReadOnly($path); |
63
|
|
|
|
64
|
2 |
|
return $this->_mainAdapter->update($path, $contents, $config); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* {@inheritdoc} |
69
|
|
|
*/ |
70
|
|
|
public function updateStream($path, $resource, Config $config) |
71
|
|
|
{ |
72
|
|
|
$this->_backportFromReadOnly($path); |
73
|
|
|
|
74
|
|
|
return $this->_mainAdapter->updateStream($path, $resource, $config); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* {@inheritdoc} |
79
|
|
|
*/ |
80
|
|
|
public function rename($path, $newpath) |
81
|
|
|
{ |
82
|
|
|
// XXX we could probably make some improvements here without duplicate the source |
83
|
|
|
$this->_backportFromReadOnly($path); |
84
|
|
|
|
85
|
2 |
|
return $this->_mainAdapter->rename($path, $newpath); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* {@inheritdoc} |
90
|
|
|
*/ |
91
|
|
|
public function copy($path, $newpath) |
92
|
|
|
{ |
93
|
|
|
// XXX we could probably make some improvements here without duplicate the source |
94
|
|
|
$this->_backportFromReadOnly($path); |
95
|
|
|
|
96
|
|
|
return $this->_mainAdapter->copy($path, $newpath); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* {@inheritdoc} |
101
|
|
|
*/ |
102
|
|
|
public function delete($path) |
103
|
|
|
{ |
104
|
2 |
|
if ($this->_readOnlyAdapter->has($path) && !$this->_mainAdapter->has($path)) |
105
|
2 |
|
{ |
106
|
|
|
// will always be find but yeah except if we have an adapter that retains the delete information, it's impossible to |
107
|
|
|
// do something. So enjoy a weird thing |
108
|
2 |
|
return true; |
109
|
|
|
} |
110
|
|
|
|
111
|
2 |
|
return $this->_mainAdapter->delete($path); |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* {@inheritdoc} |
116
|
|
|
*/ |
117
|
|
|
public function deleteDir($dirname) |
118
|
|
|
{ |
119
|
|
|
if ($this->_readOnlyAdapter->has($dirname) && !$this->_mainAdapter->has($dirname)) |
120
|
|
|
{ |
121
|
|
|
return true; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
return $this->_mainAdapter->deleteDir($dirname); |
125
|
2 |
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* {@inheritdoc} |
129
|
|
|
*/ |
130
|
|
|
public function createDir($dirname, Config $config) |
131
|
|
|
{ |
132
|
|
|
return $this->_mainAdapter->createDir($dirname, $config); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* {@inheritdoc} |
137
|
|
|
*/ |
138
|
|
|
public function setVisibility($path, $visibility) |
139
|
|
|
{ |
140
|
|
|
$this->_backportFromReadOnly($path); |
141
|
|
|
|
142
|
|
|
return $this->_mainAdapter->setVisibility($path, $visibility); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* {@inheritdoc} |
147
|
|
|
*/ |
148
|
|
|
public function has($path) |
149
|
|
|
{ |
150
|
2 |
|
return $this->_mainAdapter->has($path) || $this->_readOnlyAdapter->has($path); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* {@inheritdoc} |
155
|
|
|
*/ |
156
|
|
|
public function read($path) |
157
|
|
|
{ |
158
|
2 |
|
if ($this->_mainAdapter->has($path)) |
159
|
2 |
|
{ |
160
|
2 |
|
return $this->_mainAdapter->read($path); |
161
|
2 |
|
} |
162
|
|
|
|
163
|
|
|
|
164
|
2 |
|
return $this->_readOnlyAdapter->read($path); |
165
|
2 |
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* {@inheritdoc} |
169
|
|
|
*/ |
170
|
|
|
public function readStream($path) |
171
|
|
|
{ |
172
|
|
|
if ($this->_mainAdapter->has($path)) |
173
|
|
|
{ |
174
|
|
|
return $this->_mainAdapter->readStream($path); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
return $this->_readOnlyAdapter->readStream($path); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
//TODO |
181
|
|
|
/** |
182
|
|
|
* {@inheritdoc} |
183
|
|
|
* @see https://github.com/Litipk/flysystem-fallback-adapter/blob/master/src/FallbackAdapter.php#L259 |
184
|
|
|
*/ |
185
|
|
|
public function listContents($directory = '', $recursive = false) |
186
|
|
|
{ |
187
|
|
|
// taken from https://github.com/Litipk/flysystem-fallback-adapter/blob/master/src/FallbackAdapter.php#L259 |
188
|
|
|
// listContents |
189
|
|
|
$tmpResult = $this->_mainAdapter->listContents($directory, $recursive); |
190
|
2 |
|
|
191
|
|
|
$inverseRef = []; |
192
|
2 |
|
foreach ($tmpResult as $index => $mainContent) |
193
|
2 |
|
{ |
194
|
|
|
$inverseRef[$mainContent['path']] = $index; |
195
|
2 |
|
} |
196
|
2 |
|
|
197
|
|
|
$fallbackContents = $this->_readOnlyAdapter->listContents($directory, $recursive); |
198
|
2 |
|
foreach ($fallbackContents as $fallbackContent) |
199
|
2 |
|
{ |
200
|
|
|
if (!isset($inverseRef[$fallbackContent['path']])) |
201
|
2 |
|
{ |
202
|
2 |
|
$tmpResult[] = $fallbackContent; |
203
|
|
|
} |
204
|
|
|
} |
205
|
2 |
|
|
206
|
|
|
return $tmpResult; |
207
|
2 |
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* {@inheritdoc} |
211
|
|
|
*/ |
212
|
|
|
public function getMetadata($path) |
213
|
|
|
{ |
214
|
|
|
if ($this->_mainAdapter->has($path)) |
215
|
2 |
|
{ |
216
|
2 |
|
return $this->_mainAdapter->getMetadata($path); |
217
|
2 |
|
} |
218
|
2 |
|
|
219
|
|
|
return $this->_readOnlyAdapter->getMetadata($path); |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* {@inheritdoc} |
224
|
|
|
*/ |
225
|
|
|
public function getSize($path) |
226
|
|
|
{ |
227
|
|
|
if ($this->_mainAdapter->has($path)) |
228
|
|
|
{ |
229
|
|
|
return $this->_mainAdapter->getSize($path); |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
return $this->_readOnlyAdapter->getSize($path); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* {@inheritdoc} |
237
|
|
|
*/ |
238
|
|
|
public function getMimetype($path) |
239
|
|
|
{ |
240
|
|
|
if ($this->_mainAdapter->has($path)) |
241
|
|
|
{ |
242
|
|
|
return $this->_mainAdapter->getMimetype($path); |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
return $this->_readOnlyAdapter->getMimetype($path); |
246
|
|
|
} |
247
|
|
|
|
248
|
|
|
/** |
249
|
|
|
* {@inheritdoc} |
250
|
|
|
*/ |
251
|
|
|
public function getTimestamp($path) |
252
|
|
|
{ |
253
|
|
|
if ($this->_mainAdapter->has($path)) |
254
|
|
|
{ |
255
|
|
|
return $this->_mainAdapter->getTimestamp($path); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
return $this->_readOnlyAdapter->getTimestamp($path); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* {@inheritdoc} |
263
|
|
|
*/ |
264
|
|
|
public function getVisibility($path) |
265
|
|
|
{ |
266
|
|
|
if ($this->_mainAdapter->has($path)) |
267
|
|
|
{ |
268
|
|
|
return $this->_mainAdapter->getVisibility($path); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
return $this->_readOnlyAdapter->getVisibility($path); |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
/** |
275
|
|
|
* Make resource available for modification on the new adapter |
276
|
|
|
* @param string $path |
277
|
|
|
* @return bool |
278
|
|
|
*/ |
279
|
|
|
protected function _backportFromReadOnly($path) |
280
|
|
|
{ |
281
|
|
|
// do nothing if it exist on the main or if the read only have none |
282
|
|
|
if ($this->_mainAdapter->has($path) || !$this->_readOnlyAdapter->has($path)) |
283
|
|
|
{ |
284
|
|
|
return true; |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
// because we change something we need to be sure to have it on the main adapter before anything |
288
|
2 |
|
$buffer = $this->_readOnlyAdapter->readStream($path); |
289
|
2 |
|
if (false === $buffer) |
290
|
2 |
|
{ |
291
|
|
|
return false; |
292
|
|
|
} |
293
|
|
|
|
294
|
2 |
|
return $this->_mainAdapter->writeStream($path, $buffer['stream'], new Config()); |
295
|
2 |
|
if (is_resource($buffer['stream'])) |
|
|
|
|
296
|
2 |
|
{ |
297
|
|
|
fclose($buffer['stream']); |
298
|
|
|
} |
299
|
|
|
|
300
|
2 |
|
return (false !== $result); |
301
|
2 |
|
} |
302
|
|
|
} |
303
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.