Completed
Pull Request — master (#421)
by Vincent
02:53
created

Filesystem::listFiles()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Gaufrette;
4
5
use Gaufrette\Adapter\ListKeysAware;
6
7
/**
8
 * A filesystem is used to store and retrieve files.
9
 *
10
 * @author Antoine Hérault <[email protected]>
11
 * @author Leszek Prabucki <[email protected]>
12
 */
13
class Filesystem
14
{
15
    protected $adapter;
16
17
    /**
18
     * Contains File objects created with $this->createFile() method.
19
     *
20
     * @var array
21
     */
22
    protected $fileRegister = array();
23
24
    /**
25
     * @param Adapter $adapter A configured Adapter instance
26
     */
27
    public function __construct(Adapter $adapter)
28
    {
29
        $this->adapter = $adapter;
30
    }
31
32
    /**
33
     * Returns the adapter.
34
     *
35
     * @return Adapter
36
     */
37
    public function getAdapter()
38
    {
39
        return $this->adapter;
40
    }
41
42
    /**
43
     * Indicates whether the file matching the specified key exists.
44
     *
45
     * @param string $key
46
     *
47
     * @return bool TRUE if the file exists, FALSE otherwise
48
     */
49
    public function has($key)
50
    {
51
        return $this->adapter->exists($key);
52
    }
53
54
    /**
55
     * Renames a file.
56
     *
57
     * @param string $sourceKey
58
     * @param string $targetKey
59
     *
60
     * @return bool TRUE if the rename was successful
61
     *
62
     * @throws Exception\FileNotFound   when sourceKey does not exist
63
     * @throws Exception\UnexpectedFile when targetKey exists
64
     * @throws \RuntimeException        when cannot rename
65
     */
66
    public function rename($sourceKey, $targetKey)
67
    {
68
        $this->assertHasFile($sourceKey);
69
70
        if ($this->has($targetKey)) {
71
            throw new Exception\UnexpectedFile($targetKey);
72
        }
73
74
        if (!$this->adapter->rename($sourceKey, $targetKey)) {
75
            throw new \RuntimeException(sprintf('Could not rename the "%s" key to "%s".', $sourceKey, $targetKey));
76
        }
77
78
        if ($this->isFileInRegister($sourceKey)) {
79
            $this->fileRegister[$targetKey] = $this->fileRegister[$sourceKey];
80
            unset($this->fileRegister[$sourceKey]);
81
        }
82
83
        return true;
84
    }
85
86
    /**
87
     * Returns the file matching the specified key.
88
     *
89
     * @param string $key    Key of the file
90
     * @param bool   $create Whether to create the file if it does not exist
91
     *
92
     * @throws Exception\FileNotFound
93
     *
94
     * @return File
95
     */
96
    public function get($key, $create = false)
97
    {
98
        if (!$create) {
99
            $this->assertHasFile($key);
100
        }
101
102
        return $this->createFile($key);
103
    }
104
105
    /**
106
     * Writes the given content into the file.
107
     *
108
     * @param string $key       Key of the file
109
     * @param string $content   Content to write in the file
110
     * @param bool   $overwrite Whether to overwrite the file if exists
111
     *
112
     * @throws Exception\FileAlreadyExists When file already exists and overwrite is false
113
     * @throws \RuntimeException           When for any reason content could not be written
114
     *
115
     * @return int The number of bytes that were written into the file
116
     */
117
    public function write($key, $content, $overwrite = false)
118
    {
119
        if (!$overwrite && $this->has($key)) {
120
            throw new Exception\FileAlreadyExists($key);
121
        }
122
123
        $numBytes = $this->adapter->write($key, $content);
124
125
        if (false === $numBytes) {
126
            throw new \RuntimeException(sprintf('Could not write the "%s" key content.', $key));
127
        }
128
129
        return $numBytes;
130
    }
131
132
    /**
133
     * Reads the content from the file.
134
     *
135
     * @param string $key Key of the file
136
     *
137
     * @throws Exception\FileNotFound when file does not exist
138
     * @throws \RuntimeException      when cannot read file
139
     *
140
     * @return string
141
     */
142 View Code Duplication
    public function read($key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
143
    {
144
        $this->assertHasFile($key);
145
146
        $content = $this->adapter->read($key);
147
148
        if (false === $content) {
149
            throw new \RuntimeException(sprintf('Could not read the "%s" key content.', $key));
150
        }
151
152
        return $content;
153
    }
154
155
    /**
156
     * Deletes the file matching the specified key.
157
     *
158
     * @param string $key
159
     *
160
     * @throws \RuntimeException when cannot read file
161
     *
162
     * @return bool
163
     */
164 View Code Duplication
    public function delete($key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
165
    {
166
        $this->assertHasFile($key);
167
168
        if ($this->adapter->delete($key)) {
169
            $this->removeFromRegister($key);
170
171
            return true;
172
        }
173
174
        throw new \RuntimeException(sprintf('Could not remove the "%s" key.', $key));
175
    }
176
177
    /**
178
     * Returns an array of all keys.
179
     *
180
     * @return array
181
     */
182
    public function keys()
183
    {
184
        return $this->adapter->keys();
185
    }
186
187
    /**
188
     * Lists keys beginning with given prefix
189
     * (no wildcard / regex matching).
190
     *
191
     * if adapter implements ListKeysAware interface, adapter's implementation will be used,
192
     * in not, ALL keys will be requested and iterated through.
193
     *
194
     * @param string $prefix
195
     *
196
     * @return array
197
     */
198
    public function listKeys($prefix = '')
199
    {
200
        if ($this->adapter instanceof ListKeysAware) {
201
            return $this->adapter->listKeys($prefix);
202
        }
203
204
        $dirs = array();
205
        $keys = array();
206
207
        foreach ($this->keys() as $key) {
208
            if (empty($prefix) || 0 === strpos($key, $prefix)) {
209
                if ($this->adapter->isDirectory($key)) {
210
                    $dirs[] = $key;
211
                } else {
212
                    $keys[] = $key;
213
                }
214
            }
215
        }
216
217
        return array(
218
            'keys' => $keys,
219
            'dirs' => $dirs,
220
        );
221
    }
222
223
    /**
224
     * Lists files beginning with given prefix
225
     * (no wildcard / regex matching)
226
     *
227
     * if adapter implements ListFilesAware interface, adapter's implementation will be used,
228
     * otherwise return empty array
229
     *
230
     * @param  string $prefix
231
     * @return array
232
     */
233
    public function listFiles($prefix = '')
234
    {
235
        if ($this->adapter instanceof ListFilesAware) {
0 ignored issues
show
Bug introduced by
The class Gaufrette\ListFilesAware does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
236
            return $this->adapter->listFiles($prefix);
237
        }
238
239
        return [];
240
    }
241
242
    /**
243
     * Returns the last modified time of the specified file.
244
     *
245
     * @param string $key
246
     *
247
     * @return int An UNIX like timestamp
248
     */
249
    public function mtime($key)
250
    {
251
        $this->assertHasFile($key);
252
253
        return $this->adapter->mtime($key);
254
    }
255
256
    /**
257
     * Returns the checksum of the specified file's content.
258
     *
259
     * @param string $key
260
     *
261
     * @return string A MD5 hash
262
     */
263
    public function checksum($key)
264
    {
265
        $this->assertHasFile($key);
266
267
        if ($this->adapter instanceof Adapter\ChecksumCalculator) {
268
            return $this->adapter->checksum($key);
269
        }
270
271
        return Util\Checksum::fromContent($this->read($key));
0 ignored issues
show
Bug introduced by
It seems like $this->read($key) targeting Gaufrette\Filesystem::read() can also be of type boolean; however, Gaufrette\Util\Checksum::fromContent() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
272
    }
273
274
    /**
275
     * Returns the size of the specified file's content.
276
     *
277
     * @param string $key
278
     *
279
     * @return int File size in Bytes
280
     */
281
    public function size($key)
282
    {
283
        $this->assertHasFile($key);
284
285
        if ($this->adapter instanceof Adapter\SizeCalculator) {
286
            return $this->adapter->size($key);
287
        }
288
289
        return Util\Size::fromContent($this->read($key));
0 ignored issues
show
Bug introduced by
It seems like $this->read($key) targeting Gaufrette\Filesystem::read() can also be of type boolean; however, Gaufrette\Util\Size::fromContent() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
290
    }
291
292
    /**
293
     * Gets a new stream instance of the specified file.
294
     *
295
     * @param $key
296
     *
297
     * @return Stream|Stream\InMemoryBuffer
298
     */
299
    public function createStream($key)
300
    {
301
        if ($this->adapter instanceof Adapter\StreamFactory) {
302
            return $this->adapter->createStream($key);
303
        }
304
305
        return new Stream\InMemoryBuffer($this, $key);
306
    }
307
308
    /**
309
     * Creates a new file in a filesystem.
310
     *
311
     * @param $key
312
     *
313
     * @return File
314
     */
315
    public function createFile($key)
316
    {
317
        if (false === $this->isFileInRegister($key)) {
318
            if ($this->adapter instanceof Adapter\FileFactory) {
319
                $this->fileRegister[$key] = $this->adapter->createFile($key, $this);
320
            } else {
321
                $this->fileRegister[$key] = new File($key, $this);
322
            }
323
        }
324
325
        return $this->fileRegister[$key];
326
    }
327
328
    /**
329
     * Get the mime type of the provided key.
330
     *
331
     * @param string $key
332
     *
333
     * @return string
334
     */
335
    public function mimeType($key)
336
    {
337
        $this->assertHasFile($key);
338
339
        if ($this->adapter instanceof Adapter\MimeTypeProvider) {
340
            return $this->adapter->mimeType($key);
341
        }
342
343
        throw new \LogicException(sprintf(
344
            'Adapter "%s" cannot provide MIME type',
345
            get_class($this->adapter)
346
        ));
347
    }
348
349
    /**
350
     * Checks if matching file by given key exists in the filesystem.
351
     *
352
     * Key must be non empty string, otherwise it will throw Exception\FileNotFound
353
     * {@see http://php.net/manual/en/function.empty.php}
354
     *
355
     * @param string $key
356
     *
357
     * @throws Exception\FileNotFound when sourceKey does not exist
358
     */
359
    private function assertHasFile($key)
360
    {
361
        if (!empty($key) && !$this->has($key)) {
362
            throw new Exception\FileNotFound($key);
363
        }
364
    }
365
366
    /**
367
     * Checks if matching File object by given key exists in the fileRegister.
368
     *
369
     * @param string $key
370
     *
371
     * @return bool
372
     */
373
    private function isFileInRegister($key)
374
    {
375
        return array_key_exists($key, $this->fileRegister);
376
    }
377
378
    /**
379
     * Clear files register.
380
     */
381
    public function clearFileRegister()
382
    {
383
        $this->fileRegister = array();
384
    }
385
386
    /**
387
     * Removes File object from register.
388
     *
389
     * @param string $key
390
     */
391
    public function removeFromRegister($key)
392
    {
393
        if ($this->isFileInRegister($key)) {
394
            unset($this->fileRegister[$key]);
395
        }
396
    }
397
398
    /**
399
     * @param string $key
400
     *
401
     * @return bool
402
     */
403
    public function isDirectory($key)
404
    {
405
        return $this->adapter->isDirectory($key);
406
    }
407
}
408