Browse Source

api request services refactoring and minor fixes of dolibarr sync

Olivier Massot 3 years ago
parent
commit
722d19aa85

+ 1 - 1
doc/logging.md

@@ -66,7 +66,7 @@ Les canaux natifs ou custom sont par défaut gérés par un handler de type rota
 dans `var/log/{env}.main.log`
 dans `var/log/{env}.main.log`
 
 
 Certains canaux sont gérés par un handler particulier et logués dans des fichiers spécifiques. Par ex, 
 Certains canaux sont gérés par un handler particulier et logués dans des fichiers spécifiques. Par ex, 
-le canal `doctrine` est redirigé vers `var/log/{env}.doctrine.log`
+le canal `security` est redirigé vers `var/log/{env}.auth.log`
 
 
 #### critical
 #### critical
 
 

+ 4 - 5
src/Commands/DolibarrSyncCommand.php

@@ -2,14 +2,13 @@
 
 
 namespace App\Commands;
 namespace App\Commands;
 
 
-use App\Service\Dolibarr\DolibarrSync\DolibarrSyncService;
+use App\Service\Dolibarr\DolibarrSyncService;
 use Symfony\Component\Console\Attribute\AsCommand;
 use Symfony\Component\Console\Attribute\AsCommand;
 use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Command\LockableTrait;
 use Symfony\Component\Console\Command\LockableTrait;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Console\Question\Question;
 
 
 #[AsCommand(
 #[AsCommand(
     name: 'opentalent:dolibarr-sync',
     name: 'opentalent:dolibarr-sync',
@@ -40,7 +39,7 @@ class DolibarrSyncCommand extends Command
         );
         );
     }
     }
 
 
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
     {
         if (!$this->lock()) {
         if (!$this->lock()) {
             $output->writeln('The command is already running in another process.');
             $output->writeln('The command is already running in another process.');
@@ -68,8 +67,8 @@ class DolibarrSyncCommand extends Command
         } else {
         } else {
             $t0 = microtime(true);
             $t0 = microtime(true);
             $output->writeln("Executing...");
             $output->writeln("Executing...");
-//            $operations = $this->dolibarrSyncService->execute($operations);
-//            $output->writeln(count($operations) . " operations successfully executed");
+            $operations = $this->dolibarrSyncService->execute($operations);
+            $output->writeln(count($operations) . " operations successfully executed");
 
 
             $t1 = microtime(true);
             $t1 = microtime(true);
             $output->writeln("Execution lasted " . ($t1 - $t0) . " sec.");
             $output->writeln("Execution lasted " . ($t1 - $t0) . " sec.");

+ 1 - 0
src/Enum/Access/FunctionEnum.php

@@ -9,6 +9,7 @@ use MyCLabs\Enum\Enum;
  * Activities functions.
  * Activities functions.
  * @method static STUDENT()
  * @method static STUDENT()
  * @method static ADHERENT()
  * @method static ADHERENT()
+ * @method static OTHER()
  */
  */
 class FunctionEnum extends Enum
 class FunctionEnum extends Enum
 {
 {

+ 3 - 3
src/Service/Dolibarr/DolibarrApiService.php

@@ -3,7 +3,7 @@ declare(strict_types=1);
 
 
 namespace App\Service\Dolibarr;
 namespace App\Service\Dolibarr;
 
 
-use App\Service\ApiRequestService;
+use App\Service\Rest\ApiRequestService;
 use JetBrains\PhpStorm\Pure;
 use JetBrains\PhpStorm\Pure;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
@@ -44,7 +44,7 @@ class DolibarrApiService extends ApiRequestService
                 "contracts",
                 "contracts",
                 ["limit" => "1", "sqlfilters" => "statut=1", "thirdparty_ids" => $socId]
                 ["limit" => "1", "sqlfilters" => "statut=1", "thirdparty_ids" => $socId]
             )[0];
             )[0];
-        } catch (HttpException) {
+        } catch (HttpException $e) {
             if ($e->getStatusCode() == 404) {
             if ($e->getStatusCode() == 404) {
                 // /!\ The dolibarr API will return a 404 error if no results are found...
                 // /!\ The dolibarr API will return a 404 error if no results are found...
                 return [];
                 return [];
@@ -64,7 +64,7 @@ class DolibarrApiService extends ApiRequestService
             return $this->getJsonContent(
             return $this->getJsonContent(
                 "invoices",
                 "invoices",
                 ["sortfield" => "datef", "sortorder" => "DESC", "limit" => 5, "sqlfilters" => "fk_soc=" . $socId]);
                 ["sortfield" => "datef", "sortorder" => "DESC", "limit" => 5, "sqlfilters" => "fk_soc=" . $socId]);
-        } catch (HttpException) {
+        } catch (HttpException $e) {
             if ($e->getStatusCode() == 404) {
             if ($e->getStatusCode() == 404) {
                 // /!\ The dolibarr API will return a 404 error if no results are found...
                 // /!\ The dolibarr API will return a 404 error if no results are found...
                 return [];
                 return [];

+ 17 - 18
src/Service/Dolibarr/DolibarrSyncService.php

@@ -1,7 +1,7 @@
 <?php
 <?php
 declare(strict_types=1);
 declare(strict_types=1);
 
 
-namespace App\Service\Dolibarr\DolibarrSync;
+namespace App\Service\Dolibarr;
 
 
 use App\Entity\Organization\Organization;
 use App\Entity\Organization\Organization;
 use App\Entity\Person\Person;
 use App\Entity\Person\Person;
@@ -17,10 +17,9 @@ use App\Repository\Access\FunctionTypeRepository;
 use App\Repository\Core\ContactPointRepository;
 use App\Repository\Core\ContactPointRepository;
 use App\Repository\Organization\OrganizationRepository;
 use App\Repository\Organization\OrganizationRepository;
 use App\Service\Core\AddressPostalUtils;
 use App\Service\Core\AddressPostalUtils;
-use App\Service\Dolibarr\DolibarrApiService;
-use App\Service\Dolibarr\DolibarrSync\SyncOperation\DolibarrCreateOperation;
-use App\Service\Dolibarr\DolibarrSync\SyncOperation\DolibarrSyncOperation;
-use App\Service\Dolibarr\DolibarrSync\SyncOperation\DolibarrUpdateOperation;
+use App\Service\Rest\Operation\BaseRestOperation;
+use App\Service\Rest\Operation\CreateOperation;
+use App\Service\Rest\Operation\UpdateOperation;
 use Exception;
 use Exception;
 use HttpException;
 use HttpException;
 use libphonenumber\PhoneNumber;
 use libphonenumber\PhoneNumber;
@@ -55,7 +54,7 @@ class DolibarrSyncService
      *
      *
      * Returns an array of DolibarrSyncOperations
      * Returns an array of DolibarrSyncOperations
      *
      *
-     * @return array<DolibarrSyncOperation>
+     * @return array<BaseRestOperation>
      * @throws Exception
      * @throws Exception
      */
      */
     public function scan(): array {
     public function scan(): array {
@@ -154,7 +153,7 @@ class DolibarrSyncService
 
 
             // Add an update operation if some data has to be updated
             // Add an update operation if some data has to be updated
             if (!empty($newSocietyData)) {
             if (!empty($newSocietyData)) {
-                $operations[] = new DolibarrUpdateOperation(
+                $operations[] = new UpdateOperation(
                     'Update society : ' . $organization->getName() . ' (' . $organization->getId() . ')',
                     'Update society : ' . $organization->getName() . ' (' . $organization->getId() . ')',
                     'thirdparties',
                     'thirdparties',
                     $dolibarrSociety,
                     $dolibarrSociety,
@@ -211,7 +210,7 @@ class DolibarrSyncService
                         ];
                         ];
 
 
                         if ($dolibarrContact === null) {
                         if ($dolibarrContact === null) {
-                            $operations[] = new DolibarrCreateOperation(
+                            $operations[] = new CreateOperation(
                                 'New contact: ' . $person->getName() . ' ' . $person->getGivenName() . ' (' . $person->getId() . ')',
                                 'New contact: ' . $person->getName() . ' ' . $person->getGivenName() . ' (' . $person->getId() . ')',
                                 'contacts',
                                 'contacts',
                                 $newContactData
                                 $newContactData
@@ -226,7 +225,7 @@ class DolibarrSyncService
 
 
                             // add an update operation if some data has to be updated
                             // add an update operation if some data has to be updated
                             if (!empty($newContactData)) {
                             if (!empty($newContactData)) {
-                                $operations[] = new DolibarrUpdateOperation(
+                                $operations[] = new UpdateOperation(
                                     'Update contact: ' . $person->getName() . ' ' . $person->getGivenName() . ' (' . $person->getId() . ')' .
                                     'Update contact: ' . $person->getName() . ' ' . $person->getGivenName() . ' (' . $person->getId() . ')' .
                                     ' in ' . $organization->getName() . ' (' . $organization->getId() . ')',
                                     ' in ' . $organization->getName() . ' (' . $organization->getId() . ')',
                                     'contacts',
                                     'contacts',
@@ -249,7 +248,7 @@ class DolibarrSyncService
                 }
                 }
                 if (!in_array($personId, $contactsProcessed)) {
                 if (!in_array($personId, $contactsProcessed)) {
                     // Ce personId n'existe plus dans les membres Opentalent de cette société, on delete
                     // Ce personId n'existe plus dans les membres Opentalent de cette société, on delete
-                    $operations[] = new DolibarrUpdateOperation(
+                    $operations[] = new UpdateOperation(
                         'Disable contact: ' . $contactData['lastname'] . ' ' . $contactData['firstname'] . ' (' . $personId . ')' .
                         'Disable contact: ' . $contactData['lastname'] . ' ' . $contactData['firstname'] . ' (' . $personId . ')' .
                         ' from  ' . $organization->getName() . ' (' . $organization->getId() . ')',
                         ' from  ' . $organization->getName() . ' (' . $organization->getId() . ')',
                         'contacts',
                         'contacts',
@@ -277,8 +276,8 @@ class DolibarrSyncService
      *
      *
      * Returns an array of DolibarrSyncOperations
      * Returns an array of DolibarrSyncOperations
      *
      *
-     * @param array<DolibarrSyncOperation> $operations
-     * @return array<DolibarrSyncOperation>
+     * @param array<BaseRestOperation> $operations
+     * @return array<BaseRestOperation>
      * @throws Exception
      * @throws Exception
      */
      */
     public function execute(array $operations): array
     public function execute(array $operations): array
@@ -288,21 +287,21 @@ class DolibarrSyncService
         $done = 0; $errors = 0; $unknown = 0;
         $done = 0; $errors = 0; $unknown = 0;
 
 
         foreach ($operations as $operation) {
         foreach ($operations as $operation) {
-            if ($operation->getStatus() !== DolibarrSyncOperation::STATUS_READY) {
+            if ($operation->getStatus() !== BaseRestOperation::STATUS_READY) {
                 // operation has already been treated
                 // operation has already been treated
                 $this->logger->warning('Tried to execute an operation that was not marked as ready : ' . $operation);
                 $this->logger->warning('Tried to execute an operation that was not marked as ready : ' . $operation);
                 continue;
                 continue;
             }
             }
 
 
-            $operation->execute(
-                $this->dolibarrApiService
+            $operation = $this->dolibarrApiService->execute(
+                $operation
             );
             );
 
 
-            if ($operation->getStatus() === DolibarrSyncOperation::STATUS_ERROR) {
+            if ($operation->getStatus() === BaseRestOperation::STATUS_ERROR) {
                 $this->logger->error('Error while executing operation : ' . $operation);
                 $this->logger->error('Error while executing operation : ' . $operation);
                 $this->logger->error($operation->getErrorMessage());
                 $this->logger->error($operation->getErrorMessage());
                 $errors++;
                 $errors++;
-            } elseif ($operation->getStatus() === DolibarrSyncOperation::STATUS_DONE) {
+            } elseif ($operation->getStatus() === BaseRestOperation::STATUS_DONE) {
                 $done++;
                 $done++;
             } else {
             } else {
                 $unknown++;
                 $unknown++;
@@ -321,8 +320,8 @@ class DolibarrSyncService
     /**
     /**
      * Scan and execute the sync process
      * Scan and execute the sync process
      *
      *
+     * @return array<BaseRestOperation>
      * @throws HttpException
      * @throws HttpException
-     * @return array<DolibarrSyncOperation>
      * @throws Exception
      * @throws Exception
      */
      */
     public function run(): array
     public function run(): array

+ 1 - 1
src/Service/Mobyt/MobytService.php

@@ -3,7 +3,7 @@ declare(strict_types=1);
 
 
 namespace App\Service\Mobyt;
 namespace App\Service\Mobyt;
 
 
-use App\Service\ApiRequestService;
+use App\Service\Rest\ApiRequestService;
 use JetBrains\PhpStorm\Pure;
 use JetBrains\PhpStorm\Pure;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
 
 

+ 99 - 1
src/Service/Rest/ApiRequestInterface.php

@@ -1,8 +1,106 @@
 <?php
 <?php
+declare(strict_types = 1);
 
 
 namespace App\Service\Rest;
 namespace App\Service\Rest;
 
 
-class ApiRequestInterface
+use App\Service\Rest\Operation\BaseRestOperation;
+use Symfony\Component\HttpKernel\Exception\HttpException;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+
+/**
+ * Interface for services sending requests to an external REST API
+ */
+interface ApiRequestInterface
 {
 {
+    /**
+     * Sends a GET request and returns the response's body decoded as json
+     * @param string $path
+     * @param array $parameters
+     * @param array $options
+     * @return array
+     * @throws HttpException
+     */
+    function getJsonContent(string $path, array $parameters = [], array $options = []): array;
+
+    /**
+     * Sends a GET request and returns the response's body
+     *
+     * @param string $path
+     * @param array $parameters
+     * @param array $options
+     * @return string
+     * @throws HttpException
+     */
+    function getContent(string $path, array $parameters = [], array $options = []): string;
+
+    /**
+     * Sends a GET request and returns the response
+     *
+     * @param string $path
+     * @param array $parameters
+     * @param array $options
+     * @return ResponseInterface
+     * @throws HttpException
+     */
+    function get(string $path, array $parameters = [], array $options = []): ResponseInterface;
+
+    /**
+     * Sends a POST request and returns the response
+     *
+     * @param string $path
+     * @param array $parameters
+     * @param array $options
+     * @return ResponseInterface
+     * @throws HttpException
+     */
+    function post(string $path, array $parameters = [], array $options = []): ResponseInterface;
+
+    /**
+     * Sends a PUT request and returns the response
+     *
+     * @param string $path
+     * @param array $parameters
+     * @param array $options
+     * @return ResponseInterface
+     * @throws HttpException
+     */
+    function put(string $path, array $parameters = [], array $options = []): ResponseInterface;
+
+    /**
+     * Sends a DELETE request and returns the response
+     *
+     * @param string $path
+     * @param array $parameters
+     * @param array $options
+     * @return ResponseInterface
+     * @throws HttpException
+     */
+    function delete(string $path, array $parameters = [], array $options = []): ResponseInterface;
+
+    /**
+     * Send an HTTP request to the Dolibarr API,
+     * and return the decoded content of the response's body
+     *
+     * @param string $method
+     * @param string $url
+     * @param array $parameters
+     * @param array $options
+     * @return ResponseInterface
+     * @throws HttpException
+     */
+    function request(
+        string $method,
+        string $url,
+        array  $parameters = [],
+        array  $options = []
+    ): ResponseInterface;
+
+    /**
+     * Executes the given Rest Operation, then returns it
+     *
+     * @param BaseRestOperation $operation
+     * @return BaseRestOperation
+     */
+    function execute(BaseRestOperation $operation): BaseRestOperation;
 
 
 }
 }

+ 17 - 3
src/Service/Rest/ApiRequestService.php

@@ -1,8 +1,9 @@
 <?php
 <?php
 declare(strict_types=1);
 declare(strict_types=1);
 
 
-namespace App\Service;
+namespace App\Service\Rest;
 
 
+use App\Service\Rest\Operation\BaseRestOperation;
 use App\Service\Utils\UrlBuilder;
 use App\Service\Utils\UrlBuilder;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
@@ -16,7 +17,7 @@ use Symfony\Contracts\HttpClient\ResponseInterface;
 /**
 /**
  * Base class for services sending requests to an external API
  * Base class for services sending requests to an external API
  */
  */
-class ApiRequestService
+class ApiRequestService implements ApiRequestInterface
 {
 {
     function __construct(
     function __construct(
         protected HttpClientInterface $client
         protected HttpClientInterface $client
@@ -60,7 +61,7 @@ class ApiRequestService
      * @return ResponseInterface
      * @return ResponseInterface
      * @throws HttpException
      * @throws HttpException
      */
      */
-    protected function get(string $path, array $parameters = [], array $options = []): ResponseInterface {
+    public function get(string $path, array $parameters = [], array $options = []): ResponseInterface {
         return $this->request('GET', $path, $parameters, $options);
         return $this->request('GET', $path, $parameters, $options);
     }
     }
 
 
@@ -132,4 +133,17 @@ class ApiRequestService
             throw new HttpException(500, 'Request error : ', $e);
             throw new HttpException(500, 'Request error : ', $e);
         }
         }
     }
     }
+
+    /**
+     * Executes the given Rest Operation, then returns it
+     *
+     * @param BaseRestOperation $operation
+     * @return BaseRestOperation
+     */
+    public function execute(BaseRestOperation $operation): BaseRestOperation
+    {
+        $operation->setApiRequestService($this);
+        $operation->execute();
+        return $operation;
+    }
 }
 }

+ 4 - 3
src/Service/Rest/Operation/BaseRestOperation.php

@@ -1,8 +1,9 @@
 <?php
 <?php
 declare(strict_types=1);
 declare(strict_types=1);
 
 
-namespace App\Service\Rest\SyncOperation;
+namespace App\Service\Rest\Operation;
 
 
+use App\Service\Rest\ApiRequestInterface;
 use App\Service\Rest\ApiRequestService;
 use App\Service\Rest\ApiRequestService;
 use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
 use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
 use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
 use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
@@ -11,7 +12,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
 use Symfony\Contracts\Service\Attribute\Required;
 use Symfony\Contracts\Service\Attribute\Required;
 
 
 /**
 /**
- * Single synchronization operation, corresponding to a single request
+ * A single operation, corresponding to a single request
  * to a REST API
  * to a REST API
  */
  */
 abstract class BaseRestOperation
 abstract class BaseRestOperation
@@ -21,7 +22,7 @@ abstract class BaseRestOperation
     const STATUS_DONE = 2;
     const STATUS_DONE = 2;
     const STATUS_ERROR = 3;
     const STATUS_ERROR = 3;
 
 
-    protected ApiRequestService $apiService;
+    protected ApiRequestInterface $apiService;
     protected int $status = self::STATUS_READY;
     protected int $status = self::STATUS_READY;
     protected string $label;
     protected string $label;
     protected string $method;
     protected string $method;

+ 4 - 1
src/Service/Rest/Operation/CreateOperation.php

@@ -1,10 +1,13 @@
 <?php
 <?php
 declare(strict_types=1);
 declare(strict_types=1);
 
 
-namespace App\Service\Rest\SyncOperation;
+namespace App\Service\Rest\Operation;
 
 
 use JetBrains\PhpStorm\Pure;
 use JetBrains\PhpStorm\Pure;
 
 
+/**
+ * A single create operation (a POST request)
+ */
 class CreateOperation extends BaseRestOperation
 class CreateOperation extends BaseRestOperation
 {
 {
     protected string $entity;
     protected string $entity;

+ 4 - 1
src/Service/Rest/Operation/DeleteOperation.php

@@ -1,10 +1,13 @@
 <?php
 <?php
 declare(strict_types=1);
 declare(strict_types=1);
 
 
-namespace App\Service\Rest\SyncOperation;
+namespace App\Service\Rest\Operation;
 
 
 use JetBrains\PhpStorm\Pure;
 use JetBrains\PhpStorm\Pure;
 
 
+/**
+ * A single delete operation (a DELETE request)
+ */
 class DeleteOperation extends BaseRestOperation
 class DeleteOperation extends BaseRestOperation
 {
 {
     protected string $entity;
     protected string $entity;

+ 4 - 1
src/Service/Rest/Operation/UpdateOperation.php

@@ -1,10 +1,13 @@
 <?php
 <?php
 declare(strict_types=1);
 declare(strict_types=1);
 
 
-namespace App\Service\Rest\SyncOperation;
+namespace App\Service\Rest\Operation;
 
 
 use JetBrains\PhpStorm\Pure;
 use JetBrains\PhpStorm\Pure;
 
 
+/**
+ * A single update operation (a PUT request)
+ */
 class UpdateOperation extends BaseRestOperation
 class UpdateOperation extends BaseRestOperation
 {
 {
     protected string $entity;
     protected string $entity;