Issues (17)

lib/RestApiImpl.php (4 issues)

Labels
Severity
1
<?php
2
/*
3
 * The MIT License
4
 *
5
 * Copyright 2016 BCL Technologies.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 */
25
26
namespace Bcl\EasyPdfCloud;
27
28
use InvalidArgumentException;
29
use function stream_context_create;
30
use function urlencode;
31
use function mb_strlen;
32
use function array_push;
33
use function http_build_query;
34
35
class RestApiImpl extends OAuth2HttpClient
36
{
37
    const WORKFLOW_ID_LENGTH = 16;
38
    const JOB_ID_LENGTH = 16;
39
40
    private $urlInfo;
41
42
    public function __construct($clientId, $clientSecret, IOAuth2TokenManager $tokenManager = null, UrlInfo $urlInfo = null)
43
    {
44
        if (StringUtils::isEmpty($clientId)) {
45
            throw new InvalidArgumentException('client ID is not specified');
46
        }
47
48
        if (StringUtils::isEmpty($clientSecret)) {
49
            throw new InvalidArgumentException('client secret is not specified');
50
        }
51
52
        if (null === $tokenManager) {
53
            $tokenManager = new LocalFileTokenManager($clientId);
54
        }
55
56
        if (null === $urlInfo) {
57
            $urlInfo = new UrlInfo();
58
        }
59
60
        $this->urlInfo = $urlInfo;
61
62
        parent::__construct($clientId, $clientSecret, $tokenManager, $urlInfo);
63
    }
64
65
    public function validateWorkflowId($workflowId)
66
    {
67
        if (StringUtils::isEmpty($workflowId)) {
68
            throw new InvalidArgumentException('Workflow ID is not specified');
69
        }
70
71
        if (self::WORKFLOW_ID_LENGTH !== StringUtils::length($workflowId)) {
72
            throw new InvalidArgumentException('Workflow ID is invalid');
73
        }
74
    }
75
76
    public function validateJobId($jobId)
77
    {
78
        if (StringUtils::isEmpty($jobId)) {
79
            throw new InvalidArgumentException('Job ID is not specified');
80
        }
81
82
        if (self::JOB_ID_LENGTH !== StringUtils::length($jobId)) {
83
            throw new InvalidArgumentException('Job ID is invalid');
84
        }
85
    }
86
87
    public function getWorkflowInfoList($autoRenewAccessToken)
88
    {
89
        $accessToken = $this->getAccessToken();
90
91
        $url = $this->getWorkflowsEndPoint();
92
93
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
94
        $httpHeader .= 'Accept: application/json; charset=utf-8' . static::CRLF;
95
96
        $options = array(
97
            'http' => array(
98
                'ignore_errors' => true,
99
                'method' => 'GET',
100
                'header' => $httpHeader,
101
            ),
102
        );
103
104
        $context = stream_context_create($options);
105
106
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
107
        $http_response_header = $httpResponse['header'];
108
        $contents = $httpResponse['contents'];
109
110
        $headers = $this->mapHttpHeaders($http_response_header);
111
112
        if ($this->handleResponse($headers, $contents)) {
113
            $jsonResponse = $this->decodeJsonFromResponse($headers, $contents, true);
114
115
            $workflowList = array();
116
117
            if (!isset($jsonResponse['workflows'])) {
118
                return $workflowList; // return empty array
119
            }
120
121
            $workflows = $jsonResponse['workflows'];
122
123
            foreach ($workflows as $workflow) {
124
                $workflowId = $this->getValueFromArray($workflow, 'workflowID', '');
125
                $workflowName = $this->getValueFromArray($workflow, 'workflowName', '');
126
                $monitorFolder = $this->getValueFromArray($workflow, 'monitorFolder', false);
127
                $createdByUser = $this->getValueFromArray($workflow, 'createdByUser', false);
128
129
                $workflowInfo = new WorkflowInfo($workflowId, $workflowName, $monitorFolder, $createdByUser);
0 ignored issues
show
It seems like $createdByUser can also be of type false; however, parameter $createdByUser of Bcl\EasyPdfCloud\WorkflowInfo::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
                $workflowInfo = new WorkflowInfo($workflowId, $workflowName, $monitorFolder, /** @scrutinizer ignore-type */ $createdByUser);
Loading history...
It seems like $monitorFolder can also be of type false; however, parameter $monitorFolder of Bcl\EasyPdfCloud\WorkflowInfo::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

129
                $workflowInfo = new WorkflowInfo($workflowId, $workflowName, /** @scrutinizer ignore-type */ $monitorFolder, $createdByUser);
Loading history...
130
131
                array_push($workflowList, $workflowInfo);
132
            }
133
134
            return $workflowList;
135
        }
136
137
        if ($autoRenewAccessToken) {
138
            $this->getNewAccessToken();
139
140
            return $this->getWorkflowInfoList(false);
141
        }
142
143
        // This should raise an exception
144
        $this->checkWwwAuthenticateResponseHeader($headers);
145
146
        return null;
147
    }
148
149
    public function getWorkflowInfo($workflowId, $autoRenewAccessToken)
150
    {
151
        $accessToken = $this->getAccessToken();
152
153
        $url = $this->getWorkflowsEndPoint() . '/' . $workflowId;
154
155
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
156
        $httpHeader .= 'Accept: application/json; charset=utf-8' . static::CRLF;
157
158
        $options = array(
159
            'http' => array(
160
                'ignore_errors' => true,
161
                'method' => 'GET',
162
                'header' => $httpHeader,
163
            ),
164
        );
165
166
        $context = stream_context_create($options);
167
168
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
169
        $http_response_header = $httpResponse['header'];
170
        $contents = $httpResponse['contents'];
171
172
        $headers = $this->mapHttpHeaders($http_response_header);
173
174
        if ($this->handleResponse($headers, $contents)) {
175
            $jsonResponse = $this->decodeJsonFromResponse($headers, $contents, true);
176
177
            $monitorFolder = $this->getValueFromArray($jsonResponse, 'monitorFolder', false);
178
            $workflowName = $this->getValueFromArray($jsonResponse, 'workflowName', '');
179
180
            $workflowInfo = new WorkflowInfo($workflowId, $monitorFolder, $workflowName);
0 ignored issues
show
The call to Bcl\EasyPdfCloud\WorkflowInfo::__construct() has too few arguments starting with createdByUser. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

180
            $workflowInfo = /** @scrutinizer ignore-call */ new WorkflowInfo($workflowId, $monitorFolder, $workflowName);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
It seems like $monitorFolder can also be of type false; however, parameter $workflowName of Bcl\EasyPdfCloud\WorkflowInfo::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

180
            $workflowInfo = new WorkflowInfo($workflowId, /** @scrutinizer ignore-type */ $monitorFolder, $workflowName);
Loading history...
181
182
            return $workflowInfo;
183
        }
184
185
        if ($autoRenewAccessToken) {
186
            $this->getNewAccessToken();
187
188
            return $this->getWorkflowInfo($workflowId, false);
189
        }
190
191
        // This should raise an exception
192
        $this->checkWwwAuthenticateResponseHeader($headers);
193
194
        return null;
195
    }
196
197
    public function createNewJobWithFileContents($workflowId, $fileContents, $fileName, $start, $test, $autoRenewAccessToken)
198
    {
199
        $fileType = 'application/octet-stream';
200
201
        //$finfo = finfo_open(FILEINFO_MIME_TYPE);
202
        //$fileType = finfo_file($finfo, $filePath);
203
        //finfo_close($finfo);
204
205
        $accessToken = $this->getAccessToken();
206
207
        $url = $this->getWorkflowsEndPoint() . '/' . $workflowId . '/jobs';
208
        $url .= '?file=' . urlencode($fileName);
209
        $url .= '&start=' . ($start ? 'true' : 'false');
210
        $url .= '&test=' . ($test ? 'true' : 'false');
211
212
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
213
        $httpHeader .= 'Accept: application/json; charset=utf-8' . static::CRLF;
214
        $httpHeader .= 'Content-Length: ' . mb_strlen($fileContents, '8bit') . static::CRLF;
215
        $httpHeader .= 'Content-Type: ' . $fileType . static::CRLF;
216
217
        $options = array(
218
            'http' => array(
219
                'ignore_errors' => true,
220
                'method' => 'PUT',
221
                'header' => $httpHeader,
222
                'content' => $fileContents,
223
            ),
224
        );
225
226
        $context = stream_context_create($options);
227
228
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
229
        $http_response_header = $httpResponse['header'];
230
        $contents = $httpResponse['contents'];
231
232
        $headers = $this->mapHttpHeaders($http_response_header);
233
234
        if ($this->handleResponse($headers, $contents)) {
235
            $jsonResponse = $this->decodeJsonFromResponse($headers, $contents, true);
236
237
            $jobId = $this->getValueFromArray($jsonResponse, 'jobID', '');
238
239
            return $jobId;
240
        }
241
242
        if ($autoRenewAccessToken) {
243
            $this->getNewAccessToken();
244
245
            return $this->createNewJobWithFileContents($workflowId, $fileContents, $fileName, $start, $test, false);
246
        }
247
248
        // This should raise an exception
249
        $this->checkWwwAuthenticateResponseHeader($headers);
250
251
        return null;
252
    }
253
254
    public function uploadInputWithFileContents($jobId, $fileContents, $fileName, $autoRenewAccessToken)
255
    {
256
        $fileType = 'application/octet-stream';
257
        $accessToken = $this->getAccessToken();
258
        $url = $this->getJobsEndPoint() . '/' . $jobId . '/input/' . urlencode($fileName);
259
260
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
261
        $httpHeader .= 'Accept: application/json; charset=utf-8' . static::CRLF;
262
        $httpHeader .= 'Content-Length: ' . mb_strlen($fileContents, '8bit') . static::CRLF;
263
        $httpHeader .= 'Content-Type: ' . $fileType . static::CRLF;
264
265
        $options = array(
266
            'http' => array(
267
                'ignore_errors' => true,
268
                'method' => 'PUT',
269
                'header' => $httpHeader,
270
                'content' => $fileContents,
271
            ),
272
        );
273
274
        $context = stream_context_create($options);
275
276
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
277
        $http_response_header = $httpResponse['header'];
278
        $contents = $httpResponse['contents'];
279
280
        $headers = $this->mapHttpHeaders($http_response_header);
281
282
        if ($this->handleResponse($headers, $contents)) {
283
            $this->decodeJsonFromResponse($headers, $contents, false);
284
285
            return;
286
        }
287
288
        if ($autoRenewAccessToken) {
289
            $this->getNewAccessToken();
290
            $this->uploadInputWithFileContents($jobId, $fileContents, $fileName, false);
291
        }
292
293
        // This should raise an exception
294
        $this->checkWwwAuthenticateResponseHeader($headers);
295
    }
296
297
    public function getOutputInfoForFileName($jobId, $fileName, $autoRenewAccessToken)
298
    {
299
        $accessToken = $this->getAccessToken();
300
301
        $fileNameSpecified = StringUtils::length($fileName) > 0;
302
303
        $url = $this->getJobsEndPoint() . '/' . $jobId . '/output';
304
        $url .= ($fileNameSpecified ? '/' . urlencode($fileName) : '');
305
        $url .= '?type=metadata';
306
307
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
308
309
        $options = array(
310
            'http' => array(
311
                'ignore_errors' => true,
312
                'method' => 'GET',
313
                'header' => $httpHeader,
314
            ),
315
        );
316
317
        $context = stream_context_create($options);
318
319
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
320
        $http_response_header = $httpResponse['header'];
321
        $contents = $httpResponse['contents'];
322
323
        $headers = $this->mapHttpHeaders($http_response_header);
324
325
        if ($this->handleResponse($headers, $contents)) {
326
            $jsonResponse = $this->decodeJsonFromResponse($headers, $contents, true);
327
328
            $fileMetadata = $this->getFileInfoFromJsonResponse($jsonResponse);
329
330
            return $fileMetadata;
331
        }
332
333
        if ($autoRenewAccessToken) {
334
            $this->getNewAccessToken();
335
336
            return $this->getOutputInfoForFileName($jobId, $fileName, false);
337
        }
338
339
        // This should raise an exception
340
        $this->checkWwwAuthenticateResponseHeader($headers);
341
342
        return null;
343
    }
344
345
    public function downloadOutputForFileName($jobId, $fileName, $autoRenewAccessToken)
346
    {
347
        $accessToken = $this->getAccessToken();
348
349
        $fileNameSpecified = StringUtils::length($fileName) > 0;
350
351
        $url = $this->getJobsEndPoint() . '/' . $jobId . '/output';
352
        $url .= ($fileNameSpecified ? '/' . urlencode($fileName) : '');
353
        $url .= '?type=file';
354
355
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
356
357
        $options = array(
358
            'http' => array(
359
                'ignore_errors' => true,
360
                'method' => 'GET',
361
                'header' => $httpHeader,
362
            ),
363
        );
364
365
        $context = stream_context_create($options);
366
367
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
368
        $http_response_header = $httpResponse['header'];
369
        $contents = $httpResponse['contents'];
370
371
        $headers = $this->mapHttpHeaders($http_response_header);
372
373
        if ($this->handleResponse($headers, $contents)) {
374
            $outputFileName = $fileName;
375
376
            if (0 === StringUtils::length($outputFileName)) {
377
                if (isset($headers['content-disposition'])) {
378
                    $contentDisposition = $headers['content-disposition'];
379
                    $outputFileName = $this->getFileNameFromContentDisposisionHeader($contentDisposition);
380
381
                    if (0 === StringUtils::length($outputFileName)) {
382
                        $outputFileName = 'output';
383
                    }
384
                }
385
            }
386
387
            $fileBytes = mb_strlen($contents, '8bit');
388
389
            $contentType = 'application/octet-stream';
390
            if (isset($headers['content-type'])) {
391
                $contentType = $headers['content-type'];
392
            }
393
394
            $fileData = new FileData($outputFileName, $contents, $fileBytes, $contentType);
395
396
            return $fileData;
397
        }
398
399
        if ($autoRenewAccessToken) {
400
            $this->getNewAccessToken();
401
402
            return $this->downloadOutputForFileName($jobId, $fileName, false);
403
        }
404
405
        // This should raise an exception
406
        $this->checkWwwAuthenticateResponseHeader($headers);
407
408
        return null;
409
    }
410
411
    public function getJobInfo($jobId, $autoRenewAccessToken)
412
    {
413
        $accessToken = $this->getAccessToken();
414
415
        $url = $this->getJobsEndPoint() . '/' . $jobId;
416
417
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
418
        $httpHeader .= 'Accept: application/json; charset=utf-8' . static::CRLF;
419
420
        $options = array(
421
            'http' => array(
422
                'ignore_errors' => true,
423
                'method' => 'GET',
424
                'header' => $httpHeader,
425
            ),
426
        );
427
428
        $context = stream_context_create($options);
429
430
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
431
        $http_response_header = $httpResponse['header'];
432
        $contents = $httpResponse['contents'];
433
434
        $headers = $this->mapHttpHeaders($http_response_header);
435
436
        if ($this->handleResponse($headers, $contents)) {
437
            $jsonResponse = $this->decodeJsonFromResponse($headers, $contents, true);
438
439
            $jobInfo = $this->getJobInfoFromJsonResponse($jsonResponse);
440
441
            return $jobInfo;
442
        }
443
444
        if ($autoRenewAccessToken) {
445
            $this->getNewAccessToken();
446
447
            return $this->getJobInfo($jobId, false);
448
        }
449
450
        // This should raise an exception
451
        $this->checkWwwAuthenticateResponseHeader($headers);
452
453
        return null;
454
    }
455
456
    public function startOrStopJob($jobId, $start, $autoRenewAccessToken)
457
    {
458
        $accessToken = $this->getAccessToken();
459
460
        $postData = http_build_query(
461
            array(
462
                'operation' => ($start ? 'start' : 'stop'),
463
            )
464
        );
465
466
        $url = $this->getJobsEndPoint() . '/' . $jobId;
467
468
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
469
        $httpHeader .= 'Accept: application/json; charset=utf-8' . static::CRLF;
470
        $httpHeader .= 'Content-Length: ' . mb_strlen($postData, '8bit') . static::CRLF;
471
        $httpHeader .= 'Content-Type: application/x-www-form-urlencoded' . static::CRLF;
472
473
        $options = array(
474
            'http' => array(
475
                'ignore_errors' => true,
476
                'method' => 'POST',
477
                'header' => $httpHeader,
478
                'content' => $postData,
479
            ),
480
        );
481
482
        $context = stream_context_create($options);
483
484
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
485
        $http_response_header = $httpResponse['header'];
486
        $contents = $httpResponse['contents'];
487
488
        $headers = $this->mapHttpHeaders($http_response_header);
489
490
        if ($this->handleResponse($headers, $contents)) {
491
            $this->decodeJsonFromResponse($headers, $contents, false);
492
493
            return;
494
        }
495
496
        if ($autoRenewAccessToken) {
497
            $this->getNewAccessToken();
498
            $this->startOrStopJob($jobId, $start, false);
499
        }
500
501
        // This should raise an exception
502
        $this->checkWwwAuthenticateResponseHeader($headers);
503
    }
504
505
    public function deleteJob($jobId, $autoRenewAccessToken)
506
    {
507
        $accessToken = $this->getAccessToken();
508
509
        $url = $this->getJobsEndPoint() . '/' . $jobId;
510
511
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
512
        $httpHeader .= 'Accept: application/json; charset=utf-8' . static::CRLF;
513
514
        $options = array(
515
            'http' => array(
516
                'ignore_errors' => true,
517
                'method' => 'DELETE',
518
                'header' => $httpHeader,
519
            ),
520
        );
521
522
        $context = stream_context_create($options);
523
524
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
525
        $http_response_header = $httpResponse['header'];
526
        $contents = $httpResponse['contents'];
527
528
        $headers = $this->mapHttpHeaders($http_response_header);
529
530
        if ($this->handleResponse($headers, $contents)) {
531
            $this->decodeJsonFromResponse($headers, $contents, false);
532
533
            return;
534
        }
535
536
        if ($autoRenewAccessToken) {
537
            $this->getNewAccessToken();
538
            $this->deleteJob($jobId, false);
539
        }
540
541
        // This should raise an exception
542
        $this->checkWwwAuthenticateResponseHeader($headers);
543
    }
544
545
    public function waitForJobEvent($jobId, $autoRenewAccessToken)
546
    {
547
        $accessToken = $this->getAccessToken();
548
549
        $url = $this->getJobsEndPoint() . '/' . $jobId . '/event';
550
551
        $httpHeader = 'Authorization: Bearer ' . $accessToken . static::CRLF;
552
        $httpHeader .= 'Accept: application/json; charset=utf-8' . static::CRLF;
553
        $httpHeader .= 'Content-Length: 0' . static::CRLF;
554
        $httpHeader .= 'Content-Type: application/x-www-form-urlencoded' . static::CRLF;
555
556
        $options = array(
557
            'http' => array(
558
                'ignore_errors' => true,
559
                'method' => 'POST',
560
                'header' => $httpHeader,
561
            ),
562
        );
563
564
        $context = stream_context_create($options);
565
566
        $httpResponse = $this->getHttpResponseFromUrl($url, $context);
567
        $http_response_header = $httpResponse['header'];
568
        $contents = $httpResponse['contents'];
569
570
        $headers = $this->mapHttpHeaders($http_response_header);
571
572
        if ($this->handleResponse($headers, $contents)) {
573
            $statusCode = $this->getStatusCodeFromResponse($headers);
574
            if (self::HTTP_ACCEPTED === $statusCode) {
575
                // Job execution is not completed yet
576
                return new JobInfo($jobId, '', false, JobInfo::STATUS_WAITING, 0, null);
577
            }
578
579
            $jsonResponse = $this->decodeJsonFromResponse($headers, $contents, true);
580
581
            $jobInfo = $this->getJobInfoFromJsonResponse($jsonResponse);
582
583
            return $jobInfo;
584
        }
585
586
        if ($autoRenewAccessToken) {
587
            $this->getNewAccessToken();
588
589
            return $this->waitForJobEvent($jobId, false);
590
        }
591
592
        // This should raise an exception
593
        $this->checkWwwAuthenticateResponseHeader($headers);
594
595
        return null;
596
    }
597
598
    public static function getJobInfoStatusFromString($statusString)
599
    {
600
        if (StringUtils::length($statusString) > 0) {
601
            if ('waiting' === $statusString) {
602
                return JobInfo::STATUS_WAITING;
603
            } elseif ('completed' === $statusString) {
604
                return JobInfo::STATUS_COMPLETED;
605
            } elseif ('failed' === $statusString) {
606
                return JobInfo::STATUS_FAILED;
607
            } elseif ('cancelled' === $statusString) {
608
                return JobInfo::STATUS_CANCELLED;
609
            }
610
        }
611
612
        return JobInfo::STATUS_UNKNOWN;
613
    }
614
615
    private function getWorkflowsEndPoint()
616
    {
617
        return $this->urlInfo->getApiBaseUrl() . '/workflows';
618
    }
619
620
    private function getJobsEndPoint()
621
    {
622
        return $this->urlInfo->getApiBaseUrl() . '/jobs';
623
    }
624
625
    private function getFileInfoFromJsonResponse($jsonResponse)
626
    {
627
        $isFolder = $this->getValueFromArray($jsonResponse, 'isFolder', false);
628
        $name = $this->getValueFromArray($jsonResponse, 'name', '');
629
        $bytes = $this->getValueFromArray($jsonResponse, 'bytes', 0);
630
        $mime = $this->getValueFromArray($jsonResponse, 'mime', 'application/octet-stream');
631
        $modifiedDate = $this->getValueFromArray($jsonResponse, 'modifiedDate', '');
632
        $contents = null;
633
634
        if ($isFolder) {
635
            $contents = array();
636
637
            if (isset($jsonResponse['contents'])) {
638
                $contentsJson = $jsonResponse['contents'];
639
640
                foreach ($contentsJson as $contentJson) {
641
                    $isFolderInner = $this->getValueFromArray($contentJson, 'isFolder', false);
642
                    $nameInner = $this->getValueFromArray($contentJson, 'name', '');
643
                    $bytesInner = $this->getValueFromArray($contentJson, 'bytes', 0);
644
                    $mimeInner = $this->getValueFromArray($contentJson, 'mime', 'application/octet-stream');
645
                    $modifiedDateInner = $this->getValueFromArray($contentJson, 'modifiedDate', '');
646
647
                    $fileMetadataInner = new FileMetadata(
648
                        $isFolderInner,
649
                        $nameInner,
650
                        $bytesInner,
651
                        $mimeInner,
652
                        $modifiedDateInner,
653
                        null
654
                    );
655
656
                    array_push($contents, $fileMetadataInner);
657
                }
658
            }
659
        }
660
661
        $fileMetadata = new FileMetadata($isFolder, $name, $bytes, $mime, $modifiedDate, $contents);
662
663
        return $fileMetadata;
664
    }
665
666
    private function getJobInfoFromJsonResponse($jsonResponse)
667
    {
668
        $jobId = $this->getValueFromArray($jsonResponse, 'jobID', '');
669
        $workflowId = $this->getValueFromArray($jsonResponse, 'workflowID', '');
670
        $finished = $this->getValueFromArray($jsonResponse, 'finished', false);
671
        $progress = $this->getValueFromArray($jsonResponse, 'progress', 0);
672
673
        $statusString = $this->getValueFromArray($jsonResponse, 'status', 'unknown');
674
        $status = $this->getJobInfoStatusFromString($statusString);
675
676
        $apiCredits = null;
677
        $ocrCredits = null;
678
        $detail = null;
679
680
        if (isset($jsonResponse['detail'])) {
681
            $detailJson = $jsonResponse['detail'];
682
            $errors = array();
683
684
            if (isset($detailJson['apiCredits'])) {
685
                $apiCreditsJson = $detailJson['apiCredits'];
686
687
                $creditsRemaining = $this->getValueFromArray($apiCreditsJson, 'creditsRemaining', 0);
688
                $notEnoughCredits = $this->getValueFromArray($apiCreditsJson, 'notEnoughCredits', false);
689
690
                $apiCredits = new CreditsInfo($creditsRemaining, $notEnoughCredits);
691
            }
692
693
            if (isset($detailJson['ocrCredits'])) {
694
                $ocrCreditsJson = $detailJson['ocrCredits'];
695
696
                $creditsRemaining = $this->getValueFromArray($ocrCreditsJson, 'creditsRemaining', 0);
697
                $notEnoughCredits = $this->getValueFromArray($ocrCreditsJson, 'notEnoughCredits', false);
698
699
                $ocrCredits = new CreditsInfo($creditsRemaining, $notEnoughCredits);
700
            }
701
702
            if (isset($detailJson['errors'])) {
703
                $errorsJson = $detailJson['errors'];
704
                $errors = array();
705
706
                foreach ($errorsJson as $errorJson) {
707
                    $taskName = $this->getValueFromArray($errorJson, 'taskName', '');
708
                    $fileName = $this->getValueFromArray($errorJson, 'fileName', '');
709
                    $message = $this->getValueFromArray($errorJson, 'message', '');
710
                    $detail = $this->getValueFromArray($errorJson, 'detail', null);
711
                    $extraDetail = $this->getValueFromArray($errorJson, 'extraDetail', null);
712
713
                    $error = new JobError($taskName, $fileName, $message, $detail, $extraDetail);
714
715
                    array_push($errors, $error);
716
                }
717
            }
718
719
            $detail = new JobInfoDetail($apiCredits, $ocrCredits, $errors);
720
        }
721
722
        return new JobInfo($jobId, $workflowId, $finished, $status, $progress, $detail);
723
    }
724
}
725