1<?php
2namespace Kunnu\Dropbox;
3
4use Kunnu\Dropbox\Http\Clients\DropboxHttpClientInterface;
5
6/**
7 * DropboxClient
8 */
9class DropboxClient
10{
11    /**
12     * Dropbox API Root URL.
13     *
14     * @const string
15     */
16    const BASE_PATH = 'https://api.dropboxapi.com/2';
17
18    /**
19     * Dropbox API Content Root URL.
20     *
21     * @const string
22     */
23    const CONTENT_PATH = 'https://content.dropboxapi.com/2';
24
25    /**
26     * DropboxHttpClientInterface Implementation
27     *
28     * @var \Kunnu\Dropbox\Http\Clients\DropboxHttpClientInterface
29     */
30    protected $httpClient;
31
32    /**
33     * Create a new DropboxClient instance
34     *
35     * @param DropboxHttpClientInterface $httpClient
36     */
37    public function __construct(DropboxHttpClientInterface $httpClient)
38    {
39        //Set the HTTP Client
40        $this->setHttpClient($httpClient);
41    }
42
43    /**
44     * Get the HTTP Client
45     *
46     * @return \Kunnu\Dropbox\Http\Clients\DropboxHttpClientInterface $httpClient
47     */
48    public function getHttpClient()
49    {
50        return $this->httpClient;
51    }
52
53    /**
54     * Set the HTTP Client
55     *
56     * @param \Kunnu\Dropbox\Http\Clients\DropboxHttpClientInterface $httpClient
57     *
58     * @return \Kunnu\Dropbox\DropboxClient
59     */
60    public function setHttpClient(DropboxHttpClientInterface $httpClient)
61    {
62        $this->httpClient = $httpClient;
63
64        return $this;
65    }
66
67    /**
68     * Get the API Base Path.
69     *
70     * @return string API Base Path
71     */
72    public function getBasePath()
73    {
74        return static::BASE_PATH;
75    }
76
77    /**
78     * Get the API Content Path.
79     *
80     * @return string API Content Path
81     */
82    public function getContentPath()
83    {
84        return static::CONTENT_PATH;
85    }
86
87    /**
88     * Get the Authorization Header with the Access Token.
89     *
90     * @param string $accessToken Access Token
91     *
92     * @return array Authorization Header
93     */
94    protected function buildAuthHeader($accessToken = "")
95    {
96        return ['Authorization' => 'Bearer '. $accessToken];
97    }
98
99    /**
100     * Get the Content Type Header.
101     *
102     * @param string $contentType Request Content Type
103     *
104     * @return array Content Type Header
105     */
106    protected function buildContentTypeHeader($contentType = "")
107    {
108        return ['Content-Type' => $contentType];
109    }
110
111    /**
112     * Build URL for the Request
113     *
114     * @param string $endpoint Relative API endpoint
115     * @param string $type Endpoint Type
116     *
117     * @link https://www.dropbox.com/developers/documentation/http/documentation#formats Request and response formats
118     *
119     * @return string The Full URL to the API Endpoints
120     */
121    protected function buildUrl($endpoint = '', $type = 'api')
122    {
123        //Get the base path
124        $base = $this->getBasePath();
125
126        //If the endpoint type is 'content'
127        if ($type === 'content') {
128            //Get the Content Path
129            $base = $this->getContentPath();
130        }
131
132        //Join and return the base and api path/endpoint
133        return $base . $endpoint;
134    }
135
136    /**
137     * Send the Request to the Server and return the Response
138     *
139     * @param  DropboxRequest $request
140     * @param  DropboxResponse $response
141     *
142     * @return \Kunnu\Dropbox\DropboxResponse
143     *
144     * @throws \Kunnu\Dropbox\Exceptions\DropboxClientException
145     */
146    public function sendRequest(DropboxRequest $request, DropboxResponse $response = null)
147    {
148        //Method
149        $method = $request->getMethod();
150
151        //Prepare Request
152        list($url, $headers, $requestBody) = $this->prepareRequest($request);
153
154        $options = [];
155        if ($response instanceof DropboxResponseToFile) {
156            $options['sink'] = $response->getFilePath();
157        }
158
159        //Send the Request to the Server through the HTTP Client
160        //and fetch the raw response as DropboxRawResponse
161        $rawResponse = $this->getHttpClient()->send($url, $method, $requestBody, $headers, $options);
162
163        //Create DropboxResponse from DropboxRawResponse
164        $response = $response ?: new DropboxResponse($request);
165        $response->setHttpStatusCode($rawResponse->getHttpResponseCode());
166        $response->setHeaders($rawResponse->getHeaders());
167        if (!$response instanceof DropboxResponseToFile) {
168            $response->setBody($rawResponse->getBody());
169        }
170
171        //Return the DropboxResponse
172        return $response;
173    }
174
175    /**
176     * Prepare a Request before being sent to the HTTP Client
177     *
178     * @param  \Kunnu\Dropbox\DropboxRequest $request
179     *
180     * @return array [Request URL, Request Headers, Request Body]
181     */
182    protected function prepareRequest(DropboxRequest $request)
183    {
184        //Build URL
185        $url = $this->buildUrl($request->getEndpoint(), $request->getEndpointType());
186
187        //The Endpoint is content
188        if ($request->getEndpointType() === 'content') {
189            //Dropbox requires the parameters to be passed
190            //through the 'Dropbox-API-Arg' header
191            $request->setHeaders(['Dropbox-API-Arg' => json_encode($request->getParams())]);
192
193            //If a File is also being uploaded
194            if ($request->hasFile()) {
195                //Content Type
196                $request->setContentType("application/octet-stream");
197
198                //Request Body (File Contents)
199                $requestBody = $request->getStreamBody()->getBody();
200            } else {
201                //Empty Body
202                $requestBody = null;
203            }
204        } else {
205            //The endpoint is 'api'
206            //Request Body (Parameters)
207            $requestBody = $request->getJsonBody()->getBody();
208        }
209
210        //Empty body
211        if (is_null($requestBody)) {
212            //Content Type needs to be kept empty
213            $request->setContentType("");
214        }
215
216        //Build headers
217        $headers = array_merge(
218            $this->buildAuthHeader($request->getAccessToken()),
219            $this->buildContentTypeHeader($request->getContentType()),
220            $request->getHeaders()
221            );
222
223        //Return the URL, Headers and Request Body
224        return [$url, $headers, $requestBody];
225    }
226}
227