Completed
Push — master ( edb6e3...d6e7e6 )
by Hong
02:14
created

Storage::diffFilesystemCopy()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 22
rs 8.9197
cc 4
eloc 12
nc 6
nop 2
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\Storage\Traits\PathAwareTrait;
21
use Phossa2\Shared\Error\ErrorAwareInterface;
22
use Phossa2\Storage\Interfaces\StorageInterface;
23
use Phossa2\Shared\Extension\ExtensionAwareTrait;
24
use Phossa2\Storage\Interfaces\FilesystemInterface;
25
use Phossa2\Shared\Extension\ExtensionAwareInterface;
26
27
/**
28
 * Storage
29
 *
30
 * @package Phossa2\Storage
31
 * @author  Hong Zhang <[email protected]>
32
 * @see     ObjectAbstract
33
 * @see     StorageInterface
34
 * @see     ErrorAwareInterface
35
 * @see     ExtensionAwareInterface
36
 * @version 2.0.0
37
 * @since   2.0.0 added
38
 */
39
class Storage extends ObjectAbstract implements StorageInterface, ErrorAwareInterface, ExtensionAwareInterface
40
{
41
    use PathAwareTrait, ErrorAwareTrait, ExtensionAwareTrait;
42
43
    /**
44
     * At least have one filesystem mounted
45
     *
46
     * @param  string $mountPoint
47
     * @param  FilesystemInterface $filesystem
48
     * @access public
49
     */
50
    public function __construct(
51
        /*# string */ $mountPoint,
52
        FilesystemInterface $filesystem
53
    ) {
54
        $this->mount($mountPoint, $filesystem);
55
    }
56
57
    /**
58
     * {@inheritDoc}
59
     */
60
    public function has(/*# string */ $path)/*# : bool */
61
    {
62
        // found
63
        if ($this->path($path)->exists()) {
64
            return true;
65
        }
66
67
        // not found
68
        return $this->setError(
69
            Message::get(Message::MSG_PATH_NOTFOUND, $path),
70
            Message::MSG_PATH_NOTFOUND
71
        );
72
    }
73
74
    /**
75
     * {@inheritDoc}
76
     */
77
    public function get(/*# string */ $path, /*# bool */ $stream = false)
78
    {
79
        $obj = $this->path($path);
80
        $res = $obj->getContent($stream);
81
82
        // append mount point if result is array
83
        if (is_array($res)) {
84
            return $this->prependMountPoint(
85
                $res, $this->getMountPoint($obj->getFullPath())
86
            );
87
        }
88
89
        $this->copyError($obj);
90
91
        return $res;
92
    }
93
94
    /**
95
     * {@inheritDoc}
96
     */
97
    public function put(
98
        /*# string */ $path,
99
        $content,
100
        array $meta = []
101
    )/*# : bool */ {
102
        $obj = $this->path($path);
103
104
        // write content
105
        if (null !== $content && !$obj->setContent($content)) {
106
            $this->copyError($obj);
107
            return false;
108
        }
109
110
        // set meta if any
111
        $res = $obj->setMeta($meta);
112
        $this->copyError($obj);
113
        return $res;
114
    }
115
116
    /**
117
     * {@inheritDoc}
118
     */
119
    public function del(/*# string */ $path)/*# : bool */
120
    {
121
        $obj = $this->path($path);
122
        $res = $obj->delete();
123
        $this->copyError($obj);
124
        return $res;
125
    }
126
127
    /**
128
     * {@inheritDoc}
129
     */
130
    public function meta(/*# string */ $path)/*# : array */
131
    {
132
        $obj = $this->path($path);
133
        $res = $obj->getMeta();
134
        $this->copyError($obj);
135
        return $res;
136
    }
137
138
    /**
139
     * {@inheritDoc}
140
     */
141
    public function copy(
142
        /*# string */ $from,
143
        /*# string */ $to
144
    )/*# : bool */ {
145
        if ($this->isSameFilesystem($from, $to)) {
146
            return $this->sameFilesystemAction($from, $to, 'copy');
147
        } else {
148
            return $this->diffFilesystemCopy($from, $to);
149
        }
150
    }
151
152
    /**
153
     * {@inheritDoc}
154
     */
155
    public function move(
156
        /*# string */ $from,
157
        /*# string */ $to
158
    )/*# : bool */ {
159
        if ($this->isSameFilesystem($from, $to)) {
160
            return $this->sameFilesystemAction($from, $to, 'rename');
161
        } elseif ($this->copy($from, $to)) {
162
            return $this->del($from);
163
        }
164
        return false;
165
    }
166
167
    /**
168
     * Copy or rename
169
     *
170
     * @param  string $from
171
     * @param  string $to
172
     * @param  string $action 'copy' or 'rename'
173
     * @return bool
174
     * @access protected
175
     */
176
    protected function sameFilesystemAction(
177
        /*# string */ $from,
178
        /*# string */ $to,
179
        /*# string */ $action = 'copy'
180
    )/*# : bool */ {
181
        $obj = $this->path($from);
182
        $res = $obj->{$action}($this->path($to)->getPath());
183
        $this->copyError($obj);
184
        return $res;
185
    }
186
187
    /**
188
     * Copy between different filesystem
189
     *
190
     * @param  string $from
191
     * @param  string $to
192
     * @return bool
193
     * @access protected
194
     */
195
    protected function diffFilesystemCopy(
196
        /*# string */ $from,
197
        /*# string */ $to
198
    )/*# : bool */ {
199
        // if $to is dir, copy INTO $to
200
        if ($this->path($to)->isDir()) {
201
            $to = $this->mergePath($to, basename($from));
202
        }
203
204
        // read contents of $content
205
        $content = $this->get($from);
206
207
        if (is_null($content)) {
208
            return false;
209
210
        } elseif (is_array($content)) {
211
            return $this->copyDir($content, $to);
212
213
        } else {
214
            return $this->put($to, $content);
215
        }
216
    }
217
218
    /**
219
     * Exists on same filesystem ?
220
     *
221
     * @param  string $path1
222
     * @param  string $path2
223
     * @return bool
224
     * @access protected
225
     */
226
    protected function isSameFilesystem(
227
        /*# string */ $path1,
228
        /*# string */ $path2
229
    )/*# : bool */ {
230
        return $this->path($path1)->getFilesystem() === $this->path($path2)->getFilesystem();
231
    }
232
233
    /**
234
     * Copy an array of paths to destination
235
     *
236
     * @param  array $paths
237
     * @param  string $destination
238
     * @access protected
239
     */
240
    protected function copyDir(array $paths, /*# string */ $destination)
241
    {
242
        // if $destination is a file, reomve first
243
        if (!$this->path($destination)->isDir()) {
244
            $this->del($destination);
245
        }
246
247
        foreach ($paths as $path) {
248
            $dest = $this->mergePath($destination, basename($path));
249
            if (!$this->copy($path, $dest)) {
250
                return false;
251
            }
252
        }
253
        return true;
254
    }
255
256
    /**
257
     * Prepend mount point prefix to the array of paths
258
     *
259
     * @param  array $paths
260
     * @param  string $mountPoint
261
     * @return array
262
     * @access protected
263
     */
264
    protected function prependMountPoint(
265
        array $paths,
266
        /*# string */ $mountPoint
267
    )/*# : array */ {
268
        $res = [];
269
        foreach ($paths as $p) {
270
            $res[] = $this->mergePath($mountPoint, $p);
271
        }
272
        return $res;
273
    }
274
}
275