|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace FlyCrud; |
|
4
|
|
|
|
|
5
|
|
|
use League\Flysystem\FilesystemInterface; |
|
6
|
|
|
use League\Flysystem\Filesystem; |
|
7
|
|
|
use League\Flysystem\Adapter\Local; |
|
8
|
|
|
use ArrayAccess; |
|
9
|
|
|
|
|
10
|
|
|
class Directory implements ArrayAccess |
|
11
|
|
|
{ |
|
12
|
|
|
protected $path; |
|
13
|
|
|
protected $format; |
|
14
|
|
|
protected $filesystem; |
|
15
|
|
|
protected $documents = []; |
|
16
|
|
|
protected $directories = []; |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* Creates a new directory instance. |
|
20
|
|
|
* |
|
21
|
|
|
* @param string $path |
|
22
|
|
|
* @param FormatInterface $format |
|
23
|
|
|
* |
|
24
|
|
|
* @return static |
|
25
|
|
|
*/ |
|
26
|
|
|
public static function make($path, FormatInterface $format) |
|
27
|
|
|
{ |
|
28
|
|
|
return new static(new Filesystem(new Local($path)), '', $format); |
|
29
|
|
|
} |
|
30
|
|
|
|
|
31
|
|
|
/** |
|
32
|
|
|
* Init the directory. |
|
33
|
|
|
* |
|
34
|
|
|
* @param FilesystemInterface $filesystem |
|
35
|
|
|
* @param string $path |
|
36
|
|
|
* @param FormatInterface $format |
|
37
|
|
|
*/ |
|
38
|
|
|
public function __construct(FilesystemInterface $filesystem, $path, FormatInterface $format) |
|
39
|
|
|
{ |
|
40
|
|
|
$this->filesystem = $filesystem; |
|
41
|
|
|
$this->format = $format; |
|
42
|
|
|
$this->path = $path; |
|
43
|
|
|
} |
|
44
|
|
|
|
|
45
|
|
|
/** |
|
46
|
|
|
* Read and return a document. |
|
47
|
|
|
* |
|
48
|
|
|
* @param string $id |
|
49
|
|
|
* |
|
50
|
|
|
* @return Document |
|
51
|
|
|
*/ |
|
52
|
|
|
public function getDocument($id) |
|
53
|
|
|
{ |
|
54
|
|
|
if (isset($this->documents[$id])) { |
|
55
|
|
|
return $this->documents[$id]; |
|
56
|
|
|
} |
|
57
|
|
|
|
|
58
|
|
|
if ($this->hasDocument($id)) { |
|
59
|
|
|
$path = $this->getDocumentPath($id); |
|
60
|
|
|
$source = $this->filesystem->read($path); |
|
61
|
|
|
|
|
62
|
|
|
if (is_string($source)) { |
|
63
|
|
|
return $this->documents[$id] = new Document($this->format->parse($source)); |
|
64
|
|
|
} |
|
65
|
|
|
|
|
66
|
|
|
throw new Exception(sprintf('Format error in the file "%s"', $path)); |
|
67
|
|
|
} |
|
68
|
|
|
|
|
69
|
|
|
throw new Exception(sprintf('File "%s" not found', $path)); |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
/** |
|
73
|
|
|
* Read and return a directory. |
|
74
|
|
|
* |
|
75
|
|
|
* @param string $id |
|
76
|
|
|
* |
|
77
|
|
|
* @return Document |
|
78
|
|
|
*/ |
|
79
|
|
|
public function getDirectory($id) |
|
80
|
|
|
{ |
|
81
|
|
|
if (isset($this->directories[$id])) { |
|
82
|
|
|
return $this->directories[$id]; |
|
83
|
|
|
} |
|
84
|
|
|
|
|
85
|
|
|
if ($this->hasDirectory($id)) { |
|
86
|
|
|
return $this->directories[$id] = new static($this->filesystem, $this->getDirectoryPath($id), $this->format); |
|
|
|
|
|
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
|
|
throw new Exception(sprintf('Directory "%s" not found', $path)); |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
/** |
|
93
|
|
|
* Check whether a document exists. |
|
94
|
|
|
* |
|
95
|
|
|
* @param string $id |
|
96
|
|
|
* |
|
97
|
|
|
* @return bool |
|
98
|
|
|
*/ |
|
99
|
|
View Code Duplication |
public function hasDocument($id) |
|
|
|
|
|
|
100
|
|
|
{ |
|
101
|
|
|
if (isset($this->documents[$id])) { |
|
102
|
|
|
return true; |
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
|
|
$path = $this->getDocumentPath($id); |
|
106
|
|
|
|
|
107
|
|
|
if ($this->filesystem->has($path)) { |
|
108
|
|
|
$info = $this->filesystem->getMetadata($path); |
|
109
|
|
|
|
|
110
|
|
|
return $info['type'] === 'file'; |
|
111
|
|
|
} |
|
112
|
|
|
|
|
113
|
|
|
return false; |
|
114
|
|
|
} |
|
115
|
|
|
|
|
116
|
|
|
/** |
|
117
|
|
|
* Check whether a document or directory exists. |
|
118
|
|
|
* |
|
119
|
|
|
* @param string $id |
|
120
|
|
|
* |
|
121
|
|
|
* @return bool |
|
122
|
|
|
*/ |
|
123
|
|
View Code Duplication |
public function hasDirectory($id) |
|
|
|
|
|
|
124
|
|
|
{ |
|
125
|
|
|
if (isset($this->directories[$id])) { |
|
126
|
|
|
return true; |
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
$path = $this->getDirectoryPath($id); |
|
130
|
|
|
|
|
131
|
|
|
if ($this->filesystem->has($path)) { |
|
132
|
|
|
$info = $this->filesystem->getMetadata($path); |
|
133
|
|
|
|
|
134
|
|
|
return $info['type'] === 'dir'; |
|
135
|
|
|
} |
|
136
|
|
|
|
|
137
|
|
|
return false; |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
|
|
/** |
|
141
|
|
|
* Saves a document. |
|
142
|
|
|
* |
|
143
|
|
|
* @param string $id |
|
144
|
|
|
* @param Document $document |
|
145
|
|
|
* |
|
146
|
|
|
* @return self |
|
147
|
|
|
*/ |
|
148
|
|
|
public function saveDocument($id, Document $document) |
|
149
|
|
|
{ |
|
150
|
|
|
$this->documents[$id] = $document; |
|
151
|
|
|
$this->filesystem->put($this->getDocumentPath($id), $this->format->stringify($document->getArrayCopy())); |
|
152
|
|
|
|
|
153
|
|
|
return $this; |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
/** |
|
157
|
|
|
* Creates a new directory. |
|
158
|
|
|
* |
|
159
|
|
|
* @param string $id |
|
160
|
|
|
* |
|
161
|
|
|
* @return self |
|
162
|
|
|
*/ |
|
163
|
|
|
public function createDirectory($id) |
|
164
|
|
|
{ |
|
165
|
|
|
$path = $this->getDirectoryPath($id); |
|
166
|
|
|
$this->filesystem->createDir($path); |
|
167
|
|
|
|
|
168
|
|
|
return $this->directories[$id] = new static($this->filesystem, $path, $this->format); |
|
169
|
|
|
} |
|
170
|
|
|
|
|
171
|
|
|
/** |
|
172
|
|
|
* Deletes a document. |
|
173
|
|
|
* |
|
174
|
|
|
* @param string $id |
|
175
|
|
|
* |
|
176
|
|
|
* @return self |
|
177
|
|
|
*/ |
|
178
|
|
|
public function deleteDocument($id) |
|
179
|
|
|
{ |
|
180
|
|
|
$this->filesystem->delete($this->getDocumentPath($id)); |
|
181
|
|
|
unset($this->documents[$id]); |
|
182
|
|
|
|
|
183
|
|
|
return $this; |
|
184
|
|
|
} |
|
185
|
|
|
|
|
186
|
|
|
/** |
|
187
|
|
|
* Deletes a directory. |
|
188
|
|
|
* |
|
189
|
|
|
* @param string $id |
|
190
|
|
|
* |
|
191
|
|
|
* @return self |
|
192
|
|
|
*/ |
|
193
|
|
|
public function deleteDirectory($id) |
|
194
|
|
|
{ |
|
195
|
|
|
$this->filesystem->deleteDir($this->getDirectoryPath($id)); |
|
196
|
|
|
unset($this->directories[$id]); |
|
197
|
|
|
|
|
198
|
|
|
return $this; |
|
199
|
|
|
} |
|
200
|
|
|
|
|
201
|
|
|
/** |
|
202
|
|
|
* Returns all documents. |
|
203
|
|
|
* |
|
204
|
|
|
* @return array |
|
205
|
|
|
*/ |
|
206
|
|
View Code Duplication |
public function getAllDocuments() |
|
|
|
|
|
|
207
|
|
|
{ |
|
208
|
|
|
$documents = []; |
|
209
|
|
|
|
|
210
|
|
|
foreach ($this->filesystem->listContents('/'.$this->path) as $info) { |
|
211
|
|
|
$id = $info['filename']; |
|
212
|
|
|
|
|
213
|
|
|
if ($this->hasDocument($id)) { |
|
214
|
|
|
$documents[$id] = $this->getDocument($id); |
|
215
|
|
|
} |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
|
|
return $documents; |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
/** |
|
222
|
|
|
* Returns all directories. |
|
223
|
|
|
* |
|
224
|
|
|
* @return array |
|
225
|
|
|
*/ |
|
226
|
|
View Code Duplication |
public function getAllDirectories() |
|
|
|
|
|
|
227
|
|
|
{ |
|
228
|
|
|
$directories = []; |
|
229
|
|
|
|
|
230
|
|
|
foreach ($this->filesystem->listContents('/'.$this->path) as $info) { |
|
231
|
|
|
$id = $info['filename']; |
|
232
|
|
|
|
|
233
|
|
|
if ($this->hasDirectory($id)) { |
|
234
|
|
|
$directories[$id] = $this->getDirectory($id); |
|
235
|
|
|
} |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
return $directories; |
|
239
|
|
|
} |
|
240
|
|
|
|
|
241
|
|
|
/** |
|
242
|
|
|
* Returns a file path. |
|
243
|
|
|
* |
|
244
|
|
|
* @param string $id |
|
245
|
|
|
* |
|
246
|
|
|
* @return string |
|
247
|
|
|
*/ |
|
248
|
|
|
private function getDocumentPath($id) |
|
249
|
|
|
{ |
|
250
|
|
|
return $this->getDirectoryPath($id).'.'.$this->format->getExtension(); |
|
251
|
|
|
} |
|
252
|
|
|
|
|
253
|
|
|
/** |
|
254
|
|
|
* Returns a directory path. |
|
255
|
|
|
* |
|
256
|
|
|
* @param string $id |
|
257
|
|
|
* |
|
258
|
|
|
* @return string |
|
259
|
|
|
*/ |
|
260
|
|
|
private function getDirectoryPath($id) |
|
261
|
|
|
{ |
|
262
|
|
|
if ($this->path === '') { |
|
263
|
|
|
return "/{$id}"; |
|
264
|
|
|
} |
|
265
|
|
|
|
|
266
|
|
|
return "/{$this->path}/{$id}"; |
|
267
|
|
|
} |
|
268
|
|
|
|
|
269
|
|
|
private function getPathType($path) |
|
|
|
|
|
|
270
|
|
|
{ |
|
271
|
|
|
if ($this->filesystem->has($path)) { |
|
272
|
|
|
$info = $this->filesystem->getMetadata($path); |
|
273
|
|
|
|
|
274
|
|
|
return $info['type']; |
|
275
|
|
|
} |
|
276
|
|
|
} |
|
277
|
|
|
|
|
278
|
|
|
/** |
|
279
|
|
|
* ArrayAccess used to documents. |
|
280
|
|
|
* |
|
281
|
|
|
* @param string $id |
|
282
|
|
|
* |
|
283
|
|
|
* @return bool |
|
284
|
|
|
*/ |
|
285
|
|
|
public function offsetExists($id) |
|
286
|
|
|
{ |
|
287
|
|
|
return $this->hasDocument($id); |
|
288
|
|
|
} |
|
289
|
|
|
|
|
290
|
|
|
/** |
|
291
|
|
|
* ArrayAccess used to documents. |
|
292
|
|
|
* |
|
293
|
|
|
* @param string $id |
|
294
|
|
|
* |
|
295
|
|
|
* @return Document |
|
296
|
|
|
*/ |
|
297
|
|
|
public function offsetGet($id) |
|
298
|
|
|
{ |
|
299
|
|
|
return $this->getDocument($id); |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
/** |
|
303
|
|
|
* ArrayAccess used to documents. |
|
304
|
|
|
* |
|
305
|
|
|
* @param string $id |
|
306
|
|
|
* @param Document $document |
|
307
|
|
|
*/ |
|
308
|
|
|
public function offsetSet($id, $document) |
|
309
|
|
|
{ |
|
310
|
|
|
$this->saveDocument($id, $document); |
|
311
|
|
|
} |
|
312
|
|
|
|
|
313
|
|
|
/** |
|
314
|
|
|
* ArrayAccess used to documents. |
|
315
|
|
|
* |
|
316
|
|
|
* @param string $id |
|
317
|
|
|
*/ |
|
318
|
|
|
public function offsetUnset($id) |
|
319
|
|
|
{ |
|
320
|
|
|
$this->deleteDocument($id); |
|
321
|
|
|
} |
|
322
|
|
|
|
|
323
|
|
|
/** |
|
324
|
|
|
* Property magic method used to directories. |
|
325
|
|
|
* |
|
326
|
|
|
* @param string $offset |
|
|
|
|
|
|
327
|
|
|
* |
|
328
|
|
|
* @return Directory |
|
329
|
|
|
*/ |
|
330
|
|
|
public function __get($id) |
|
331
|
|
|
{ |
|
332
|
|
|
return $this->getDirectory($id); |
|
333
|
|
|
} |
|
334
|
|
|
|
|
335
|
|
|
/** |
|
336
|
|
|
* Property magic method used to directories. |
|
337
|
|
|
* |
|
338
|
|
|
* @param string $id |
|
339
|
|
|
*/ |
|
340
|
|
|
public function __isset($id) |
|
341
|
|
|
{ |
|
342
|
|
|
return $this->hasDirectory($id); |
|
343
|
|
|
} |
|
344
|
|
|
|
|
345
|
|
|
/** |
|
346
|
|
|
* Property magic method used to directories. |
|
347
|
|
|
* |
|
348
|
|
|
* @param string $id |
|
349
|
|
|
*/ |
|
350
|
|
|
public function __unset($id) |
|
351
|
|
|
{ |
|
352
|
|
|
$this->deleteDirectory($id); |
|
353
|
|
|
} |
|
354
|
|
|
} |
|
355
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.