Total Complexity | 71 |
Total Lines | 688 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like RestApiImpl 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.
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 RestApiImpl, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
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) |
||
84 | } |
||
85 | } |
||
86 | |||
87 | public function getWorkflowInfoList($autoRenewAccessToken) |
||
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); |
||
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() |
||
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); |
||
664 | } |
||
665 | |||
666 | private function getJobInfoFromJsonResponse($jsonResponse) |
||
723 | } |
||
724 | } |
||
725 |