Completed
Push — master ( f3d80d...8d277a )
by Pierre
08:08 queued 05:26
created

Filesystem::rename()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 22
rs 8.9197
cc 4
eloc 12
nc 4
nop 2
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
     * @throws \InvalidArgumentException If $key is invalid
50
     */
51
    public function has($key)
52
    {
53
        self::assertValidKey($key);
54
55
        return $this->adapter->exists($key);
56
    }
57
58
    /**
59
     * Renames a file.
60
     *
61
     * @param string $sourceKey
62
     * @param string $targetKey
63
     *
64
     * @return bool TRUE if the rename was successful
65
     *
66
     * @throws Exception\FileNotFound    when sourceKey does not exist
67
     * @throws Exception\UnexpectedFile  when targetKey exists
68
     * @throws \RuntimeException         when cannot rename
69
     * @throws \InvalidArgumentException If $sourceKey or $targetKey are invalid
70
     */
71
    public function rename($sourceKey, $targetKey)
72
    {
73
        self::assertValidKey($sourceKey);
74
        self::assertValidKey($targetKey);
75
76
        $this->assertHasFile($sourceKey);
77
78
        if ($this->has($targetKey)) {
79
            throw new Exception\UnexpectedFile($targetKey);
80
        }
81
82
        if (!$this->adapter->rename($sourceKey, $targetKey)) {
83
            throw new \RuntimeException(sprintf('Could not rename the "%s" key to "%s".', $sourceKey, $targetKey));
84
        }
85
86
        if ($this->isFileInRegister($sourceKey)) {
87
            $this->fileRegister[$targetKey] = $this->fileRegister[$sourceKey];
88
            unset($this->fileRegister[$sourceKey]);
89
        }
90
91
        return true;
92
    }
93
94
    /**
95
     * Returns the file matching the specified key.
96
     *
97
     * @param string $key    Key of the file
98
     * @param bool   $create Whether to create the file if it does not exist
99
     *
100
     * @throws Exception\FileNotFound
101
     * @throws \InvalidArgumentException If $key is invalid
102
     *
103
     * @return File
104
     */
105
    public function get($key, $create = false)
106
    {
107
        self::assertValidKey($key);
108
109
        if (!$create) {
110
            $this->assertHasFile($key);
111
        }
112
113
        return $this->createFile($key);
114
    }
115
116
    /**
117
     * Writes the given content into the file.
118
     *
119
     * @param string $key       Key of the file
120
     * @param string $content   Content to write in the file
121
     * @param bool   $overwrite Whether to overwrite the file if exists
122
     *
123
     * @throws Exception\FileAlreadyExists When file already exists and overwrite is false
124
     * @throws \RuntimeException           When for any reason content could not be written
125
     * @throws \InvalidArgumentException   If $key is invalid
126
     *
127
     * @return int The number of bytes that were written into the file
128
     */
129
    public function write($key, $content, $overwrite = false)
130
    {
131
        self::assertValidKey($key);
132
133
        if (!$overwrite && $this->has($key)) {
134
            throw new Exception\FileAlreadyExists($key);
135
        }
136
137
        $numBytes = $this->adapter->write($key, $content);
138
139
        if (false === $numBytes) {
140
            throw new \RuntimeException(sprintf('Could not write the "%s" key content.', $key));
141
        }
142
143
        return $numBytes;
144
    }
145
146
    /**
147
     * Reads the content from the file.
148
     *
149
     * @param string $key Key of the file
150
     *
151
     * @throws Exception\FileNotFound    when file does not exist
152
     * @throws \RuntimeException         when cannot read file
153
     * @throws \InvalidArgumentException If $key is invalid
154
     *
155
     * @return string
156
     */
157 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...
158
    {
159
        self::assertValidKey($key);
160
161
        $this->assertHasFile($key);
162
163
        $content = $this->adapter->read($key);
164
165
        if (false === $content) {
166
            throw new \RuntimeException(sprintf('Could not read the "%s" key content.', $key));
167
        }
168
169
        return $content;
170
    }
171
172
    /**
173
     * Deletes the file matching the specified key.
174
     *
175
     * @param string $key
176
     *
177
     * @throws \RuntimeException         when cannot read file
178
     * @throws \InvalidArgumentException If $key is invalid
179
     *
180
     * @return bool
181
     */
182 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...
183
    {
184
        self::assertValidKey($key);
185
186
        $this->assertHasFile($key);
187
188
        if ($this->adapter->delete($key)) {
189
            $this->removeFromRegister($key);
190
191
            return true;
192
        }
193
194
        throw new \RuntimeException(sprintf('Could not remove the "%s" key.', $key));
195
    }
196
197
    /**
198
     * Returns an array of all keys.
199
     *
200
     * @return array
201
     */
202
    public function keys()
203
    {
204
        return $this->adapter->keys();
205
    }
206
207
    /**
208
     * Lists keys beginning with given prefix
209
     * (no wildcard / regex matching).
210
     *
211
     * if adapter implements ListKeysAware interface, adapter's implementation will be used,
212
     * in not, ALL keys will be requested and iterated through.
213
     *
214
     * @param string $prefix
215
     *
216
     * @return array
217
     */
218
    public function listKeys($prefix = '')
219
    {
220
        if ($this->adapter instanceof ListKeysAware) {
221
            return $this->adapter->listKeys($prefix);
222
        }
223
224
        $dirs = array();
225
        $keys = array();
226
227
        foreach ($this->keys() as $key) {
228
            if (empty($prefix) || 0 === strpos($key, $prefix)) {
229
                if ($this->adapter->isDirectory($key)) {
230
                    $dirs[] = $key;
231
                } else {
232
                    $keys[] = $key;
233
                }
234
            }
235
        }
236
237
        return array(
238
            'keys' => $keys,
239
            'dirs' => $dirs,
240
        );
241
    }
242
243
    /**
244
     * Returns the last modified time of the specified file.
245
     *
246
     * @param string $key
247
     *
248
     * @return int An UNIX like timestamp
249
     *
250
     * @throws \InvalidArgumentException If $key is invalid
251
     */
252
    public function mtime($key)
253
    {
254
        self::assertValidKey($key);
255
256
        $this->assertHasFile($key);
257
258
        return $this->adapter->mtime($key);
259
    }
260
261
    /**
262
     * Returns the checksum of the specified file's content.
263
     *
264
     * @param string $key
265
     *
266
     * @return string A MD5 hash
267
     *
268
     * @throws \InvalidArgumentException If $key is invalid
269
     */
270 View Code Duplication
    public function checksum($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...
271
    {
272
        self::assertValidKey($key);
273
274
        $this->assertHasFile($key);
275
276
        if ($this->adapter instanceof Adapter\ChecksumCalculator) {
277
            return $this->adapter->checksum($key);
278
        }
279
280
        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...
281
    }
282
283
    /**
284
     * Returns the size of the specified file's content.
285
     *
286
     * @param string $key
287
     *
288
     * @return int File size in Bytes
289
     *
290
     * @throws \InvalidArgumentException If $key is invalid
291
     */
292 View Code Duplication
    public function size($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...
293
    {
294
        self::assertValidKey($key);
295
296
        $this->assertHasFile($key);
297
298
        if ($this->adapter instanceof Adapter\SizeCalculator) {
299
            return $this->adapter->size($key);
300
        }
301
302
        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...
303
    }
304
305
    /**
306
     * Gets a new stream instance of the specified file.
307
     *
308
     * @param $key
309
     *
310
     * @return Stream|Stream\InMemoryBuffer
311
     *
312
     * @throws \InvalidArgumentException If $key is invalid
313
     */
314
    public function createStream($key)
315
    {
316
        self::assertValidKey($key);
317
318
        if ($this->adapter instanceof Adapter\StreamFactory) {
319
            return $this->adapter->createStream($key);
320
        }
321
322
        return new Stream\InMemoryBuffer($this, $key);
323
    }
324
325
    /**
326
     * Creates a new file in a filesystem.
327
     *
328
     * @param $key
329
     *
330
     * @return File
331
     *
332
     * @throws \InvalidArgumentException If $key is invalid
333
     */
334
    public function createFile($key)
335
    {
336
        self::assertValidKey($key);
337
338
        if (false === $this->isFileInRegister($key)) {
339
            if ($this->adapter instanceof Adapter\FileFactory) {
340
                $this->fileRegister[$key] = $this->adapter->createFile($key, $this);
341
            } else {
342
                $this->fileRegister[$key] = new File($key, $this);
343
            }
344
        }
345
346
        return $this->fileRegister[$key];
347
    }
348
349
    /**
350
     * Get the mime type of the provided key.
351
     *
352
     * @param string $key
353
     *
354
     * @return string
355
     *
356
     * @throws \InvalidArgumentException If $key is invalid
357
     */
358
    public function mimeType($key)
359
    {
360
        self::assertValidKey($key);
361
362
        $this->assertHasFile($key);
363
364
        if ($this->adapter instanceof Adapter\MimeTypeProvider) {
365
            return $this->adapter->mimeType($key);
366
        }
367
368
        throw new \LogicException(sprintf(
369
            'Adapter "%s" cannot provide MIME type',
370
            get_class($this->adapter)
371
        ));
372
    }
373
374
    /**
375
     * Checks if matching file by given key exists in the filesystem.
376
     *
377
     * Key must be non empty string, otherwise it will throw Exception\FileNotFound
378
     * {@see http://php.net/manual/en/function.empty.php}
379
     *
380
     * @param string $key
381
     *
382
     * @throws Exception\FileNotFound when sourceKey does not exist
383
     */
384
    private function assertHasFile($key)
385
    {
386
        if (!$this->has($key)) {
387
            throw new Exception\FileNotFound($key);
388
        }
389
    }
390
391
    /**
392
     * Checks if matching File object by given key exists in the fileRegister.
393
     *
394
     * @param string $key
395
     *
396
     * @return bool
397
     */
398
    private function isFileInRegister($key)
399
    {
400
        return array_key_exists($key, $this->fileRegister);
401
    }
402
403
    /**
404
     * Clear files register.
405
     */
406
    public function clearFileRegister()
407
    {
408
        $this->fileRegister = array();
409
    }
410
411
    /**
412
     * Removes File object from register.
413
     *
414
     * @param string $key
415
     */
416
    public function removeFromRegister($key)
417
    {
418
        if ($this->isFileInRegister($key)) {
419
            unset($this->fileRegister[$key]);
420
        }
421
    }
422
423
    /**
424
     * @param string $key
425
     *
426
     * @return bool
427
     */
428
    public function isDirectory($key)
429
    {
430
        return $this->adapter->isDirectory($key);
431
    }
432
433
    /**
434
     * @param string $key
435
     *
436
     * @throws \InvalidArgumentException Given $key should not be empty
437
     */
438
    private static function assertValidKey($key)
439
    {
440
        if (empty($key)) {
441
            throw new \InvalidArgumentException('Object path is empty.');
442
        }
443
    }
444
}
445