src/V4/DataPersister/AbstractWithoutRequestDataPersister.php line 198

Open in your IDE?
  1. <?php
  2. namespace App\V4\DataPersister;
  3. use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
  4. use App\Model\CustomerFile\CustomerFile;
  5. use App\Security\User;
  6. use App\Service\ApiWebService;
  7. use App\Service\Cache\CacheManager;
  8. use App\Service\DataWrapper\BasicDataWrapper;
  9. use App\Service\PreSendSerializer;
  10. use App\Service\Provider\ApiProviderInterface;
  11. use App\Service\TokenDataWrapper\TokenDataWrapper;
  12. use App\V4\Event\PostPersistEvent;
  13. use App\V4\Event\PostRemoveEvent;
  14. use App\V4\Logger\SentryLogger;
  15. use App\V4\Messenger\Message\ResynchronizeBadgesRequest;
  16. use App\V4\Model\CustomerFileAwareInterface;
  17. use Doctrine\Common\Annotations\AnnotationException;
  18. use Psr\Cache\InvalidArgumentException;
  19. use RuntimeException;
  20. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use Symfony\Component\Messenger\MessageBusInterface;
  24. use Symfony\Component\Security\Core\Security;
  25. use Symfony\Component\Serializer\Exception\ExceptionInterface;
  26. use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
  27. use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
  28. use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
  29. use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
  30. use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
  31. use Throwable;
  32. abstract class AbstractWithoutRequestDataPersister implements ContextAwareDataPersisterInterface
  33. {
  34.     protected const ENTITY null;
  35.     protected const ENDPOINT '/';
  36.     protected const POST_SERIALIZATION_GROUPS = [];
  37.     protected const PUT_SERIALIZATION_GROUPS = [];
  38.     public const CONTEXT_IS_V4 'is_v4';
  39.     public const CONTEXT_NOT_POST_PERSIST_EVENT 'not_post_persist_event';
  40.     /**
  41.      * @var ApiWebService
  42.      */
  43.     private $apiWebService;
  44.     /**
  45.      * @var ApiProviderInterface
  46.      */
  47.     private $apiProvider;
  48.     /**
  49.      * @var TokenDataWrapper
  50.      */
  51.     private $tokenDataWrapper;
  52.     /**
  53.      * @var BasicDataWrapper
  54.      */
  55.     private $basicDataWrapper;
  56.     /**
  57.      * @var PreSendSerializer
  58.      */
  59.     private $serializer;
  60.     /**
  61.      * @var CacheManager
  62.      */
  63.     private $cacheManager;
  64.     /**
  65.      * @var MessageBusInterface
  66.      */
  67.     private $bus;
  68.     /**
  69.      * @var Security
  70.      */
  71.     private $security;
  72.     /**
  73.      * @var EventDispatcherInterface
  74.      */
  75.     private $eventDispatcher;
  76.     /**
  77.      * @var SentryLogger
  78.      */
  79.     private $sentryLogger;
  80.     /**
  81.      * @param ApiWebService            $apiWebService
  82.      * @param ApiProviderInterface     $apiProvider
  83.      * @param TokenDataWrapper         $tokenDataWrapper
  84.      * @param BasicDataWrapper         $basicDataWrapper
  85.      * @param PreSendSerializer        $serializer
  86.      * @param CacheManager             $cacheManager
  87.      * @param MessageBusInterface      $bus
  88.      * @param Security                 $security
  89.      * @param EventDispatcherInterface $eventDispatcher
  90.      * @param SentryLogger             $sentryLogger
  91.      */
  92.     public function __construct(
  93.         ApiWebService $apiWebService,
  94.         ApiProviderInterface $apiProvider,
  95.         TokenDataWrapper $tokenDataWrapper,
  96.         BasicDataWrapper $basicDataWrapper,
  97.         PreSendSerializer $serializer,
  98.         CacheManager $cacheManager,
  99.         MessageBusInterface $bus,
  100.         Security $security,
  101.         EventDispatcherInterface $eventDispatcher,
  102.         SentryLogger $sentryLogger
  103.     ) {
  104.         $this->apiWebService $apiWebService;
  105.         $this->apiProvider $apiProvider;
  106.         $this->tokenDataWrapper $tokenDataWrapper;
  107.         $this->basicDataWrapper $basicDataWrapper;
  108.         $this->serializer $serializer;
  109.         $this->cacheManager $cacheManager;
  110.         $this->bus $bus;
  111.         $this->security $security;
  112.         $this->eventDispatcher $eventDispatcher;
  113.         $this->sentryLogger $sentryLogger;
  114.     }
  115.     /**
  116.      * @param $data
  117.      * @param array $context
  118.      *
  119.      * @return bool
  120.      */
  121.     public function supports($data, array $context = []): bool
  122.     {
  123.         $entity $this::ENTITY;
  124.         return $data instanceof $entity && isset($context[self::CONTEXT_IS_V4]);
  125.     }
  126.     /**
  127.      * @param object $data
  128.      * @param array  $context
  129.      *
  130.      * @return object
  131.      *
  132.      * @throws InvalidArgumentException
  133.      * @throws AnnotationException
  134.      * @throws ExceptionInterface
  135.      * @throws ClientExceptionInterface
  136.      * @throws DecodingExceptionInterface
  137.      * @throws RedirectionExceptionInterface
  138.      * @throws ServerExceptionInterface
  139.      * @throws TransportExceptionInterface
  140.      */
  141.     public function persist($data, array $context = [])
  142.     {
  143.         $url $this::ENDPOINT;
  144.         $serializationGroups $this::POST_SERIALIZATION_GROUPS;
  145.         $method Request::METHOD_POST;
  146.         if (null !== $data->getId()) {
  147.             $method Request::METHOD_PUT;
  148.             $url sprintf('%s/%s'$this::ENDPOINT$data->getId());
  149.             $serializationGroups $this::PUT_SERIALIZATION_GROUPS;
  150.         }
  151.         $requestContent $this->serializer->serialize($data$serializationGroups);
  152.         $requestContent $this->reformatSubmittedData($requestContent);
  153.         $serializedData $this->basicDataWrapper->wrapData($requestContent);
  154.         $serializedData $this->tokenDataWrapper->wrapData($serializedData);
  155.         $response $this
  156.             ->apiWebService
  157.             ->send($this->apiProvider$method$url$serializedData)
  158.         ;
  159.         $data->setId($response->toArray()['id']);
  160.         $this->cacheManager->invalidateTag([$this->cacheManager->getCustomerPrefix().'_'.$this::ENTITY]);
  161.         if ($data instanceof CustomerFileAwareInterface) {
  162.             $this->cacheManager->invalidateTag([CustomerFile::class]);
  163.         }
  164.         if (!isset($context[self::CONTEXT_NOT_POST_PERSIST_EVENT])) {
  165.             $this->eventDispatcher->dispatch(
  166.                 (new PostPersistEvent())->setAfter($data)->setContext($context),
  167.                 PostPersistEvent::NAME
  168.             );
  169.         }
  170.         $user $this->security->getUser();
  171.         if ($user instanceof User) {
  172.             $this->bus->dispatch((new ResynchronizeBadgesRequest())
  173.                 ->setCustomerId($user->getCustomerId()));
  174.         }
  175.         return $data;
  176.     }
  177.     /**
  178.      * @param $data
  179.      * @param array $context
  180.      *
  181.      * @return void
  182.      *
  183.      * @throws TransportExceptionInterface
  184.      * @throws \Exception
  185.      */
  186.     public function remove($data, array $context = []): void
  187.     {
  188.         try {
  189.             $response $this
  190.                 ->apiWebService
  191.                 ->send($this->apiProviderRequest::METHOD_DELETEsprintf('%s/%s'$this::ENDPOINT$data->getId()))
  192.             ;
  193.             $this->cacheManager->invalidateTag([$this::ENTITY]);
  194.             if (Response::HTTP_OK === $response->getStatusCode() || Response::HTTP_NO_CONTENT === $response->getStatusCode()) {
  195.                 $this->eventDispatcher->dispatch((new PostRemoveEvent())->setAfter($data), PostRemoveEvent::NAME);
  196.             }
  197.         } catch (Throwable InvalidArgumentException $exception) {
  198.             $this->sentryLogger->captureException(
  199.                 SentryLogger::CHANNEL_DATA_PERSISTER,
  200.                 $exception,
  201.                 [
  202.                     'catchOnClass' => self::class,
  203.                     'apiCalled' => $this->apiProvider->getHost(),
  204.                     'urlCalled' => sprintf('%s/%s'self::ENDPOINT$data->getId()),
  205.                     'method' => Request::METHOD_DELETE,
  206.                     'message' => 'Unable to delete '.self::ENTITY.' with id '.$data->getId(),
  207.                 ]
  208.             );
  209.             throw new RuntimeException('Unable to delete '.$this::ENTITY.' with id '.$data->getId(), 0$exception);
  210.         }
  211.     }
  212.     /**
  213.      * @param $submittedData
  214.      *
  215.      * @return array
  216.      */
  217.     protected function reformatSubmittedData($submittedData): array
  218.     {
  219.         $submittedDataFormatted = [];
  220.         foreach ($submittedData as $fieldName => $value) {
  221.             if (str_starts_with($fieldName'sf_')) {
  222.                 $submittedDataFormatted array_merge($submittedDataFormatted, [$fieldName => $value]);
  223.                 continue;
  224.             }
  225.             $temp = &$submittedDataFormatted;
  226.             foreach (explode('_'$fieldName) as $key) {
  227.                 $temp = &$temp[$key];
  228.             }
  229.             $temp $value;
  230.         }
  231.         return $submittedDataFormatted;
  232.     }
  233. }