BaseRestOperation.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Service\Rest\Operation;
  4. use App\Service\Rest\ApiRequestInterface;
  5. use JetBrains\PhpStorm\Pure;
  6. use RuntimeException;
  7. use Symfony\Component\HttpClient\Exception\InvalidArgumentException;
  8. use Symfony\Component\HttpKernel\Exception\HttpException;
  9. use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
  10. use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
  11. use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
  12. use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
  13. use Symfony\Contracts\HttpClient\ResponseInterface;
  14. /**
  15. * A single operation, corresponding to a single request
  16. * to a REST API (Json only)
  17. */
  18. abstract class BaseRestOperation
  19. {
  20. public const STATUS_READY = 0;
  21. public const STATUS_PENDING = 1;
  22. public const STATUS_DONE = 2;
  23. public const STATUS_ERROR = 3;
  24. protected int $status = self::STATUS_READY;
  25. protected string $errorMessage = "";
  26. /**
  27. * @param string $label
  28. * @param string $method
  29. * @param string $path
  30. * @param array<mixed> $initialData
  31. * @param array<mixed> $parameters
  32. * @param array<mixed> $options
  33. */
  34. public function __construct(
  35. protected string $label,
  36. protected string $method,
  37. protected string $path,
  38. protected array $initialData = [],
  39. protected array $parameters = [],
  40. protected array $options = []
  41. ) {}
  42. /**
  43. * Execute the operation and update its status according to the result
  44. *
  45. * @param ApiRequestInterface $apiService
  46. * @return ResponseInterface
  47. */
  48. public function execute(ApiRequestInterface $apiService): ResponseInterface
  49. {
  50. $this->status = self::STATUS_PENDING;
  51. try {
  52. $response = $apiService->request($this->method, $this->path, $this->parameters, $this->options);
  53. if ($response->getStatusCode() === 200) {
  54. $this->status = self::STATUS_DONE;
  55. } else {
  56. $this->status = self::STATUS_ERROR;
  57. $this->errorMessage = 'Error ' . $response->getStatusCode() . ' : ' . $response->getContent();
  58. throw new HttpException($response->getStatusCode(), $response->getContent());
  59. }
  60. return $response;
  61. } catch (
  62. HttpException |
  63. ClientExceptionInterface |
  64. TransportExceptionInterface |
  65. RedirectionExceptionInterface |
  66. ServerExceptionInterface |
  67. InvalidArgumentException
  68. $e) {
  69. $this->status = self::STATUS_ERROR;
  70. $this->errorMessage = '' . $e;
  71. throw new RuntimeException($e->getMessage());
  72. }
  73. }
  74. /**
  75. * @return string
  76. */
  77. public function getLabel(): string
  78. {
  79. return $this->label;
  80. }
  81. /**
  82. * @return int
  83. */
  84. public function getStatus(): int
  85. {
  86. return $this->status;
  87. }
  88. /**
  89. * @return string
  90. */
  91. public function getErrorMessage(): string
  92. {
  93. return $this->errorMessage;
  94. }
  95. /**
  96. * @return string
  97. */
  98. public function getMethod(): string
  99. {
  100. return $this->method;
  101. }
  102. /**
  103. * @return string
  104. */
  105. public function getPath(): string
  106. {
  107. return $this->path;
  108. }
  109. /**
  110. * @return array<mixed>
  111. */
  112. public function getInitialData(): array
  113. {
  114. return $this->initialData;
  115. }
  116. /**
  117. * @return array<mixed>
  118. */
  119. public function getParameters(): array
  120. {
  121. return $this->parameters;
  122. }
  123. /**
  124. * @return array<mixed>
  125. */
  126. public function getOptions(): array
  127. {
  128. return $this->options;
  129. }
  130. /**
  131. * Return an array of messages describing the change that this operation will bring
  132. *
  133. * @return list<string>
  134. * @throws \Exception
  135. */
  136. abstract public function getChangeLog(): array;
  137. #[Pure]
  138. public function __toString(): string {
  139. return $this->getMethod() . " " . $this->getPath();
  140. }
  141. /**
  142. * @param array<mixed> $initialData
  143. * @param array<mixed> $newData
  144. * @param string $prefix
  145. * @return array<mixed>
  146. */
  147. protected static function getRecursiveChangeLog(array $initialData, array $newData, string $prefix = ""): array {
  148. $messages = [];
  149. foreach ($newData as $field => $newValue) {
  150. $fieldLabel = $prefix ? $prefix . '.' . $field : $field;
  151. if (is_array($newValue)) {
  152. array_push(
  153. $messages,
  154. ...self::getRecursiveChangeLog(
  155. $initialData[$field] ?? [],
  156. $newValue,
  157. $fieldLabel)
  158. );
  159. } else if (!array_key_exists($field, $initialData)) {
  160. $messages[] = $fieldLabel . ' : (new) => `' . $newValue . '`';
  161. } else if ($newValue !== $initialData[$field]) {
  162. $messages[] = $fieldLabel . ' : `' . $initialData[$field] . '` => `' . $newValue . '`';
  163. }
  164. }
  165. return $messages;
  166. }
  167. }