Completed
Pull Request — master (#10)
by
unknown
02:57
created

SalesForceClient::getAuthorizationField()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
3
namespace Akeneo\SalesForce\Connector;
4
5
use Akeneo\SalesForce\Authentification\AccessToken;
6
use Akeneo\SalesForce\Authentification\AccessTokenGenerator;
7
use Akeneo\SalesForce\Exception\AuthenticationException;
8
use Akeneo\SalesForce\Exception\DuplicateDetectedException;
9
use Akeneo\SalesForce\Search\ParameterizedSearchBuilder;
10
use GuzzleHttp\Client as GuzzleClient;
11
use Akeneo\SalesForce\Exception\RequestException;
12
13
/**
14
 * @author Anael Chardan <[email protected]>
15
 */
16
class SalesForceClient
17
{
18
    const BASE_API_URL    = '/services/data/v37.0/sobjects';
19
    const BASE_QUERY_URL  = '/services/data/v37.0/query';
20
    const BASE_SEARCH_URL = '/services/data/v37.0/parameterizedSearch';
21
22
    /**
23
     * @var string
24
     */
25
    protected $salesforceLoginUrl;
26
27
    /**
28
     * @var string
29
     */
30
    protected $clientId;
31
32
    /**
33
     * @var string
34
     */
35
    protected $clientSecret;
36
37
    /**
38
     * @var GuzzleClient
39
     */
40
    protected $clientGuzzle;
41
42
    /**
43
     * @var string
44
     */
45
    protected $username;
46
47
    /**
48
     * @var string
49
     */
50
    protected $password;
51
52
    /**
53
     * @var AccessTokenGenerator
54
     */
55
    protected $accessTokenGenerator;
56
57
    /**
58
     * @var AccessToken
59
     */
60
    protected $salesForceAccessToken;
61
62
    /**
63
     * @var string
64
     */
65
    protected $baseUrl;
66
67
    /**
68
     * {@inheritdoc}
69
     */
70
    public function __construct(
71
        string $username,
72
        string $password,
73
        string $clientId,
74
        string $clientSecret,
75
        string $salesForceLoginUrl,
76
        GuzzleClient $guzzleClient,
77
        AccessTokenGenerator $accessTokenGenerator
78
    ) {
79
        $this->username             = $username;
80
        $this->password             = $password;
81
        $this->clientId             = $clientId;
82
        $this->clientSecret         = $clientSecret;
83
        $this->salesforceLoginUrl   = $salesForceLoginUrl;
84
        $this->clientGuzzle         = $guzzleClient;
85
        $this->accessTokenGenerator = $accessTokenGenerator;
86
    }
87
88
    public function search($query = null, $nextUrl = null)
89
    {
90
        $url = !empty($nextUrl) ?
91
            sprintf('%s/%s', $this->getBaseUrl(), $nextUrl) :
92
            sprintf(
93
                '%s%s/?q=%s',
94
                $this->getBaseUrl(),
95
                static::BASE_QUERY_URL,
96
                urlencode($query)
97
            )
98
        ;
99
100
        $response = $this->request(HttpWords::GET, $url, $this->getHeaderWithAuthorization());
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorization() is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
101
        $data     = json_decode($response->getBody(), true);
102
103
        $results = $data['records']; // or $data['searchRecords']
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
104
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
    public function parameterizedSearch(string $query)
116
    {
117
        $url = sprintf(
118
            '%s%s/?q=%s',
119
            $this->getBaseUrl(),
120
            static::BASE_SEARCH_URL,
121
            $query
122
        );
123
124
        $response = $this->request(HttpWords::GET, $url, $this->getHeaderWithAuthorization());
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorization() is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
125
        $data     = json_decode($response->getBody(), true);
126
        $results = $data['searchRecords'];
127
128
        return $results;
129
    }
130
131
    public function getAllRessources()
132
    {
133
        $url      = sprintf('%s%s', $this->getBaseUrl(), static::BASE_API_URL);
134
        $response = $this->request(HttpWords::GET, $url, $this->getHeaderWithAuthorization());
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorization() is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
135
136
        return json_decode($response->getBody(), true);
137
    }
138
139 View Code Duplication
    public function getBasicInformation(string $objectName)
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...
140
    {
141
        $url      = sprintf('%s%s/%s', $this->getBaseUrl(), static::BASE_API_URL, $objectName);
142
        $response = $this->request(HttpWords::GET, $url, $this->getHeaderWithAuthorization());
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorization() is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
143
144
        return json_decode($response->getBody(), true);
145
    }
146
147 View Code Duplication
    public function getDescribedObject(string $objectName)
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...
148
    {
149
        $url      = sprintf(
150
            '%s%s/%s/describe',
151
            $this->getBaseUrl(),
152
            static::BASE_API_URL,
153
            $objectName
154
        );
155
        $response = $this->request(HttpWords::GET, $url, $this->getHeaderWithAuthorization());
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorization() is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
156
157
        return json_decode($response->getBody(), true);
158
    }
159
160 View Code Duplication
    public function findById($objectName, $objectId, array $fields = [])
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...
161
    {
162
        $url      = sprintf(
163
            '%s%s/%s/%s?fields=%s',
164
            $this->getBaseUrl(),
165
            static::BASE_API_URL,
166
            $objectName,
167
            $objectId,
168
            implode(',', $fields)
169
        );
170
        $response = $this->request(HttpWords::GET, $url, $this->getHeaderWithAuthorization());
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorization() is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
171
172
        return json_decode($response->getBody(), true);
173
    }
174
175 View Code Duplication
    public function insert($objectName, array $data = [])
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...
176
    {
177
        $url      = sprintf('%s%s/%s/', $this->getBaseUrl(), static::BASE_API_URL, $objectName);
178
        $response = $this->request(HttpWords::POST, $url, $this->getHeaderWithAuthorizationAndData($data));
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorizationAndData($data) is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
179
180
        return json_decode($response->getBody(), true);
181
    }
182
183 View Code Duplication
    public function upsertByExternalId(
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...
184
        string $objectName,
185
        string $externalIdName,
186
        string $externalIdValue,
187
        array $data = []
188
    ) {
189
        $url      = sprintf(
190
            '%s%s/%s/%s/%s',
191
            $this->getBaseUrl(),
192
            static::BASE_API_URL,
193
            $objectName,
194
            $externalIdName,
195
            $externalIdValue
196
        );
197
        $response = $this->request(HttpWords::PATCH, $url, $this->getHeaderWithAuthorizationAndData($data));
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorizationAndData($data) is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
198
199
        return json_decode($response->getBody(), true);
200
    }
201
202 View Code Duplication
    public function update($objectName, $objectId, $data = [])
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...
203
    {
204
        $url      = sprintf(
205
            '%s%s/%s/%s',
206
            $this->getBaseUrl(),
207
            static::BASE_API_URL,
208
            $objectName,
209
            $objectId
210
        );
211
        $response = $this->request(HttpWords::PATCH, $url, $this->getHeaderWithAuthorizationAndData($data));
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorizationAndData($data) is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
212
213
        return json_decode($response->getBody(), true);
214
    }
215
216
    public function delete($objectName, $objectId)
217
    {
218
        $url = sprintf(
219
            '%s%s/%s/%s',
220
            $this->getBaseUrl(),
221
            static::BASE_API_URL,
222
            $objectName,
223
            $objectId
224
        );
225
226
        $this->request(HttpWords::DELETE, $url, $this->getHeaderWithAuthorization());
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorization() is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
227
228
        return true;
229
    }
230
231
    protected function getBaseUrl()
232
    {
233
        if ($this->baseUrl == null) {
234
            $this->setupToken();
235
        }
236
237
        return $this->baseUrl;
238
    }
239
240
    /**
241
     * @param AccessToken $accessToken
242
     */
243
    public function setAccessToken(AccessToken $accessToken)
244
    {
245
        $this->salesForceAccessToken = $accessToken;
246
        $this->baseUrl               = $accessToken->getApiUrl();
247
    }
248
249
    protected function getHeaderWithAuthorizationAndData(array $data = [])
250
    {
251
        return [
252
            HttpWords::HEADERS => $this->getHeaderJsonAndAuthorization(),
253
            HttpWords::BODY    => json_encode($data),
254
        ];
255
    }
256
257
    protected function getHeaderWithAuthorization()
258
    {
259
        return [HttpWords::HEADERS => $this->getAuthorizationField()];
260
    }
261
262
    protected function getHeaderJsonAndAuthorization()
263
    {
264
        return array_merge([HttpWords::CONTENT_TYPE => HttpWords::APPLICATION_JSON], $this->getAuthorizationField());
265
    }
266
267
    protected function getAuthorizationField()
268
    {
269
        $this->setupToken();
270
271
        $value = sprintf('%s %s', HttpWords::BEARER, $this->salesForceAccessToken->getAccessToken());
272
273
        return [HttpWords::AUTHORIZATION => $value];
274
    }
275
276
    /**
277
     * Refresh an existing access token.
278
     *
279
     * @throws \Exception
280
     *
281
     * @return AccessToken
282
     */
283
    protected function refreshToken()
284
    {
285
        $url = sprintf(
286
            '%s%s',
287
            $this->salesforceLoginUrl,
288
            SalesForceWords::TOKEN_ENDPOINT
289
        );
290
291
        $postData = [
292
            SalesForceWords::GRANT_TYPE    => SalesForceWords::REFRESH_TOKEN,
293
            SalesForceWords::CLIENT_ID     => $this->clientId,
294
            SalesForceWords::CLIENT_SECRET => $this->clientSecret,
295
            SalesForceWords::REFRESH_TOKEN => $this->salesForceAccessToken->getRefreshToken(),
296
        ];
297
298
        $response = $this->request(HttpWords::POST, $url, [SalesForceWords::FORM_PARAMS => $postData]);
0 ignored issues
show
Documentation introduced by
array(\Akeneo\SalesForce...RM_PARAMS => $postData) is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
299
300
        $update = json_decode($response->getBody(), true);
301
        $this->salesForceAccessToken->updateFromSalesforceRefresh($update);
302
        $this->baseUrl = $this->salesForceAccessToken->getApiUrl();
303
304
        return $this->salesForceAccessToken;
305
    }
306
307
    /**
308
     * @return AccessToken
309
     */
310
    protected function setupToken()
311
    {
312
        if ($this->salesForceAccessToken === null) {
313
            $this->authenticate();
314
315
            return;
316
        }
317
318
        if ($this->salesForceAccessToken->needsRefresh()) {
319
            $this->salesForceAccessToken = $this->refreshToken();
320
        }
321
    }
322
323
    protected function authenticate()
324
    {
325
        $url = sprintf(
326
            '%s%s',
327
            $this->salesforceLoginUrl,
328
            SalesForceWords::TOKEN_ENDPOINT
329
        );
330
331
        $postData = [
332
            SalesForceWords::GRANT_TYPE    => SalesForceWords::PASSWORD,
333
            SalesForceWords::CLIENT_ID     => $this->clientId,
334
            SalesForceWords::CLIENT_SECRET => $this->clientSecret,
335
            SalesForceWords::USERNAME      => $this->username,
336
            SalesForceWords::PASSWORD      => $this->password,
337
        ];
338
339
        $response = $this->request(HttpWords::POST, $url, [SalesForceWords::FORM_PARAMS => $postData]);
0 ignored issues
show
Documentation introduced by
array(\Akeneo\SalesForce...RM_PARAMS => $postData) is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
340
341
        $this->salesForceAccessToken = $this
342
            ->accessTokenGenerator
343
            ->createFromSalesforceResponse(json_decode($response->getBody(), true))
344
        ;
345
346
        $this->baseUrl = $this->salesForceAccessToken->getApiUrl();
347
    }
348
349
    /**
350
     * @param string $imageUrl
351
     *
352
     * @return mixed
353
     * @throws AuthenticationException
354
     * @throws \Exception
355
     */
356
    public function downloadImageFromUrl(string $imageUrl)
357
    {
358
        return $this->request(HttpWords::GET, $imageUrl, $this->getHeaderWithAuthorization());
0 ignored issues
show
Documentation introduced by
$this->getHeaderWithAuthorization() is of type array<string|integer,arr...string|integer,string>>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
359
    }
360
361
362
    /**
363
     * @param string $method
364
     * @param string $url
365
     * @param string $data
366
     *
367
     * @throws AuthenticationException
368
     * @throws \Exception
369
     *
370
     * @return mixed
371
     */
372
    protected function request($method, $url, $data)
373
    {
374
        try {
375
            $response = $this->clientGuzzle->$method($url, $data);
376
377
            return $response;
378
        } catch (\GuzzleHttp\Exception\RequestException $e) {
379
            if ($e->getResponse() === null) {
380
                throw $e;
381
            }
382
383
            $error = json_decode($e->getResponse()->getBody(), true);
384
385
            //If its an auth error convert to an auth exception
386
            if (isset($error[0])
387
                && isset($error[0]['errorCode'])
388
                && isset($error[0]['message'])
389
                && $e->getResponse()->getStatusCode() == 401
390
            ) {
391
                throw new AuthenticationException($error[0]['errorCode'], $error[0]['message']);
392
            }
393
394
            //Invalid data sent to salesforce
395
            if (isset($error[0])
396
                && isset($error[0]['errorCode'])
397
                && $e->getResponse()->getStatusCode() == 400
398
                && $error[0]['errorCode'] == 'DUPLICATES_DETECTED'
399
            ) {
400
                throw new DuplicateDetectedException($error, $e->getRequest()->getUri());
401
            }
402
403
            throw new RequestException($e->getMessage(), (string) $e->getResponse()->getBody());
404
        }
405
    }
406
}
407