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

Client   B

Complexity

Total Complexity 42

Size/Duplication

Total Lines 455
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 11

Importance

Changes 0
Metric Value
wmc 42
lcom 3
cbo 11
dl 0
loc 455
rs 8.295
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 3
A getMyOrganization() 0 5 1
A createAdministrator() 0 5 1
A getAdministrators() 0 11 2
A createWorker() 0 5 1
A getWorkers() 0 17 2
A getWorker() 0 11 2
A getHubs() 0 11 2
A createTeam() 0 5 1
A getTeams() 0 11 2
A getTeam() 0 5 1
A createDestination() 0 5 1
A getDestination() 0 5 1
A createRecipient() 0 5 1
A getRecipient() 0 5 1
A getRecipientByName() 0 5 1
A getRecipientByPhone() 0 5 1
A createTask() 0 5 1
A getTasks() 0 19 3
A getTask() 0 5 1
A getTaskByShortId() 0 5 1
A setOrganizationTasks() 0 4 1
A addTasksToOrganization() 0 4 1
A setTeamTasks() 0 4 1
A addTasksToTeam() 0 4 1
A setWorkerTasks() 0 4 1
A addTasksToWorker() 0 4 1
A createWebhook() 0 11 1
A getWebhooks() 0 11 2
A setContainerTasks() 0 16 3

How to fix   Complexity   

Complex Class

Complex classes like Client often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Client, and based on these observations, apply Extract Interface, too.

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