Completed
Push — master ( 3c6fd6...131292 )
by Raza
02:05
created

DropboxClient   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 511
Duplicated Lines 8.81 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 95.04%

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 6
dl 45
loc 511
ccs 134
cts 141
cp 0.9504
rs 9.6
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A setClient() 0 12 2
A setAccessToken() 0 4 1
A copy() 11 11 1
A createFolder() 0 13 1
A delete() 0 10 1
A download() 0 14 1
A getMetaData() 0 10 1
A getTemporaryLink() 12 12 1
A getThumbnail() 0 14 1
A listFolder() 11 11 1
A listFolderContinue() 0 10 1
A move() 11 11 1
A upload() 0 22 2
A getAccountInfo() 0 6 1
A revokeToken() 0 6 1
A setupRequest() 0 4 1
A doDropboxApiRequest() 0 12 3
A setupDropboxHeaders() 0 14 2
A doDropboxApiContentRequest() 0 13 3
A normalizePath() 0 6 2
A determineException() 0 8 3

How to fix   Duplicated Code   

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:

1
<?php
2
3
namespace Srmklive\Dropbox\Client;
4
5
use GuzzleHttp\Client as HttpClient;
6
use GuzzleHttp\Exception\ClientException as HttpClientException;
7
use GuzzleHttp\Psr7\StreamWrapper;
8
use Srmklive\Dropbox\Exceptions\BadRequest;
9
use Srmklive\Dropbox\UploadContent;
10
11
class DropboxClient
12
{
13
    use UploadContent;
14
15
    const THUMBNAIL_FORMAT_JPEG = 'jpeg';
16
    const THUMBNAIL_FORMAT_PNG = 'png';
17
18
    const THUMBNAIL_SIZE_XS = 'w32h32';
19
    const THUMBNAIL_SIZE_S = 'w64h64';
20
    const THUMBNAIL_SIZE_M = 'w128h128';
21
    const THUMBNAIL_SIZE_L = 'w640h480';
22
    const THUMBNAIL_SIZE_XL = 'w1024h768';
23
24
    const MAX_CHUNK_SIZE = 157286400;
25
26
    /** @var \GuzzleHttp\Client */
27
    protected $client;
28
29
    /**
30
     * Dropbox OAuth access token.
31
     *
32
     * @var string
33
     */
34
    protected $accessToken;
35
36
    /**
37
     * Dropbox API v2 Url.
38
     *
39
     * @var string
40
     */
41
    protected $apiUrl;
42
43
    /**
44
     * Dropbox content API v2 url for uploading content.
45
     *
46
     * @var string
47
     */
48
    protected $apiContentUrl;
49
50
    /**
51
     * Dropbox API v2 endpoint.
52
     *
53
     * @var string
54
     */
55
    protected $apiEndpoint;
56
57
    /**
58
     * @var mixed
59
     */
60
    protected $content;
61
62
    /**
63
     * Dropbox API request data.
64
     *
65
     * @var array
66
     */
67
    protected $request;
68
69
    /**
70
     * DropboxClient constructor.
71
     *
72
     * @param string             $token
73
     * @param \GuzzleHttp\Client $client
74
     */
75 20
    public function __construct($token, HttpClient $client = null)
76
    {
77 20
        $this->setAccessToken($token);
78
79 20
        $this->setClient($client);
80
81 20
        $this->apiUrl = 'https://api.dropboxapi.com/2/';
82 20
        $this->apiContentUrl = 'https://content.dropboxapi.com/2/';
83 20
    }
84
85
    /**
86
     * Set Http Client.
87
     *
88
     * @param \GuzzleHttp\Client $client
89
     */
90 20
    protected function setClient(HttpClient $client = null)
91
    {
92 20
        if ($client instanceof HttpClient) {
93 16
            $this->client = $client;
94 16
        } else {
95 4
            $this->client = new HttpClient([
96
                'headers' => [
97 4
                    'Authorization' => "Bearer {$this->accessToken}",
98 4
                ],
99 4
            ]);
100
        }
101 20
    }
102
103
    /**
104
     * Set Dropbox OAuth access token.
105
     *
106
     * @param string $token
107
     */
108 20
    protected function setAccessToken($token)
109
    {
110 20
        $this->accessToken = $token;
111 20
    }
112
113
    /**
114
     * Copy a file or folder to a different location in the user's Dropbox.
115
     *
116
     * If the source path is a folder all its contents will be copied.
117
     *
118
     * @param string $fromPath
119
     * @param string $toPath
120
     *
121
     * @return \Psr\Http\Message\ResponseInterface
122
     *
123
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy
124
     */
125 1 View Code Duplication
    public function copy($fromPath, $toPath)
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...
126
    {
127 1
        $this->setupRequest([
128 1
            'from_path' => $this->normalizePath($fromPath),
129 1
            'to_path'   => $this->normalizePath($toPath),
130 1
        ]);
131
132 1
        $this->apiEndpoint = 'files/copy';
133
134 1
        return $this->doDropboxApiRequest();
135
    }
136
137
    /**
138
     * Create a folder at a given path.
139
     *
140
     * @param string $path
141
     *
142
     * @return \Psr\Http\Message\ResponseInterface
143
     *
144
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-create_folder
145
     */
146 1
    public function createFolder($path)
147
    {
148 1
        $this->setupRequest([
149 1
            'path' => $this->normalizePath($path),
150 1
        ]);
151
152 1
        $this->apiEndpoint = 'files/create_folder';
153
154 1
        $response = $this->doDropboxApiRequest();
155 1
        $response['.tag'] = 'folder';
156
157 1
        return $response;
158
    }
159
160
    /**
161
     * Delete the file or folder at a given path.
162
     *
163
     * If the path is a folder, all its contents will be deleted too.
164
     * A successful response indicates that the file or folder was deleted.
165
     *
166
     * @param string $path
167
     *
168
     * @return \Psr\Http\Message\ResponseInterface
169
     *
170
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-delete
171
     */
172 1
    public function delete($path)
173
    {
174 1
        $this->setupRequest([
175 1
            'path' => $this->normalizePath($path),
176 1
        ]);
177
178 1
        $this->apiEndpoint = 'files/delete';
179
180 1
        return $this->doDropboxApiRequest();
181
    }
182
183
    /**
184
     * Download a file from a user's Dropbox.
185
     *
186
     * @param string $path
187
     *
188
     * @return resource
189
     *
190
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-download
191
     */
192 1
    public function download($path)
193
    {
194 1
        $this->setupRequest([
195 1
            'path' => $this->normalizePath($path),
196 1
        ]);
197
198 1
        $this->apiEndpoint = 'files/download';
199
        
200 1
        $this->content = null;
201
202 1
        $response = $this->doDropboxApiContentRequest();
203
204 1
        return StreamWrapper::getResource($response->getBody());
205
    }
206
207
    /**
208
     * Returns the metadata for a file or folder.
209
     *
210
     * Note: Metadata for the root folder is unsupported.
211
     *
212
     * @param string $path
213
     *
214
     * @return \Psr\Http\Message\ResponseInterface
215
     *
216
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata
217
     */
218 1
    public function getMetaData($path)
219
    {
220 1
        $this->setupRequest([
221 1
            'path' => $this->normalizePath($path),
222 1
        ]);
223
224 1
        $this->apiEndpoint = 'files/get_metadata';
225
226 1
        return $this->doDropboxApiRequest();
227
    }
228
229
    /**
230
     * Get a temporary link to stream content of a file.
231
     *
232
     * This link will expire in four hours and afterwards you will get 410 Gone.
233
     * Content-Type of the link is determined automatically by the file's mime type.
234
     *
235
     * @param string $path
236
     *
237
     * @return string
238
     *
239
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_temporary_link
240
     */
241 1 View Code Duplication
    public function getTemporaryLink($path)
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...
242
    {
243 1
        $this->setupRequest([
244 1
            'path' => $this->normalizePath($path),
245 1
        ]);
246
247 1
        $this->apiEndpoint = 'files/get_temporary_link';
248
249 1
        $response = $this->doDropboxApiRequest();
250
251 1
        return $response['link'];
252
    }
253
254
    /**
255
     * Get a thumbnail for an image.
256
     *
257
     * This method currently supports files with the following file extensions:
258
     * jpg, jpeg, png, tiff, tif, gif and bmp.
259
     *
260
     * Photos that are larger than 20MB in size won't be converted to a thumbnail.
261
     *
262
     * @param string $path
263
     * @param string $format
264
     * @param string $size
265
     *
266
     * @return string
267
     */
268 1
    public function getThumbnail($path, $format = 'jpeg', $size = 'w64h64')
269
    {
270 1
        $this->setupRequest([
271 1
            'path'   => $this->normalizePath($path),
272 1
            'format' => $format,
273 1
            'size'   => $size,
274 1
        ]);
275
276 1
        $this->apiEndpoint = 'files/get_thumbnail';
277
278 1
        $response = $this->doDropboxApiContentRequest();
279
280 1
        return (string) $response->getBody();
281
    }
282
283
    /**
284
     * Starts returning the contents of a folder.
285
     *
286
     * If the result's ListFolderResult.has_more field is true, call
287
     * list_folder/continue with the returned ListFolderResult.cursor to retrieve more entries.
288
     *
289
     * Note: auth.RateLimitError may be returned if multiple list_folder or list_folder/continue calls
290
     * with same parameters are made simultaneously by same API app for same user. If your app implements
291
     * retry logic, please hold off the retry until the previous request finishes.
292
     *
293
     * @param string $path
294
     * @param bool   $recursive
295
     *
296
     * @return \Psr\Http\Message\ResponseInterface
297
     *
298
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder
299
     */
300 1 View Code Duplication
    public function listFolder($path = '', $recursive = false)
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...
301
    {
302 1
        $this->setupRequest([
303 1
            'path'      => $this->normalizePath($path),
304 1
            'recursive' => $recursive,
305 1
        ]);
306
307 1
        $this->apiEndpoint = 'files/list_folder';
308
309 1
        return $this->doDropboxApiRequest();
310
    }
311
312
    /**
313
     * Once a cursor has been retrieved from list_folder, use this to paginate through all files and
314
     * retrieve updates to the folder, following the same rules as documented for list_folder.
315
     *
316
     * @param string $cursor
317
     *
318
     * @return \Psr\Http\Message\ResponseInterface
319
     *
320
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-continue
321
     */
322 1
    public function listFolderContinue($cursor = '')
323
    {
324 1
        $this->setupRequest([
325 1
            'cursor' => $cursor,
326 1
        ]);
327
328 1
        $this->apiEndpoint = 'files/list_folder/continue';
329
330 1
        return $this->doDropboxApiRequest();
331
    }
332
333
    /**
334
     * Move a file or folder to a different location in the user's Dropbox.
335
     *
336
     * If the source path is a folder all its contents will be moved.
337
     *
338
     * @param string $fromPath
339
     * @param string $toPath
340
     *
341
     * @return \Psr\Http\Message\ResponseInterface
342
     *
343
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-move
344
     */
345 1 View Code Duplication
    public function move($fromPath, $toPath)
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...
346
    {
347 1
        $this->setupRequest([
348 1
            'from_path' => $this->normalizePath($fromPath),
349 1
            'to_path'   => $this->normalizePath($toPath),
350 1
        ]);
351
352 1
        $this->apiEndpoint = 'files/move_v2';
353
354 1
        return $this->doDropboxApiRequest();
355
    }
356
357
    /**
358
     * Create a new file with the contents provided in the request.
359
     *
360
     * Do not use this to upload a file larger than 150 MB. Instead, create an upload session with upload_session/start.
361
     *
362
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload
363
     *
364
     * @param string          $path
365
     * @param string|resource $contents
366
     * @param string|array    $mode
367
     *
368
     * @return array
369
     */
370 1
    public function upload($path, $contents, $mode = 'add')
371
    {
372 1
        if ($this->shouldUploadChunk($contents)) {
373
            return $this->uploadChunk($path, $contents, $mode);
0 ignored issues
show
Bug introduced by
It seems like $mode defined by parameter $mode on line 370 can also be of type array; however, Srmklive\Dropbox\UploadContent::uploadChunk() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and 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...
374
        }
375
376 1
        $this->setupRequest([
377 1
            'path' => $this->normalizePath($path),
378 1
            'mode' => $mode,
379 1
        ]);
380
381 1
        $this->content = $contents;
382
383 1
        $this->apiEndpoint = 'files/upload';
384
385 1
        $response = $this->doDropboxApiContentRequest();
386
387 1
        $metadata = json_decode($response->getBody(), true);
388 1
        $metadata['.tag'] = 'file';
389
390 1
        return $metadata;
391
    }
392
393
    /**
394
     * Get Account Info for current authenticated user.
395
     *
396
     * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
397
     *
398
     * @return \Psr\Http\Message\ResponseInterface
399
     */
400 1
    public function getAccountInfo()
401
    {
402 1
        $this->apiEndpoint = 'users/get_current_account';
403
404 1
        return $this->doDropboxApiRequest();
405
    }
406
407
    /**
408
     * Revoke current access token.
409
     *
410
     * @link https://www.dropbox.com/developers/documentation/http/documentation#auth-token-revoke
411
     *
412
     * @return \Psr\Http\Message\ResponseInterface
413
     */
414 1
    public function revokeToken()
415
    {
416 1
        $this->apiEndpoint = 'auth/token/revoke';
417
418 1
        return $this->doDropboxApiRequest();
419
    }
420
421
    /**
422
     * Set Dropbox API request data.
423
     *
424
     * @param array $request
425
     */
426 14
    protected function setupRequest($request)
427
    {
428 14
        $this->request = $request;
429 14
    }
430
431
    /**
432
     * Perform Dropbox API request.
433
     *
434
     * @throws \Exception
435
     *
436
     * @return \Psr\Http\Message\ResponseInterface
437
     */
438 10
    protected function doDropboxApiRequest()
439
    {
440 10
        $request = empty($this->request) ? [] : ['json' => $this->request];
441
442
        try {
443 10
            $response = $this->client->post("{$this->apiUrl}{$this->apiEndpoint}", $request);
444 10
        } catch (HttpClientException $exception) {
445
            throw $this->determineException($exception);
446
        }
447
448 10
        return json_decode($response->getBody(), true);
449
    }
450
451
    /**
452
     * Setup headers for Dropbox API request.
453
     *
454
     * @return array
455
     */
456 6
    protected function setupDropboxHeaders()
457
    {
458
        $headers = [
459 6
            'Dropbox-API-Arg' => json_encode(
460 6
                $this->request
461 6
            ),
462 6
        ];
463
464 6
        if (!empty($this->content)) {
465 4
            $headers['Content-Type'] = 'application/octet-stream';
466 4
        }
467
468 6
        return $headers;
469
    }
470
471
    /**
472
     * Perform Dropbox API request.
473
     *
474
     * @throws \Exception
475
     *
476
     * @return \Psr\Http\Message\ResponseInterface
477
     */
478 6
    protected function doDropboxApiContentRequest()
479
    {
480
        try {
481 6
            $response = $this->client->post("{$this->apiContentUrl}{$this->apiEndpoint}", [
482 6
                'headers' => $this->setupDropboxHeaders(),
483 6
                'body'    => !empty($this->content) ? $this->content : '',
484 6
            ]);
485 6
        } catch (HttpClientException $exception) {
486
            throw $this->determineException($exception);
487
        }
488
489 6
        return $response;
490
    }
491
492
    /**
493
     * Normalize path.
494
     *
495
     * @param string $path
496
     *
497
     * @return string
498
     */
499 10
    protected function normalizePath($path)
500
    {
501 10
        $path = (trim($path, '/') === '') ? '' : '/'.$path;
502
503 10
        return str_replace('//', '/', $path);
504
    }
505
506
    /**
507
     * Catch Dropbox API request exception.
508
     *
509
     * @param HttpClientException $exception
510
     *
511
     * @return \Exception
512
     */
513
    protected function determineException(HttpClientException $exception)
514
    {
515
        if (!empty($exception->getResponse()) && in_array($exception->getResponse()->getStatusCode(), [400, 409])) {
516
            return new BadRequest($exception->getResponse());
517
        }
518
519
        return $exception;
520
    }
521
}
522