Completed
Push — master ( 8edee4...0135c2 )
by Marin
04:35
created

Client::getDestination()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Anorgan\Onfleet;
4
5
use GuzzleHttp\Client as Guzzle;
6
use GuzzleHttp\Exception\ClientException;
7
8
/**
9
 * Class Client
10
 * @package Anorgan\Onfleet
11
 */
12
class Client extends Guzzle
13
{
14
    const BASE_URL = 'https://onfleet.com/api/{version}/';
15
    const VERSION  = 'v2';
16
17
    /**
18
     * Client constructor.
19
     * @param string $username
20
     * @param array $config
21
     */
22
    public function __construct($username, array $config = [])
23
    {
24
        $version = isset($config['version']) ? $config['version'] : static::VERSION;
25
26
        if (!isset($config['base_url'])) {
27
            $config['base_url'] = [
28
                static::BASE_URL,
29
                ['version' => $version]
30
            ];
31
        }
32
        $config['defaults']['auth'] = [$username, null];
33
34
        parent::__construct($config);
35
    }
36
37
    /**
38
     * @param string $url
39
     * @param array $options
40
     * @throws \Exception
41
     * @return \GuzzleHttp\Message\ResponseInterface
42
     */
43
    public function post($url = null, array $options = [])
44
    {
45
        try {
46
            return parent::post($url, $options);
47
        } catch (ClientException $e) {
48
            $error   = $e->getResponse()->json();
49
            $message = $error['message']['message'];
50
            if (isset($error['message']['cause'])) {
51
                if (is_array($error['message']['cause'])) {
52
                    $message .= ' '.implode(', ', $error['message']['cause']);
53
                } else {
54
                    $message .= ' '.$error['message']['cause'];
55
                }
56
            }
57
            throw new \Exception('Error while calling post on '.$url.': '.$message);
58
        }
59
    }
60
61
    /**
62
     * @param string $url
63
     * @param array $options
64
     * @return \GuzzleHttp\Message\ResponseInterface|null
65
     */
66
    public function get($url = null, $options = [])
67
    {
68
        try {
69
            return parent::get($url, $options);
70
        } catch (ClientException $e) {
71
            if ($e->getCode() == 404) {
72
                return null;
73
            }
74
            throw $e;
75
        }
76
    }
77
78
    /**
79
     * @return Organization
80
     */
81
    public function getMyOrganization(): Organization
82
    {
83
        $response = $this->get('organization');
84
        return Organization::fromJson($response->json(['object' => true]), $this);
85
    }
86
87
    /**
88
     * Get delegatee organization
89
     *
90
     * @param string $id
91
     * @return Organization
92
     */
93
    public function getOrganization($id): Organization
94
    {
95
        $response = $this->get('organizations/'.$id);
96
        return Organization::fromJson($response->json(['object' => true]), $this);
97
    }
98
99
    /**
100
     * @param array $data {
101
     * @var string $name The administrator’s complete name.
102
     * @var string $email The administrator’s email address.
103
     * @var string $phone Optional. The administrator’s phone number.
104
     * @var boolean $isReadOnly Optional. Whether this administrator can perform write operations.
105
     * }
106
     * @return Administrator
107
     */
108
    public function createAdministrator(array $data): Administrator
109
    {
110
        $response = $this->post('admins', ['json' => $data]);
111
        return Administrator::fromJson($response->json(['object' => true]), $this);
112
    }
113
114
    /**
115
     * @return Administrator[]
116
     */
117
    public function getAdministrators(): array
118
    {
119
        $response = $this->get('admins');
120
121
        $administrators = [];
122
        foreach ($response->json(['object' => true]) as $administratorData) {
123
            $administrators[] = Administrator::fromJson($administratorData, $this);
124
        }
125
126
        return $administrators;
127
    }
128
129
    /**
130
     * @param array $data {
131
     * @var string $name The worker’s complete name.
132
     * @var string $phone A valid phone number as per the worker’s organization’s country.
133
     * @var string|array $teams One or more team IDs of which the worker is a member.
134
     * @var object $vehicle Optional. The worker’s vehicle; providing no vehicle details is equivalent to the
135
     *                              worker being on foot.
136
     * @var string $type The vehicle’s type, must be one of CAR, MOTORCYCLE, BICYCLE or TRUCK.
137
     * @var string $description Optional. The vehicle’s make, model, year, or any other relevant identifying details.
138
     * @var string $licensePlate Optional. The vehicle’s license plate number.
139
     * @var string $color Optional. The vehicle's color.
140
     * @var integer $capacity Optional. The maximum number of units this worker can carry, for route optimization purposes.
141
     * }
142
     * @return Worker
143
     */
144
    public function createWorker(array $data): Worker
145
    {
146
        $response = $this->post('workers', ['json' => $data]);
147
        return Worker::fromJson($response->json(['object' => true]), $this);
148
    }
149
150
    /**
151
     * @param string $filter Optional. A comma-separated list of fields to return, if all are not desired. For example, name, location.
152
     * @param string $teams Optional. A comma-separated list of the team IDs that workers must be part of.
153
     * @param string $states Optional. A comma-separated list of worker states, where
154
     *                       0 is off-duty, 1 is idle (on-duty, no active task) and 2 is active (on-duty, active task).
155
     * @return Worker[]
156
     */
157
    public function getWorkers($filter = null, $teams = null, $states = null): array
158
    {
159
        $query = array_filter([
160
            'filter' => $filter,
161
            'teams'  => $teams,
162
            'states' => $states,
163
        ]);
164
        $response = $this->get('workers', compact('query'));
165
166
        $workers = [];
167
        foreach ($response->json(['object' => true]) as $workerData) {
168
            $workers[] = Worker::fromJson($workerData, $this);
169
        }
170
171
        return $workers;
172
    }
173
174
    /**
175
     * @param string $id
176
     * @param string $filter Optional. A comma-separated list of fields to return, if all are not desired.
177
     *                        For example: "name, location".
178
     * @param bool $analytics Basic worker duty event, traveled distance (meters) and time analytics are optionally
179
     *                        available by specifying the query parameter analytics as true.
180
     * @return Worker
181
     *
182
     * @todo: Add "from" and "to" timestamps if analytics is true
183
     */
184
    public function getWorker($id, $filter = null, $analytics = false): Worker
185
    {
186
        $query = array_filter([
187
            'filter'    => $filter,
188
            'analytics' => $analytics ? 'true' : 'false',
189
        ]);
190
        $response = $this->get('workers/'.$id, compact('query'));
191
192
        return Worker::fromJson($response->json(['object' => true]), $this);
193
    }
194
195
    /**
196
     * @return Hub[]
197
     */
198
    public function getHubs(): array
199
    {
200
        $response = $this->get('hubs');
201
202
        $hubs = [];
203
        foreach ($response->json(['object' => true]) as $hubData) {
204
            $hubs[] = Hub::fromJson($hubData, $this);
205
        }
206
207
        return $hubs;
208
    }
209
210
    /**
211
     * @param array $data {
212
     * @var string $name A unique name for the team.
213
     * @var array $workers An array of worker IDs.
214
     * @var array $managers An array of managing administrator IDs.
215
     * @var string $hub Optional. The ID of the team's hub.
216
     * }
217
     *
218
     * @return Team
219
     */
220
    public function createTeam(array $data): Team
221
    {
222
        $response = $this->post('teams', ['json' => $data]);
223
        return Team::fromJson($response->json(['object' => true]), $this);
224
    }
225
226
    /**
227
     * @return Team[]
228
     */
229
    public function getTeams(): array
230
    {
231
        $response = $this->get('teams');
232
233
        $teams = [];
234
        foreach ($response->json(['object' => true]) as $teamData) {
235
            $teams[] = Team::fromJson($teamData, $this);
236
        }
237
238
        return $teams;
239
    }
240
241
    /**
242
     * @param string $id
243
     * @return Team
244
     */
245
    public function getTeam($id): Team
246
    {
247
        $response = $this->get('teams/'.$id);
248
        return Team::fromJson($response->json(['object' => true]), $this);
249
    }
250
251
    /**
252
     * @param array $data {
253
     * @var array $address The destination’s street address details. {
254
     * @var string $name Optional. A name associated with this address, e.g., "Transamerica Pyramid".
255
     * @var string $number The number component of this address, it may also contain letters.
256
     * @var string $street The name of the street.
257
     * @var string $apartment Optional. The suite or apartment number, or any additional relevant information.
258
     * @var string $city The name of the municipality.
259
     * @var string $state Optional. The name of the state, province or jurisdiction.
260
     * @var string $postalCode Optional. The postal or zip code.
261
     * @var string $country The name of the country.
262
     * @var string $unparsed Optional. A complete address specified in a single, unparsed string where the
263
     *                                 various elements are separated by commas. If present, all other address
264
     *                                 properties will be ignored (with the exception of name and apartment).
265
     *                                 In some countries, you may skip most address details (like city or state)
266
     *                                 if you provide a valid postalCode: for example,
267
     *                                 543 Howard St, 94105, USA will be geocoded correctly.
268
     *     }
269
     * @var string $notes Optional. Note that goes with this destination, e.g. "Please call before"
270
     * @var array $location Optional. The [ longitude, latitude ] geographic coordinates. If missing, the API will
271
     *                          geocode based on the address details provided. Note that geocoding may slightly modify
272
     *                          the format of the address properties. address.unparsed cannot be provided if you are
273
     *                          also including a location.
274
     * }
275
     * @return Destination
276
     */
277
    public function createDestination(array $data): Destination
278
    {
279
        $response = $this->post('destinations', ['json' => $data]);
280
        return Destination::fromJson($response->json(['object' => true]), $this);
281
    }
282
283
    /**
284
     * @param string $id
285
     * @return Destination
286
     */
287
    public function getDestination($id): Destination
288
    {
289
        $response = $this->get('destinations/'.$id);
290
        return Destination::fromJson($response->json(['object' => true]), $this);
291
    }
292
293
    /**
294
     * @param array $data {
295
     * @var string $name The recipient’s complete name.
296
     * @var string $phone A unique, valid phone number as per the recipient’s organization’s country.
297
     * @var string $notes Optional. Notes for this recipient: these are global notes that should not be
298
     *                          task- or destination-specific.
299
     *                          For example, "Customer since June 2012, does not drink non-specialty coffee".
300
     * @var boolean $skipSMSNotifications Optional. Whether this recipient has requested to not receive SMS
301
     *                          notifications. Defaults to false if not provided.
302
     * @var boolean $skipPhoneNumberValidation Optional. Whether to skip validation of this recipient's phone
303
     *                          number. An E.164-like number is still required (must start with +), however the API
304
     *                          will not enforce any country-specific validation rules.
305
     * }
306
     * @return Recipient
307
     */
308
    public function createRecipient(array $data): Recipient
309
    {
310
        $response = $this->post('recipients', ['json' => $data]);
311
        return Recipient::fromJson($response->json(['object' => true]), $this);
312
    }
313
314
    /**
315
     * @param string $id
316
     * @return Recipient
317
     */
318
    public function getRecipient($id): Recipient
319
    {
320
        $response = $this->get('recipients/'.$id);
321
        return Recipient::fromJson($response->json(['object' => true]), $this);
322
    }
323
324
    /**
325
     * @param string $name
326
     * @return Recipient|null
327
     */
328
    public function getRecipientByName($name)
329
    {
330
        $name     = str_replace('+', '%20', urlencode(strtolower($name)));
331
        $response = $this->get('recipients/name/'.$name);
332
333
        if (null === $response) {
334
            return null;
335
        }
336
337
        return Recipient::fromJson($response->json(['object' => true]), $this);
338
    }
339
340
    /**
341
     * @param string $phone
342
     * @return Recipient|null
343
     */
344
    public function getRecipientByPhone($phone)
345
    {
346
        $phone    = preg_replace('/[^\d]/', '', $phone);
347
        $response = $this->get('recipients/phone/+'.$phone);
348
349
        if (null === $response) {
350
            return null;
351
        }
352
353
        return Recipient::fromJson($response->json(['object' => true]), $this);
354
    }
355
356
    /**
357
     * @see Task::createAutoAssignedArray
358
     * @param array $data
359
     * @return Task
360
     */
361
    public function createTask(array $data): Task
362
    {
363
        $response = $this->post('tasks', ['json' => $data]);
364
        return Task::fromJson($response->json(['object' => true]), $this);
365
    }
366
367
    /**
368
     * @param int|\DateTime $from The starting time of the range. Tasks created or completed at or after this time will be included.
369
     *                                 Millisecond precision int or DateTime
370
     * @param int|\DateTime $to Optional. If missing, defaults to the current time. The ending time of the range.
371
     *                                 Tasks created or completed before this time will be included.
372
     *                                 Millisecond precision int or DateTime
373
     * @param string $lastId Optional. Used to walk the paginated response, if there is one. Tasks created after this ID
374
     *                       will be returned, up to the per-query limit of 64.
375
     * @return Task[]
376
     */
377
    public function getTasks($from, $to = null, &$lastId = null): array
378
    {
379
        if ($from instanceof \DateTime) {
380
            $from = $from->getTimestamp() * 1000;
381
        }
382
        if ($to instanceof \DateTime) {
383
            $to = $to->getTimestamp() * 1000;
384
        }
385
        $query = array_filter([
386
            'from'   => $from,
387
            'to'     => $to,
388
            'lastId' => $lastId,
389
        ]);
390
        $response = $this->get('tasks/all', compact('query'));
391
392
        $tasks  = [];
393
        $json   = $response->json(['object' => true]);
394
        $lastId = isset($json->lastId) ? $json->lastId : false;
395
        foreach ($json->tasks as $taskData) {
396
            $tasks[] = Task::fromJson($taskData, $this);
397
        }
398
399
        return $tasks;
400
    }
401
402
    /**
403
     * @param string $id
404
     * @return Task
405
     */
406
    public function getTask($id): Task
407
    {
408
        $response = $this->get('tasks/'.$id);
409
        return Task::fromJson($response->json(['object' => true]), $this);
410
    }
411
412
    /**
413
     * @param string $shortId
414
     * @return Task
415
     */
416
    public function getTaskByShortId($shortId): Task
417
    {
418
        $response = $this->get('tasks/shortId/'.$shortId);
419
        return Task::fromJson($response->json(['object' => true]), $this);
420
    }
421
422
    /**
423
     * Replace all organization's tasks.
424
     *
425
     * @param array $taskIds
426
     * @param string $organizationId
427
     */
428
    public function setOrganizationTasks(array $taskIds, $organizationId)
429
    {
430
        $this->setContainerTasks('organizations', $organizationId, $taskIds);
431
    }
432
433
    /**
434
     * @param array $taskIds
435
     * @param string $organizationId
436
     */
437
    public function addTasksToOrganization(array $taskIds, $organizationId)
438
    {
439
        $this->setContainerTasks('organizations', $organizationId, $taskIds, -1);
440
    }
441
442
    /**
443
     * Replace all team's tasks.
444
     *
445
     * @param array $taskIds
446
     * @param string $teamId
447
     */
448
    public function setTeamTasks(array $taskIds, $teamId)
449
    {
450
        $this->setContainerTasks('teams', $teamId, $taskIds);
451
    }
452
453
    /**
454
     * @param array $taskIds
455
     * @param string $teamId
456
     */
457
    public function addTasksToTeam(array $taskIds, $teamId)
458
    {
459
        $this->setContainerTasks('teams', $teamId, $taskIds, -1);
460
    }
461
462
    /**
463
     * Replace all worker's tasks.
464
     *
465
     * @param array $taskIds
466
     * @param string $workerId
467
     */
468
    public function setWorkerTasks(array $taskIds, $workerId)
469
    {
470
        $this->setContainerTasks('workers', $workerId, $taskIds);
471
    }
472
473
    /**
474
     * @param array $taskIds
475
     * @param string $workerId
476
     */
477
    public function addTasksToWorker(array $taskIds, $workerId)
478
    {
479
        $this->setContainerTasks('workers', $workerId, $taskIds, -1);
480
    }
481
482
    /**
483
     * @param string $url
484
     * @param int $triggerId
485
     * @return Webhook
486
     */
487
    public function createWebhook($url, $triggerId): Webhook
488
    {
489
        $response = $this->post('webhooks', [
490
            'json' => [
491
                'url'     => $url,
492
                'trigger' => $triggerId,
493
            ]
494
        ]);
495
496
        return Webhook::fromJson($response->json(['object' => true]), $this);
497
    }
498
499
    /**
500
     * @return Webhook[]
501
     */
502
    public function getWebhooks(): array
503
    {
504
        $response = $this->get('webhooks');
505
506
        $webhooks = [];
507
        foreach ($response->json(['object' => true]) as $webhookData) {
508
            $webhooks[] = Webhook::fromJson($webhookData, $this);
509
        }
510
511
        return $webhooks;
512
    }
513
514
    /**
515
     * @param string $containerEndpoint "organizations", "workers" or "teams"
516
     * @param string $targetId ID of organization, worker or team.
517
     * @param array $taskIds Array of task IDs.
518
     * @param int $position Insert tasks at a given index. To append to the end, use -1, to prepend, use 0.
519
     */
520
    private function setContainerTasks($containerEndpoint, $targetId, array $taskIds, $position = null)
521
    {
522
        if (null !== $position) {
523
            if (!is_numeric($position)) {
524
                throw new \InvalidArgumentException('Position argument should be numeric, -1 for appending, 0 to prepend');
525
            }
526
527
            array_unshift($taskIds, $position);
528
        }
529
530
        $this->put('containers/'.$containerEndpoint.'/'.$targetId, [
531
            'json' => [
532
                'tasks' => $taskIds
533
            ]
534
        ]);
535
    }
536
}
537