Completed
Push — master ( 176c96...a24a9b )
by Raza
02:21
created

DropboxClient::setClient()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 9
cts 9
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 1
crap 2
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 21
    public function __construct($token, HttpClient $client = null)
76
    {
77 21
        $this->setAccessToken($token);
78
79 21
        $this->setClient($client);
80
81 21
        $this->apiUrl = 'https://api.dropboxapi.com/2/';
82 21
        $this->apiContentUrl = 'https://content.dropboxapi.com/2/';
83 21
    }
84
85
    /**
86
     * Set Http Client.
87
     *
88
     * @param \GuzzleHttp\Client $client
89
     */
90 21
    protected function setClient(HttpClient $client = null)
91
    {
92 21
        if ($client instanceof HttpClient) {
93 16
            $this->client = $client;
94 16
        } else {
95 5
            $this->client = new HttpClient([
96
                'headers' => [
97 5
                    'Authorization' => "Bearer {$this->accessToken}",
98 5
                ],
99 5
            ]);
100
        }
101 21
    }
102
103
    /**
104
     * Set Dropbox OAuth access token.
105
     *
106
     * @param string $token
107
     */
108 21
    protected function setAccessToken($token)
109
    {
110 21
        $this->accessToken = $token;
111 21
    }
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
        $this->content = null;
279
280 1
        $response = $this->doDropboxApiContentRequest();
281
282 1
        return (string) $response->getBody();
283
    }
284
285
    /**
286
     * Starts returning the contents of a folder.
287
     *
288
     * If the result's ListFolderResult.has_more field is true, call
289
     * list_folder/continue with the returned ListFolderResult.cursor to retrieve more entries.
290
     *
291
     * Note: auth.RateLimitError may be returned if multiple list_folder or list_folder/continue calls
292
     * with same parameters are made simultaneously by same API app for same user. If your app implements
293
     * retry logic, please hold off the retry until the previous request finishes.
294
     *
295
     * @param string $path
296
     * @param bool   $recursive
297
     *
298
     * @return \Psr\Http\Message\ResponseInterface
299
     *
300
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder
301
     */
302 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...
303
    {
304 1
        $this->setupRequest([
305 1
            'path'      => $this->normalizePath($path),
306 1
            'recursive' => $recursive,
307 1
        ]);
308
309 1
        $this->apiEndpoint = 'files/list_folder';
310
311 1
        return $this->doDropboxApiRequest();
312
    }
313
314
    /**
315
     * Once a cursor has been retrieved from list_folder, use this to paginate through all files and
316
     * retrieve updates to the folder, following the same rules as documented for list_folder.
317
     *
318
     * @param string $cursor
319
     *
320
     * @return \Psr\Http\Message\ResponseInterface
321
     *
322
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-continue
323
     */
324 1
    public function listFolderContinue($cursor = '')
325
    {
326 1
        $this->setupRequest([
327 1
            'cursor' => $cursor,
328 1
        ]);
329
330 1
        $this->apiEndpoint = 'files/list_folder/continue';
331
332 1
        return $this->doDropboxApiRequest();
333
    }
334
335
    /**
336
     * Move a file or folder to a different location in the user's Dropbox.
337
     *
338
     * If the source path is a folder all its contents will be moved.
339
     *
340
     * @param string $fromPath
341
     * @param string $toPath
342
     *
343
     * @return \Psr\Http\Message\ResponseInterface
344
     *
345
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-move
346
     */
347 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...
348
    {
349 1
        $this->setupRequest([
350 1
            'from_path' => $this->normalizePath($fromPath),
351 1
            'to_path'   => $this->normalizePath($toPath),
352 1
        ]);
353
354 1
        $this->apiEndpoint = 'files/move_v2';
355
356 1
        return $this->doDropboxApiRequest();
357
    }
358
359
    /**
360
     * Create a new file with the contents provided in the request.
361
     *
362
     * Do not use this to upload a file larger than 150 MB. Instead, create an upload session with upload_session/start.
363
     *
364
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload
365
     *
366
     * @param string          $path
367
     * @param string|resource $contents
368
     * @param string|array    $mode
369
     *
370
     * @return array
371
     */
372 1
    public function upload($path, $contents, $mode = 'add')
373
    {
374 1
        if ($this->shouldUploadChunk($contents)) {
375
            return $this->uploadChunk($path, $contents, $mode);
0 ignored issues
show
Bug introduced by
It seems like $mode defined by parameter $mode on line 372 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...
376
        }
377
378 1
        $this->setupRequest([
379 1
            'path' => $this->normalizePath($path),
380 1
            'mode' => $mode,
381 1
        ]);
382
383 1
        $this->content = $contents;
384
385 1
        $this->apiEndpoint = 'files/upload';
386
387 1
        $response = $this->doDropboxApiContentRequest();
388
389 1
        $metadata = json_decode($response->getBody(), true);
390 1
        $metadata['.tag'] = 'file';
391
392 1
        return $metadata;
393
    }
394
395
    /**
396
     * Get Account Info for current authenticated user.
397
     *
398
     * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
399
     *
400
     * @return \Psr\Http\Message\ResponseInterface
401
     */
402 1
    public function getAccountInfo()
403
    {
404 1
        $this->apiEndpoint = 'users/get_current_account';
405
406 1
        return $this->doDropboxApiRequest();
407
    }
408
409
    /**
410
     * Revoke current access token.
411
     *
412
     * @link https://www.dropbox.com/developers/documentation/http/documentation#auth-token-revoke
413
     *
414
     * @return \Psr\Http\Message\ResponseInterface
415
     */
416 1
    public function revokeToken()
417
    {
418 1
        $this->apiEndpoint = 'auth/token/revoke';
419
420 1
        return $this->doDropboxApiRequest();
421
    }
422
423
    /**
424
     * Set Dropbox API request data.
425
     *
426
     * @param array $request
427
     */
428 14
    protected function setupRequest($request)
429
    {
430 14
        $this->request = $request;
431 14
    }
432
433
    /**
434
     * Perform Dropbox API request.
435
     *
436
     * @throws \Exception
437
     *
438
     * @return \Psr\Http\Message\ResponseInterface
439
     */
440 10
    protected function doDropboxApiRequest()
441
    {
442 10
        $request = empty($this->request) ? [] : ['json' => $this->request];
443
444
        try {
445 10
            $response = $this->client->post("{$this->apiUrl}{$this->apiEndpoint}", $request);
446 10
        } catch (HttpClientException $exception) {
447
            throw $this->determineException($exception);
448
        }
449
450 10
        return json_decode($response->getBody(), true);
451
    }
452
453
    /**
454
     * Setup headers for Dropbox API request.
455
     *
456
     * @return array
457
     */
458 6
    protected function setupDropboxHeaders()
459
    {
460
        $headers = [
461 6
            'Dropbox-API-Arg' => json_encode(
462 6
                $this->request
463 6
            ),
464 6
        ];
465
466 6
        if (!empty($this->content)) {
467 4
            $headers['Content-Type'] = 'application/octet-stream';
468 4
        }
469
470 6
        return $headers;
471
    }
472
473
    /**
474
     * Perform Dropbox API request.
475
     *
476
     * @throws \Exception
477
     *
478
     * @return \Psr\Http\Message\ResponseInterface
479
     */
480 6
    protected function doDropboxApiContentRequest()
481
    {
482
        try {
483 6
            $response = $this->client->post("{$this->apiContentUrl}{$this->apiEndpoint}", [
484 6
                'headers' => $this->setupDropboxHeaders(),
485 6
                'body'    => !empty($this->content) ? $this->content : '',
486 6
            ]);
487 6
        } catch (HttpClientException $exception) {
488
            throw $this->determineException($exception);
489
        }
490
491 6
        return $response;
492
    }
493
494
    /**
495
     * Normalize path.
496
     *
497
     * @param string $path
498
     *
499
     * @return string
500
     */
501 11
    protected function normalizePath($path)
502
    {
503 11
        if (preg_match("/^id:.*|^rev:.*|^(ns:[0-9]+(\/.*)?)/",  $path) === 1) {
504 1
            return $path;
505
        }        
506
        
507 11
        $path = (trim($path, '/') === '') ? '' : '/'.$path;
508
509 11
        return str_replace('//', '/', $path);
510
    }
511
512
    /**
513
     * Catch Dropbox API request exception.
514
     *
515
     * @param HttpClientException $exception
516
     *
517
     * @return \Exception
518
     */
519
    protected function determineException(HttpClientException $exception)
520
    {
521
        if (!empty($exception->getResponse()) && in_array($exception->getResponse()->getStatusCode(), [400, 409])) {
522
            return new BadRequest($exception->getResponse());
523
        }
524
525
        return $exception;
526
    }
527
}
528