Completed
Push — master ( 83dc58...593e8c )
by Hong
02:51
created

Path   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 295
Duplicated Lines 12.54 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 7
Bugs 0 Features 2
Metric Value
wmc 40
c 7
b 0
f 2
lcom 1
cbo 6
dl 37
loc 295
rs 8.2608

19 Methods

Rating   Name   Duplication   Size   Complexity  
A getPath() 0 4 1
A getFullPath() 0 4 1
A __construct() 0 9 1
A exists() 0 10 2
A getContent() 11 11 3
A getMeta() 0 10 2
A setContent() 0 11 3
A setMeta() 13 13 3
A isDir() 0 9 3
A rename() 0 4 1
A copy() 0 4 1
A delete() 13 13 3
A resetError() 0 4 1
A getDriver() 0 4 1
B alterAction() 0 19 5
A hasTrailingSlash() 0 8 3
A isFilesystemReadable() 0 11 2
A isFilesystemWritable() 0 11 2
A isFilesystemDeletable() 0 11 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Path 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 Path, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Phossa Project
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  Library
8
 * @package   Phossa2\Storage
9
 * @copyright Copyright (c) 2016 phossa.com
10
 * @license   http://mit-license.org/ MIT License
11
 * @link      http://www.phossa.com/
12
 */
13
/*# declare(strict_types=1); */
14
15
namespace Phossa2\Storage;
16
17
use Phossa2\Storage\Message\Message;
18
use Phossa2\Shared\Base\ObjectAbstract;
19
use Phossa2\Shared\Error\ErrorAwareTrait;
20
use Phossa2\Shared\Error\ErrorAwareInterface;
21
use Phossa2\Storage\Interfaces\PathInterface;
22
use Phossa2\Storage\Traits\FilesystemAwareTrait;
23
use Phossa2\Shared\Extension\ExtensionAwareTrait;
24
use Phossa2\Storage\Interfaces\FilesystemInterface;
25
use Phossa2\Shared\Extension\ExtensionAwareInterface;
26
use Phossa2\Storage\Interfaces\FilesystemAwareInterface;
27
use Phossa2\Storage\Interfaces\DriverInterface;
28
29
/**
30
 * Path
31
 *
32
 * @package Phossa2\Storage
33
 * @author  Hong Zhang <[email protected]>
34
 * @see     ObjectAbstract
35
 * @see     PathInterface
36
 * @see     ErrorAwareInterface
37
 * @see     FilesystemAwareInterface
38
 * @version 2.0.0
39
 * @since   2.0.0 added
40
 */
41
class Path extends ObjectAbstract implements PathInterface, ErrorAwareInterface, FilesystemAwareInterface, ExtensionAwareInterface
42
{
43
    use FilesystemAwareTrait, ErrorAwareTrait, ExtensionAwareTrait;
44
45
    /**
46
     * Full path with mount point
47
     *
48
     * @var    string
49
     * @access protected
50
     */
51
    protected $full;
52
53
    /**
54
     * relative path without mount point prefix
55
     *
56
     * @var    string
57
     * @access protected
58
     */
59
    protected $path;
60
61
    /**
62
     * Instantiate the path object
63
     *
64
     * @param  string $full full path
65
     * @param  string $path relative path without mount point
66
     * @param  FilesystemInterface $filesystem
67
     * @access public
68
     * @api
69
     */
70
    public function __construct(
71
        /*# string */ $full,
72
        /*# string */ $path,
73
        FilesystemInterface $filesystem
74
    ) {
75
        $this->setFilesystem($filesystem);
76
        $this->full = $full;
77
        $this->path = $path;
78
    }
79
80
    /**
81
     * {@inheritDoc}
82
     */
83
    public function exists()/*# : bool */
84
    {
85
        if (!$this->getDriver()->exists($this->path)) {
86
            return $this->setError(
87
                Message::get(Message::MSG_PATH_NOTFOUND, $this->full),
88
                Message::MSG_PATH_NOTFOUND
89
            );
90
        }
91
        return true;
92
    }
93
94
    /**
95
     * {@inheritDoc}
96
     */
97 View Code Duplication
    public function getContent(/*# bool */ $stream = false)
98
    {
99
        // not exists or filesystem not readable
100
        if (!$this->exists() || !$this->isFilesystemReadable()) {
101
            return null;
102
        }
103
104
        $res = $this->getDriver()->getContent($this->path, $stream);
105
        $this->resetError();
106
        return $res;
107
    }
108
109
    /**
110
     * {@inheritDoc}
111
     */
112
    public function getMeta()/*# : array */
113
    {
114
        if (!$this->exists()) {
115
            return [];
116
        }
117
118
        $res = $this->getDriver()->getMeta($this->path);
119
        $this->resetError();
120
        return $res;
121
    }
122
123
    /**
124
     * {@inheritDoc}
125
     */
126
    public function getPath()/*# : string */
127
    {
128
        return $this->path;
129
    }
130
131
    /**
132
     * {@inheritDoc}
133
     */
134
    public function getFullPath()/*# : string */
135
    {
136
        return $this->full;
137
    }
138
139
    /**
140
     * {@inheritDoc}
141
     */
142
    public function setContent($content)/*# : bool */
143
    {
144
        if ($this->isFilesystemWritable() &&
145
            !$this->hasTrailingSlash($this->path)
146
        ) {
147
            $res = $this->getDriver()->setContent($this->path, $content);
148
            $this->resetError();
149
            return $res;
150
        }
151
        return false;
152
    }
153
154
    /**
155
     * {@inheritDoc}
156
     */
157 View Code Duplication
    public function setMeta(array $meta)/*# : bool */
158
    {
159
        if (!$this->exists()) {
160
            return false;
161
        }
162
163
        if (!empty($meta)) {
164
            $res = $this->getDriver()->setMeta($this->path, $meta);
165
            $this->resetError();
166
            return $res;
167
        }
168
        return true;
169
    }
170
171
    /**
172
     * {@inheritDoc}
173
     */
174
    public function isDir()/*# : bool */
175
    {
176
        if ($this->hasTrailingSlash($this->path) ||
177
            $this->getDriver()->isDir($this->path)
178
        ) {
179
            return true;
180
        }
181
        return false;
182
    }
183
184
    /**
185
     * {@inheritDoc}
186
     */
187
    public function rename(/*# string */ $destination)/*# : bool */
188
    {
189
        return $this->alterAction($destination, 'rename');
190
    }
191
192
    /**
193
     * {@inheritDoc}
194
     */
195
    public function copy(/*# string */ $destination)/*# : bool */
196
    {
197
        return $this->alterAction($destination, 'copy');
198
    }
199
200
    /**
201
     * {@inheritDoc}
202
     */
203 View Code Duplication
    public function delete()/*# : bool */
204
    {
205
        if ($this->exists()) {
206
            if (!$this->isFilesystemDeletable()) {
207
                return false;
208
            }
209
210
            $res = $this->getDriver()->delete($this->path);
211
            $this->resetError();
212
            return $res;
213
        }
214
        return true;
215
    }
216
217
    /**
218
     * Reset error to driver's error
219
     *
220
     * @access protected
221
     */
222
    protected function resetError()
223
    {
224
        $this->copyError($this->getFilesystem()->getDriver());
225
    }
226
227
    /**
228
     * Get the driver
229
     *
230
     * @return DriverInterface
231
     * @access protected
232
     */
233
    protected function getDriver()/*# : DriverInterface */
234
    {
235
        return $this->getFilesystem()->getDriver();
236
    }
237
238
    /**
239
     * Do copy or rename in same filesystem
240
     *
241
     * @param  string $destination
242
     * @param  string $action 'copy' or 'rename'
243
     * @return bool
244
     * @access protected
245
     */
246
    protected function alterAction(
247
        /*# string */ $destination,
248
        /*# string */ $action
249
    )/*# : bool */ {
250
        if (!$this->exists() || !$this->isFilesystemWritable()) {
251
            return false;
252
        }
253
254
        // destination is direcotry
255
        if ($this->hasTrailingSlash($destination) ||
256
            $this->getDriver()->isDir($destination)
257
        ) {
258
            $destination = rtrim($destination, '/') . '/' . basename($this->path);
259
        }
260
261
        $res = $this->getDriver()->{$action}($this->path, $destination);
262
        $this->resetError();
263
        return (bool) $res;
264
    }
265
266
    /**
267
     * Is current path has trailing '/'
268
     *
269
     * @param  string $path
270
     * @return bool
271
     * @access protected
272
     */
273
    protected function hasTrailingSlash(/*# string */ $path)/*# : bool */
274
    {
275
        if ($path && '/' == $path[strlen($path)-1]) {
276
            return true;
277
        } else {
278
            return false;
279
        }
280
    }
281
282
    /**
283
     * Check filesystem readable or not
284
     *
285
     * @return bool
286
     * @access protected
287
     */
288
    protected function isFilesystemReadable()/*# : bool */
289
    {
290
        if ($this->getFilesystem()->isReadable()) {
291
            return true;
292
        } else {
293
            return $this->setError(
294
                Message::get(Message::STR_FS_NONREADABLE, $this->full),
295
                Message::STR_FS_NONREADABLE
296
            );
297
        }
298
    }
299
300
    /**
301
     * Check filesystem writable or not
302
     *
303
     * @return bool
304
     * @access protected
305
     */
306
    protected function isFilesystemWritable()/*# : bool */
307
    {
308
        if ($this->getFilesystem()->isWritable()) {
309
            return true;
310
        } else {
311
            return $this->setError(
312
                Message::get(Message::STR_FS_NONWRITABLE, $this->full),
313
                Message::STR_FS_NONWRITABLE
314
            );
315
        }
316
    }
317
318
    /**
319
     * Check filesystem file deletable or not
320
     *
321
     * @return bool
322
     * @access protected
323
     */
324
    protected function isFilesystemDeletable()/*# : bool */
325
    {
326
        if ($this->getFilesystem()->isDeletable()) {
327
            return true;
328
        } else {
329
            return $this->setError(
330
                Message::get(Message::STR_FS_NONDELETABLE, $this->full),
331
                Message::STR_FS_NONDELETABLE
332
            );
333
        }
334
    }
335
}
336