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