MemoryAdapter   B
last analyzed

Complexity

Total Complexity 45

Size/Duplication

Total Lines 329
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 3
dl 0
loc 329
ccs 108
cts 108
cp 1
rs 8.8
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A copy() 0 11 2
A createDir() 0 8 2
A delete() 0 10 2
A deleteDir() 0 14 3
A getMetadata() 0 7 1
A getSize() 0 4 1
A getTimestamp() 0 4 1
A getVisibility() 0 4 1
A has() 0 4 1
A listContents() 0 6 1
A read() 0 7 1
A rename() 0 9 2
A setVisibility() 0 10 2
A getMimetype() 0 10 2
A update() 0 16 3
A write() 0 12 2
A doCreateDir() 0 20 4
A doListContents() 0 17 4
A hasDirectory() 0 4 2
A hasFile() 0 4 2
A pathIsInDirectory() 0 4 2
A readStream() 0 13 2

How to fix   Complexity   

Complex Class

Complex classes like MemoryAdapter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MemoryAdapter, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace League\Flysystem\Memory;
4
5
use League\Flysystem\Adapter\Polyfill\StreamedWritingTrait;
6
use League\Flysystem\AdapterInterface;
7
use League\Flysystem\Config;
8
use League\Flysystem\Util;
9
10
/**
11
 * An adapter that keeps the filesystem in memory.
12
 */
13
class MemoryAdapter implements AdapterInterface
14
{
15
    use StreamedWritingTrait;
16
17
    /**
18
     * The emulated filesystem.
19
     *
20
     * Start with the root directory initialized.
21
     *
22
     * @var array
23
     */
24
    protected $storage = ['' => ['type' => 'dir']];
25
26 57
    public function __construct(Config $config = null)
27
    {
28 57
        $config = $config ?: new Config();
29
30 57
        $this->storage['']['timestamp'] = $config->get('timestamp', time());
31 57
    }
32
33
    /**
34
     * @inheritdoc
35
     */
36 6
    public function copy($path, $newpath)
37
    {
38
        // Make sure all the destination sub-directories exist.
39 6
        if ( ! $this->doCreateDir(Util::dirname($newpath), new Config())) {
40 6
            return false;
41
        }
42
43 6
        $this->storage[$newpath] = $this->storage[$path];
44
45 6
        return true;
46
    }
47
48
    /**
49
     * @inheritdoc
50
     */
51 9
    public function createDir($dirname, Config $config)
52
    {
53 9
        if ( ! $this->doCreateDir($dirname, $config)) {
54 3
            return false;
55
        }
56
57 9
        return $this->getMetadata($dirname);
58
    }
59
60
    /**
61
     * @inheritdoc
62
     */
63 3
    public function delete($path)
64
    {
65 3
        if ( ! $this->hasFile($path)) {
66 3
            return false;
67
        }
68
69 3
        unset($this->storage[$path]);
70
71 3
        return true;
72
    }
73
74
    /**
75
     * @inheritdoc
76
     */
77 3
    public function deleteDir($dirname)
78
    {
79 3
        if ( ! $this->hasDirectory($dirname)) {
80 3
            return false;
81
        }
82
83 3
        foreach ($this->doListContents($dirname, true) as $path) {
84 3
            unset($this->storage[$path]);
85 2
        }
86
87 3
        unset($this->storage[$dirname]);
88
89 3
        return true;
90
    }
91
92
    /**
93
     * @inheritdoc
94
     */
95 57
    public function getMetadata($path)
96
    {
97 57
        $metadata = $this->storage[$path] + ['path' => $path];
98 57
        unset($metadata['contents']);
99
100 57
        return $metadata;
101
    }
102
103
    /**
104
     * @inheritdoc
105
     */
106 3
    public function getMimetype($path)
107
    {
108 3
        $mimetype = isset($this->storage[$path]['mimetype']) ? $this->storage[$path]['mimetype'] :
109 3
            Util::guessMimeType($path, $this->storage[$path]['contents']);
110
111
        return [
112 3
            'mimetype' => $mimetype,
113 3
            'path' => $path,
114 2
        ];
115
    }
116
117
    /**
118
     * @inheritdoc
119
     */
120 3
    public function getSize($path)
121
    {
122 3
        return $this->getMetadata($path);
123
    }
124
125
    /**
126
     * @inheritdoc
127
     */
128 9
    public function getTimestamp($path)
129
    {
130 9
        return $this->getMetadata($path);
131
    }
132
133
    /**
134
     * @inheritdoc
135
     */
136 6
    public function getVisibility($path)
137
    {
138 6
        return $this->getMetadata($path);
139
    }
140
141
    /**
142
     * @inheritdoc
143
     */
144 57
    public function has($path)
145
    {
146 57
        return isset($this->storage[$path]);
147
    }
148
149
    /**
150
     * @inheritdoc
151
     */
152 3
    public function listContents($directory = '', $recursive = false)
153
    {
154 3
        $contents = $this->doListContents($directory, $recursive);
155
156 3
        return array_map([$this, 'getMetadata'], array_values($contents));
157
    }
158
159
    /**
160
     * @inheritdoc
161
     */
162 9
    public function read($path)
163
    {
164
        return [
165 9
            'path' => $path,
166 9
            'contents' => $this->storage[$path]['contents'],
167 6
        ];
168
    }
169
170
    /**
171
     * @inheritdoc
172
     */
173 3
    public function readStream($path)
174
    {
175 3
        $stream = fopen('php://memory', 'w+b');
176
177 3
        if ( ! is_resource($stream)) {
178
            throw new \RuntimeException('Unable to create memory stream.'); // @codeCoverageIgnore
179
        }
180
181 3
        fwrite($stream, $this->storage[$path]['contents']);
182 3
        rewind($stream);
183
184 3
        return compact('path', 'stream');
185
    }
186
187
    /**
188
     * @inheritdoc
189
     */
190 3
    public function rename($path, $newpath)
191
    {
192 3
        if ( ! $this->copy($path, $newpath)) {
193 3
            return false;
194
        }
195 3
        unset($this->storage[$path]);
196
197 3
        return true;
198
    }
199
200
    /**
201
     * @inheritdoc
202
     */
203 3
    public function setVisibility($path, $visibility)
204
    {
205 3
        if ( ! $this->hasFile($path)) {
206 3
            return false;
207
        }
208
209 3
        $this->storage[$path]['visibility'] = $visibility;
210
211 3
        return $this->getVisibility($path);
212
    }
213
214
    /**
215
     * @inheritdoc
216
     */
217 57
    public function update($path, $contents, Config $config)
218
    {
219 57
        if ( ! $this->hasFile($path)) {
220 3
            return false;
221
        }
222
223 57
        $this->storage[$path]['contents'] = $contents;
224 57
        $this->storage[$path]['timestamp'] = $config->get('timestamp', time());
225 57
        $this->storage[$path]['size'] = Util::contentSize($contents);
226 57
        $this->storage[$path]['visibility'] = $config->get('visibility', $this->storage[$path]['visibility']);
227 57
        if ($config->has('mimetype')) {
228 6
            $this->storage[$path]['mimetype'] = $config->get('mimetype');
229 4
        }
230
231 57
        return $this->getMetadata($path);
232
    }
233
234
    /**
235
     * @inheritdoc
236
     */
237 57
    public function write($path, $contents, Config $config)
238
    {
239
        // Make sure all the destination sub-directories exist.
240 57
        if ( ! $this->doCreateDir(Util::dirname($path), $config)) {
241 3
            return false;
242
        }
243
244 57
        $this->storage[$path]['type'] = 'file';
245 57
        $this->storage[$path]['visibility'] = AdapterInterface::VISIBILITY_PUBLIC;
246
247 57
        return $this->update($path, $contents, $config);
248
    }
249
250
    /**
251
     * Creates a directory.
252
     *
253
     * @param string $dirname
254
     * @param Config $config
255
     *
256
     * @return bool
257
     */
258 57
    protected function doCreateDir($dirname, Config $config)
259
    {
260 57
        if ($this->hasDirectory($dirname)) {
261 57
            return true;
262
        }
263
264 27
        if ($this->hasFile($dirname)) {
265 12
            return false;
266
        }
267
268
        // Make sure all the sub-directories exist.
269 24
        if ( ! $this->doCreateDir(Util::dirname($dirname), $config)) {
270 3
            return false;
271
        }
272
273 24
        $this->storage[$dirname]['type'] = 'dir';
274 24
        $this->storage[$dirname]['timestamp'] = $config->get('timestamp', time());
275
276 24
        return true;
277
    }
278
279
    /**
280
     * Filters the file system returning paths inside the directory.
281
     *
282
     *  @param string $directory
283
     *  @param bool   $recursive
284
     *
285
     * @return string[]
286
     */
287
    protected function doListContents($directory, $recursive)
288
    {
289 6
        $filter = function ($path) use ($directory, $recursive) {
290
            // Remove the root directory from any listing.
291 6
            if ($path === '') {
292 6
                return false;
293
            }
294
295 6
            if (Util::dirname($path) === $directory) {
296 6
                return true;
297
            }
298
299 6
            return $recursive && $this->pathIsInDirectory($path, $directory);
300 6
        };
301
302 6
        return array_filter(array_keys($this->storage), $filter);
303
    }
304
305
    /**
306
     * Checks whether a directory exists.
307
     *
308
     * @param string $path The directory.
309
     *
310
     * @return bool True if it exists, and is a directory, false if not.
311
     */
312 57
    protected function hasDirectory($path)
313
    {
314 57
        return $this->has($path) && $this->storage[$path]['type'] === 'dir';
315
    }
316
317
    /**
318
     * Checks whether a file exists.
319
     *
320
     * @param string $path The file.
321
     *
322
     * @return bool True if it exists, and is a file, false if not.
323
     */
324 57
    protected function hasFile($path)
325
    {
326 57
        return $this->has($path) && $this->storage[$path]['type'] === 'file';
327
    }
328
329
    /**
330
     * Determines if the path is inside the directory.
331
     *
332
     * @param string $path
333
     * @param string $directory
334
     *
335
     * @return bool
336
     */
337 6
    protected function pathIsInDirectory($path, $directory)
338
    {
339 6
        return $directory === '' || strpos($path, $directory . '/') === 0;
340
    }
341
}
342