Passed
Push — master ( ee86b6...621ce0 )
by frey
01:01
created

Adapter::getVisibility()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 6
Ratio 42.86 %

Code Coverage

Tests 2
CRAP Score 14.1113

Importance

Changes 0
Metric Value
cc 5
eloc 7
nc 3
nop 1
dl 6
loc 14
ccs 2
cts 7
cp 0.2857
crap 14.1113
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace Freyo\Flysystem\QcloudCOSv3;
4
5
use Freyo\Flysystem\QcloudCOSv3\Client\Conf;
6
use Freyo\Flysystem\QcloudCOSv3\Client\Cosapi;
7
use Freyo\Flysystem\QcloudCOSv3\Exceptions\RuntimeException;
8
use League\Flysystem\Adapter\AbstractAdapter;
9
use League\Flysystem\AdapterInterface;
10
use League\Flysystem\Config;
11
use League\Flysystem\Util;
12
13
/**
14
 * Class Adapter.
15
 */
16
class Adapter extends AbstractAdapter
17
{
18
    /**
19
     * @var
20
     */
21
    protected $bucket;
22
23
    /**
24
     * @var
25
     */
26
    protected $debug;
27
28
    /**
29
     * Adapter constructor.
30
     *
31
     * @param $config
32
     */
33
    public function __construct($config)
34
    {
35
        Conf::setAppId($config['app_id']);
36
        Conf::setSecretId($config['secret_id']);
37
        Conf::setSecretKey($config['secret_key']);
38
39
        $this->bucket = $config['bucket'];
40
        $this->debug = $config['debug'];
41
42
        $this->setPathPrefix($config['protocol'].'://'.$config['domain'].'/');
43
44
        Cosapi::setTimeout($config['timeout']);
45
    }
46
47
    /**
48
     * @return string
49
     */
50 14
    public function getBucket()
51
    {
52 14
        return $this->bucket;
53
    }
54
55
    /**
56
     * @param string $path
57
     *
58
     * @return string
59
     */
60 1
    public function getUrl($path)
61
    {
62 1
        return $this->applyPathPrefix($path);
63
    }
64
65
    /**
66
     * @param string $path
67
     * @param string $contents
68
     * @param Config $config
69
     *
70
     * @throws RuntimeException
71
     *
72
     * @return array|bool
73
     */
74 View Code Duplication
    public function write($path, $contents, Config $config)
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...
75
    {
76
        $tmpfname = $this->writeTempFile($contents);
77
78
        if (false === $tmpfname) {
79
            return false;
80
        }
81
82
        try {
83
            $response = Cosapi::upload($this->getBucket(), $tmpfname, $path,
0 ignored issues
show
Bug introduced by
It seems like $tmpfname defined by $this->writeTempFile($contents) on line 76 can also be of type boolean; however, Freyo\Flysystem\QcloudCO...Client\Cosapi::upload() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
84
                                        null, null, $config->get('insertOnly', 1));
85
86
            $this->deleteTempFile($tmpfname);
87
88
            $response = $this->normalizeResponse($response);
89
90
            if (false === $response) {
91
                return false;
92
            }
93
94
            $this->setContentType($path, $contents);
95
        } catch (RuntimeException $exception) {
96
            $this->deleteTempFile($tmpfname);
97
98
            throw $exception;
99
        }
100
101
        return $response;
102
    }
103
104
    /**
105
     * @param string   $path
106
     * @param resource $resource
107
     * @param Config   $config
108
     *
109
     * @throws RuntimeException
110
     *
111
     * @return array|bool
112
     */
113 1 View Code Duplication
    public function writeStream($path, $resource, Config $config)
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...
114
    {
115 1
        $uri = stream_get_meta_data($resource)['uri'];
116
117 1
        $response = Cosapi::upload($this->getBucket(), $uri, $path,
118 1
                                    null, null, $config->get('insertOnly', 1));
119
120 1
        $response = $this->normalizeResponse($response);
121
122
        if (false === $response) {
123
            return false;
124
        }
125
126
        $this->setContentType($path, stream_get_contents($resource));
127
128
        return $response;
129
    }
130
131
    /**
132
     * @param string $path
133
     * @param string $contents
134
     * @param Config $config
135
     *
136
     * @throws RuntimeException
137
     *
138
     * @return array|bool
139
     */
140 View Code Duplication
    public function update($path, $contents, Config $config)
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...
141
    {
142
        $tmpfname = $this->writeTempFile($contents);
143
144
        if (false === $tmpfname) {
145
            return false;
146
        }
147
148
        try {
149
            $response = Cosapi::upload($this->getBucket(), $tmpfname, $path,
0 ignored issues
show
Bug introduced by
It seems like $tmpfname defined by $this->writeTempFile($contents) on line 142 can also be of type boolean; however, Freyo\Flysystem\QcloudCO...Client\Cosapi::upload() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
150
                                        null, null, $config->get('insertOnly', 0));
151
152
            $this->deleteTempFile($tmpfname);
153
154
            $response = $this->normalizeResponse($response);
155
156
            if (false === $response) {
157
                return false;
158
            }
159
160
            $this->setContentType($path, $contents);
161
        } catch (RuntimeException $exception) {
162
            $this->deleteTempFile($tmpfname);
163
164
            throw $exception;
165
        }
166
167
        return $response;
168
    }
169
170
    /**
171
     * @param string   $path
172
     * @param resource $resource
173
     * @param Config   $config
174
     *
175
     * @throws RuntimeException
176
     *
177
     * @return array|bool
178
     */
179 1 View Code Duplication
    public function updateStream($path, $resource, Config $config)
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...
180
    {
181 1
        $uri = stream_get_meta_data($resource)['uri'];
182
183 1
        $response = Cosapi::upload($this->getBucket(), $uri, $path,
184 1
                                    null, null, $config->get('insertOnly', 0));
185
186 1
        $response = $this->normalizeResponse($response);
187
188
        if (false === $response) {
189
            return false;
190
        }
191
192
        $this->setContentType($path, stream_get_contents($resource));
193
194
        return $response;
195
    }
196
197
    /**
198
     * @param string $path
199
     * @param string $newpath
200
     *
201
     * @return bool
202
     */
203 1
    public function rename($path, $newpath)
204
    {
205 1
        return (bool) $this->normalizeResponse(
206 1
            Cosapi::move($this->getBucket(), $path, $newpath, 1)
207 1
        );
208
    }
209
210
    /**
211
     * @param string $path
212
     * @param string $newpath
213
     *
214
     * @return bool
215
     */
216
    public function copy($path, $newpath)
217
    {
218
        $resource = $this->read($path);
219
220
        if (false === $resource) {
221
            return false;
222
        }
223
224
        return (bool) $this->update($newpath, $resource['contents'], new Config());
225
    }
226
227
    /**
228
     * @param string $path
229
     *
230
     * @return bool
231
     */
232 1
    public function delete($path)
233
    {
234 1
        return (bool) $this->normalizeResponse(
235 1
            Cosapi::delFile($this->getBucket(), $path)
236 1
        );
237
    }
238
239
    /**
240
     * @param string $dirname
241
     *
242
     * @return bool
243
     */
244 1
    public function deleteDir($dirname)
245
    {
246 1
        return (bool) $this->normalizeResponse(
247 1
            Cosapi::delFolder($this->getBucket(), $dirname)
248 1
        );
249
    }
250
251
    /**
252
     * @param string $dirname
253
     * @param Config $config
254
     *
255
     * @return array|bool
256
     */
257 1
    public function createDir($dirname, Config $config)
258
    {
259 1
        return $this->normalizeResponse(
260 1
            Cosapi::createFolder($this->getBucket(), $dirname)
261 1
        );
262
    }
263
264
    /**
265
     * @param string $path
266
     * @param string $visibility
267
     *
268
     * @return bool
269
     */
270 1
    public function setVisibility($path, $visibility)
271
    {
272 1
        $visibility = $visibility === AdapterInterface::VISIBILITY_PUBLIC ? 'eWPrivateRPublic' : 'eWRPrivate';
273
274 1
        return (bool) $this->normalizeResponse(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return (bool) $this->nor...h, null, $visibility)); (boolean) is incompatible with the return type declared by the interface League\Flysystem\AdapterInterface::setVisibility of type array|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
275 1
            Cosapi::update($this->getBucket(), $path, null, $visibility)
276 1
        );
277
    }
278
279
    /**
280
     * @param string $path
281
     *
282
     * @return bool
283
     */
284 1
    public function has($path)
285
    {
286
        try {
287 1
            return (bool) $this->getMetadata($path);
288 1
        } catch (RuntimeException $exception) {
289 1
            return false;
290
        }
291
    }
292
293
    /**
294
     * @param string $path
295
     *
296
     * @return string
297
     */
298
    public function read($path)
299
    {
300
        return ['contents' => file_get_contents($this->getUrl($path))];
301
    }
302
303
    /**
304
     * @param string $path
305
     *
306
     * @return array
307
     */
308
    public function readStream($path)
309
    {
310
        return ['stream' => fopen($this->getUrl($path), 'r')];
311
    }
312
313
    /**
314
     * @param string $directory
315
     * @param bool   $recursive
316
     *
317
     * @return bool
318
     */
319 1
    public function listContents($directory = '', $recursive = false)
320
    {
321 1
        return $this->normalizeResponse(
322 1
            Cosapi::listFolder($this->getBucket(), $directory)
323 1
        );
324
    }
325
326
    /**
327
     * @param string $path
328
     *
329
     * @return bool
330
     */
331 6
    public function getMetadata($path)
332
    {
333 6
        return $this->normalizeResponse(
334 6
            Cosapi::stat($this->getBucket(), $path)
335 6
        );
336
    }
337
338
    /**
339
     * @param string $path
340
     *
341
     * @return array|bool
342
     */
343 1
    public function getSize($path)
344
    {
345 1
        $stat = $this->getMetadata($path);
346
347
        if (isset($stat['filesize'])) {
348
            return ['size' => $stat['filesize']];
349
        }
350
351
        return false;
352
    }
353
354
    /**
355
     * @param string $path
356
     *
357
     * @return array|bool
358
     */
359 1
    public function getMimetype($path)
360
    {
361 1
        $stat = $this->getMetadata($path);
362
363
        if (isset($stat['custom_headers']['Content-Type'])) {
364
            return ['mimetype' => $stat['custom_headers']['Content-Type']];
365
        }
366
367
        return false;
368
    }
369
370
    /**
371
     * @param string $path
372
     *
373
     * @return array|bool
374
     */
375 1
    public function getTimestamp($path)
376
    {
377 1
        $stat = $this->getMetadata($path);
378
379
        if (isset($stat['ctime'])) {
380
            return ['timestamp' => $stat['ctime']];
381
        }
382
383
        return false;
384
    }
385
386
    /**
387
     * @param string $path
388
     *
389
     * @return array|bool
390
     */
391 1
    public function getVisibility($path)
392
    {
393 1
        $stat = $this->getMetadata($path);
394
395 View Code Duplication
        if (isset($stat['authority']) && $stat['authority'] === 'eWPrivateRPublic') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
396
            return ['visibility' => AdapterInterface::VISIBILITY_PUBLIC];
397
        }
398
399 View Code Duplication
        if (isset($stat['authority']) && $stat['authority'] === 'eWRPrivate') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
400
            return ['visibility' => AdapterInterface::VISIBILITY_PRIVATE];
401
        }
402
403
        return false;
404
    }
405
406
    /**
407
     * @param string $content
408
     *
409
     * @return bool|string
410
     */
411
    private function writeTempFile($content)
412
    {
413
        $tmpfname = tempnam('/tmp', 'dir');
414
415
        chmod($tmpfname, 0777);
416
417
        file_put_contents($tmpfname, $content);
418
419
        return $tmpfname;
420
    }
421
422
    /**
423
     * @param string|bool $tmpfname
424
     *
425
     * @return bool
426
     */
427
    private function deleteTempFile($tmpfname)
428
    {
429
        if (false === $tmpfname) {
430
            return false;
431
        }
432
433
        return unlink($tmpfname);
434
    }
435
436
    /**
437
     * @param string $path
438
     * @param string $content
439
     *
440
     * @return bool
441
     */
442
    protected function setContentType($path, $content)
443
    {
444
        $custom_headers = [
445
            'Content-Type' => Util::guessMimeType($path, $content),
446
        ];
447
448
        return $this->normalizeResponse(
449
            Cosapi::update($this->getBucket(), $path, null, null, $custom_headers)
450
        );
451
    }
452
453
    /**
454
     * @param $response
455
     *
456
     * @throws RuntimeException
457
     *
458
     * @return mixed
459
     */
460 14
    protected function normalizeResponse($response)
461
    {
462 14
        if ($response['code'] == 0) {
463
            return isset($response['data']) ? $response['data'] : true;
464
        }
465
466 14
        if ($this->debug) {
467 14
            throw new RuntimeException($response['message'], $response['code']);
468
        }
469
470
        return false;
471
    }
472
}
473