Client::search()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 9.6
c 0
b 0
f 0
cc 4
nc 6
nop 2
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
    public function deleteRecord($object, $id)
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
     * Complete the oauth process by confirming the code and returning an access token
176
     *
177
     * @param $code
178
     * @param $redirect_url
179
     * @return array|mixed
180
     * @throws \Exception
181
     */
182
    public function authorizeConfirm($code, $redirect_url)
183
    {
184
        $url = $this->salesforceLoginUrl . 'services/oauth2/token';
185
186
        $post_data = [
187
            'grant_type'    => 'authorization_code',
188
            'client_id'     => $this->clientId,
189
            'client_secret' => $this->clientSecret,
190
            'code'          => $code,
191
            'redirect_uri'  => $redirect_url
192
        ];
193
194
        $response = $this->makeRequest('post', $url, ['form_params' => $post_data]);
195
196
        return json_decode($response->getBody(), true);
197
    }
198
199
    /**
200
     * Get the url to redirect users to when setting up a salesforce access token
201
     *
202
     * @param $redirectUrl
203
     * @return string
204
     */
205
    public function getLoginUrl($redirectUrl)
206
    {
207
        $params = [
208
            'client_id'     => $this->clientId,
209
            'redirect_uri'  => $redirectUrl,
210
            'response_type' => 'code',
211
            'grant_type'    => 'authorization_code'
212
        ];
213
214
        return $this->salesforceLoginUrl . 'services/oauth2/authorize?' . http_build_query($params);
215
    }
216
217
    /**
218
     * Refresh an existing access token
219
     *
220
     * @return AccessToken
221
     * @throws \Exception
222
     */
223
    public function refreshToken()
224
    {
225
        $url = $this->salesforceLoginUrl . 'services/oauth2/token';
226
227
        $post_data = [
228
            'grant_type'    => 'refresh_token',
229
            'client_id'     => $this->clientId,
230
            'client_secret' => $this->clientSecret,
231
            'refresh_token' => $this->accessToken->getRefreshToken()
232
        ];
233
234
        $response = $this->makeRequest('post', $url, ['form_params' => $post_data]);
235
236
        $update = json_decode($response->getBody(), true);
237
        $this->accessToken->updateFromSalesforceRefresh($update);
238
239
        return $this->accessToken;
240
    }
241
242
    /**
243
     * @param AccessToken $accessToken
244
     */
245
    public function setAccessToken(AccessToken $accessToken)
246
    {
247
        $this->accessToken = $accessToken;
248
        $this->baseUrl     = $accessToken->getApiUrl();
249
    }
250
251
    /**
252
     * @param string $method
253
     * @param string $url
254
     * @param array  $data
255
     * @return mixed
256
     * @throws AuthenticationException
257
     * @throws RequestException
258
     */
259
    private function makeRequest($method, $url, $data)
260
    {
261
        try {
262
            $response = $this->guzzleClient->$method($url, $data);
263
264
            return $response;
265
        } catch (GuzzleRequestException $e) {
266
            
267
            if ($e->getResponse() === null) {
268
        		throw $e;
269
        	}
270
271
            //If its an auth error convert to an auth exception
272
            if ($e->getResponse()->getStatusCode() == 401) {
273
                $error = json_decode($e->getResponse()->getBody(), true);
274
                throw new AuthenticationException($error[0]['errorCode'], $error[0]['message']);
275
            }
276
            throw new RequestException($e->getMessage(), (string)$e->getResponse()->getBody());
277
        }
278
279
    }
280
281
    /**
282
     * @return string
283
     */
284
    private function getAuthHeader()
285
    {
286
        if ($this->accessToken === null) {
287
    		throw new AuthenticationException(0, "Access token not set");
288
    	}
289
    	
290
        return 'Bearer ' . $this->accessToken->getAccessToken();
291
    }
292
293
}
294