Completed
Pull Request — master (#14)
by
unknown
02:08
created

Client::getAuthHeader()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php namespace Crunch\Salesforce;
2
3
use Crunch\Salesforce\Exceptions\RequestException;
4
use GuzzleHttp\Exception\RequestException as GuzzleRequestException;
5
use Crunch\Salesforce\Exceptions\AuthenticationException;
6
7
class Client
8
{
9
    /**
10
     * @var string
11
     */
12
    protected $salesforceLoginUrl;
13
14
    /**
15
     * @var string
16
     */
17
    protected $clientId;
18
19
    /**
20
     * @var string
21
     */
22
    protected $clientSecret;
23
24
    /**
25
     * @var AccessToken
26
     */
27
    private $accessToken;
28
29
    /**
30
     * @var string
31
     */
32
    private $baseUrl;
33
34
    /**
35
     * @var \GuzzleHttp\Client
36
     */
37
    private $guzzleClient;
38
39
40
    /**
41
     * Create a sf client using a client config object or an array of params
42
     *
43
     * @param ClientConfigInterface $clientConfig
44
     * @param \GuzzleHttp\Client    $guzzleClient
45
     * @throws \Exception
46
     */
47
    public function __construct(ClientConfigInterface $clientConfig, \GuzzleHttp\Client $guzzleClient)
48
    {
49
        $this->salesforceLoginUrl = $clientConfig->getLoginUrl();
50
        $this->clientId           = $clientConfig->getClientId();
51
        $this->clientSecret       = $clientConfig->getClientSecret();
52
53
        $this->guzzleClient = $guzzleClient;
54
    }
55
56
    /**
57
     * Create an instance of the salesforce client using the passed in config data
58
     *
59
     * @param $salesforceLoginUrl
60
     * @param $clientId
61
     * @param $clientSecret
62
     * @return Client
63
     */
64
    public static function create($salesforceLoginUrl, $clientId, $clientSecret)
65
    {
66
        return new self(new ClientConfig($salesforceLoginUrl, $clientId, $clientSecret), new \GuzzleHttp\Client);
67
    }
68
69
    /**
70
     * Fetch a specific object
71
     *
72
     * @param string $objectType
73
     * @param string $sfId
74
     * @param array  $fields
75
     * @return string
76
     */
77
    public function getRecord($objectType, $sfId, array $fields)
78
    {
79
        $url      = $this->baseUrl . '/services/data/v20.0/sobjects/' . $objectType . '/' . $sfId . '?fields=' . implode(',', $fields);
80
        $response = $this->makeRequest('get', $url, ['headers' => ['Authorization' => $this->getAuthHeader()]]);
81
82
        return json_decode($response->getBody(), true);
83
    }
84
85
    /**
86
     * Execute an SOQL query and return the result set
87
     * This will loop through large result sets collecting all the data so the query should be limited
88
     *
89
     * @param string|null $query
90
     * @param string|null $next_url
91
     * @return array
92
     * @throws \Exception
93
     */
94
    public function search($query = null, $next_url = null)
95
    {
96
        if ( ! empty($next_url)) {
97
            $url = $this->baseUrl . '/' . $next_url;
98
        } else {
99
            $url = $this->baseUrl . '/services/data/v24.0/query/?q=' . urlencode($query);
100
        }
101
        $response = $this->makeRequest('get', $url, ['headers' => ['Authorization' => $this->getAuthHeader()]]);
102
        $data     = json_decode($response->getBody(), true);
103
104
        $results = $data['records'];
105
        if ( ! $data['done']) {
106
            $more_results = $this->search(null, substr($data['nextRecordsUrl'], 1));
107
            if ( ! empty($more_results)) {
108
                $results = array_merge($results, $more_results);
109
            }
110
        }
111
112
        return $results;
113
    }
114
115
    /**
116
     * Make an update request
117
     *
118
     * @param string $object The object type to update
119
     * @param string $id The ID of the record to update
120
     * @param array  $data The data to put into the record
121
     * @return bool
122
     * @throws \Exception
123
     */
124
    public function updateRecord($object, $id, array $data)
125
    {
126
        $url = $this->baseUrl . '/services/data/v20.0/sobjects/' . $object . '/' . $id;
127
128
        $this->makeRequest('patch', $url, [
129
            'headers' => ['Content-Type' => 'application/json', 'Authorization' => $this->getAuthHeader()],
130
            'body'    => json_encode($data)
131
        ]);
132
133
        return true;
134
    }
135
136
    /**
137
     * Create a new object in salesforce
138
     *
139
     * @param string $object
140
     * @param array|object $data
141
     * @return string The id of the newly created record
142
     * @throws \Exception
143
     */
144
    public function createRecord($object, $data)
145
    {
146
        $url = $this->baseUrl . '/services/data/v20.0/sobjects/' . $object . '/';
147
148
        $response     = $this->makeRequest('post', $url, [
149
            'headers' => ['Content-Type' => 'application/json', 'Authorization' => $this->getAuthHeader()],
150
            'body'    => json_encode($data)
151
        ]);
152
        $responseBody = json_decode($response->getBody(), true);
153
154
        return $responseBody['id'];
155
    }
156
157
    /**
158
     * Delete an object with th specified id
159
     *
160
     * @param string $object
161
     * @param string $id
162
     * @return bool
163
     * @throws \Exception
164
     */
165 View Code Duplication
    public function deleteRecord($object, $id)
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...
166
    {
167
        $url = $this->baseUrl . '/services/data/v20.0/sobjects/' . $object . '/' . $id;
168
169
        $this->makeRequest('delete', $url, ['headers' => ['Authorization' => $this->getAuthHeader()]]);
170
171
        return true;
172
    }
173
174
175
176
    /**
177
     * Delete multiple objects with specified ids
178
     *
179
     * @param $object
180
     * @param $id
181
     * @return bool
182
     * @throws \Exception
183
     */
184 View Code Duplication
    public function bulkDeleteRecords(array $ids)
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...
185
    {
186
        $url = $this->baseUrl . '/services/data/v20.0/composite/sobjects?ids=' . \implode($ids, ',');
187
188
        $this->makeRequest('delete', $url, ['headers' => ['Authorization' => $this->getAuthHeader()]]);
189
190
        return true;
191
    }
192
193
    /**
194
     * Login with user and password
195
     *
196
     * @param $username
197
     * @param $password
198
     * @return array|mixed
199
     * @throws \Exception
200
     */
201 View Code Duplication
    public function login($username, $password)
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...
202
    {
203
        $url = $this->salesforceLoginUrl . 'services/oauth2/token';
204
205
        $post_data = [
206
            'grant_type'    => 'password',
207
            'client_id'     => $this->clientId,
208
            'client_secret' => $this->clientSecret,
209
            'username'      => $username,
210
            'password'      => $password
211
        ];
212
213
        $response = $this->makeRequest('post', $url, ['form_params' => $post_data]);
214
215
        return json_decode($response->getBody(), true);
216
    }
217
218
    /**
219
     * Complete the oauth process by confirming the code and returning an access token
220
     *
221
     * @param $code
222
     * @param $redirect_url
223
     * @return array|mixed
224
     * @throws \Exception
225
     */
226 View Code Duplication
    public function authorizeConfirm($code, $redirect_url)
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...
227
    {
228
        $url = $this->salesforceLoginUrl . 'services/oauth2/token';
229
230
        $post_data = [
231
            'grant_type'    => 'authorization_code',
232
            'client_id'     => $this->clientId,
233
            'client_secret' => $this->clientSecret,
234
            'code'          => $code,
235
            'redirect_uri'  => $redirect_url
236
        ];
237
238
        $response = $this->makeRequest('post', $url, ['form_params' => $post_data]);
239
240
        return json_decode($response->getBody(), true);
241
    }
242
243
    /**
244
     * Get the url to redirect users to when setting up a salesforce access token
245
     *
246
     * @param $redirectUrl
247
     * @return string
248
     */
249
    public function getLoginUrl($redirectUrl)
250
    {
251
        $params = [
252
            'client_id'     => $this->clientId,
253
            'redirect_uri'  => $redirectUrl,
254
            'response_type' => 'code',
255
            'grant_type'    => 'authorization_code'
256
        ];
257
258
        return $this->salesforceLoginUrl . 'services/oauth2/authorize?' . http_build_query($params);
259
    }
260
261
    /**
262
     * Refresh an existing access token
263
     *
264
     * @return AccessToken
265
     * @throws \Exception
266
     */
267
    public function refreshToken()
268
    {
269
        $url = $this->salesforceLoginUrl . 'services/oauth2/token';
270
271
        $post_data = [
272
            'grant_type'    => 'refresh_token',
273
            'client_id'     => $this->clientId,
274
            'client_secret' => $this->clientSecret,
275
            'refresh_token' => $this->accessToken->getRefreshToken()
276
        ];
277
278
        $response = $this->makeRequest('post', $url, ['form_params' => $post_data]);
279
280
        $update = json_decode($response->getBody(), true);
281
        $this->accessToken->updateFromSalesforceRefresh($update);
282
283
        return $this->accessToken;
284
    }
285
286
    /**
287
     * @param AccessToken $accessToken
288
     */
289
    public function setAccessToken(AccessToken $accessToken)
290
    {
291
        $this->accessToken = $accessToken;
292
        $this->baseUrl     = $accessToken->getApiUrl();
293
    }
294
295
    /**
296
     * @param string $method
297
     * @param string $url
298
     * @param array  $data
299
     * @return mixed
300
     * @throws AuthenticationException
301
     * @throws RequestException
302
     */
303
    private function makeRequest($method, $url, $data)
304
    {
305
        try {
306
            $response = $this->guzzleClient->$method($url, $data);
307
308
            return $response;
309
        } catch (GuzzleRequestException $e) {
310
            
311
            if ($e->getResponse() === null) {
312
        		throw $e;
313
        	}
314
315
            //If its an auth error convert to an auth exception
316
            if ($e->getResponse()->getStatusCode() == 401) {
317
                $error = json_decode($e->getResponse()->getBody(), true);
318
                throw new AuthenticationException($error[0]['errorCode'], $error[0]['message']);
319
            }
320
            throw new RequestException($e->getMessage(), (string)$e->getResponse()->getBody());
321
        }
322
323
    }
324
325
    /**
326
     * @return string
327
     */
328
    private function getAuthHeader()
329
    {
330
        if ($this->accessToken === null) {
331
    		throw new AuthenticationException(0, "Access token not set");
332
    	}
333
    	
334
        return 'Bearer ' . $this->accessToken->getAccessToken();
335
    }
336
337
}
338