vendor/can/rest/src/Can/RestBundle/EventListener/VersionListener.php line 64

Open in your IDE?
  1. <?php
  2. namespace Can\RestBundle\EventListener;
  3. use Can\RestBundle\CanRestBundle;
  4. use Can\RestBundle\Http\Exception\UpgradeRequiredHttpException;
  5. use Can\RestBundle\Mapping\Metadata\VersionMetadata;
  6. use Can\RestBundle\Mapping\MetadataStore;
  7. use Can\RestBundle\URI\ServiceNode;
  8. use Can\RestBundle\URI\WellKnownURIs;
  9. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  10. use Symfony\Component\HttpKernel\Event\RequestEvent;
  11. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  12. use DateTime;
  13. use Exception;
  14. /**
  15.  * @group service
  16.  *
  17.  * @package can/rest-bundle
  18.  * @author lechecacharro <lechecacharro@gmail.com>
  19.  */
  20. class VersionListener
  21. {
  22.     /**
  23.      * @var bool
  24.      */
  25.     private $enabled;
  26.     /**
  27.      * @var EventDispatcherInterface
  28.      */
  29.     private $dispatcher;
  30.     /**
  31.      * @var MetadataStore
  32.      */
  33.     private $metadataStore;
  34.     /**
  35.      * VersionListener constructor.
  36.      *
  37.      * @param bool                     $enabled
  38.      * @param MetadataStore            $metadataStore
  39.      * @param EventDispatcherInterface $dispatcher
  40.      */
  41.     public function __construct(bool $enabledEventDispatcherInterface $dispatcherMetadataStore $metadataStore)
  42.     {
  43.         $this->enabled $enabled;
  44.         $this->dispatcher $dispatcher;
  45.         $this->metadataStore $metadataStore;
  46.     }
  47.     /**
  48.      * @param RequestEvent $event
  49.      *
  50.      * @throws Exception
  51.      */
  52.     public function onRequest(RequestEvent $event): void
  53.     {
  54.         if (! $this->enabled) {
  55.             return;
  56.         }
  57.         if (! $event->isMasterRequest()) {
  58.             return;
  59.         }
  60.         $request $event->getRequest();
  61.         if (! $serviceNode $request->attributes->get(CanRestBundle::ATTR_SERVICE_NODE)) {
  62.             return;
  63.         }
  64.         if (! $metadata $this->getVersionMetadata($serviceNode)) {
  65.             return;
  66.         }
  67.         // If the requested service version is no longer supported, and we can
  68.         // offer an alternative to the consumer (that is a version upgrade),
  69.         // then return a 426 (Upgrade Required) response
  70.         if ($metadata->isNotSupported()) {
  71.             if ($upgradeToVersion $this->getUpgradeToVersion($metadata)) {
  72.                 throw new UpgradeRequiredHttpException($serviceNode->getVersionNumber(), $upgradeToVersion$metadata->getSupportEndsAt());
  73.             }
  74.         }
  75.         // Else, if the requested service version is already deprecated, then
  76.         // add a response listener to generate the appropriate HTTP headers
  77.         // to keep the consumer informed
  78.         if ($metadata->isDeprecated()) {
  79.             $this->dispatcher->addListener('kernel.response', [static::class, 'onResponse'], -1);
  80.         }
  81.     }
  82.     /**
  83.      * @param ResponseEvent $event
  84.      */
  85.     public function onResponse(ResponseEvent $event): void
  86.     {
  87.         $serviceNode $event->getRequest()->attributes->get(CanRestBundle::ATTR_SERVICE_NODE);
  88.         $metadata $this->getVersionMetadata($serviceNode);
  89.         // Add a Sunset header
  90.         $event->getResponse()->headers->set('Sunset'$this->getSunset($metadata));
  91.     }
  92.     /**
  93.      * @param ServiceNode $serviceNode
  94.      *
  95.      * @return VersionMetadata | null
  96.      */
  97.     private function getVersionMetadata(ServiceNode $serviceNode): ?VersionMetadata
  98.     {
  99.         if (! $versionNumber $serviceNode->getVersionNumber()) {
  100.             return null;
  101.         }
  102.         if (WellKnownURIs::WELL_KNOWN === $versionNumber) {
  103.             return null;
  104.         }
  105.         return $this->metadataStore->getVersionMetadata($versionNumber);
  106.     }
  107.     /**
  108.      * @param VersionMetadata $metadata
  109.      *
  110.      * @return string
  111.      */
  112.     private function getSunset(VersionMetadata $metadata): string
  113.     {
  114.         return $metadata->getDeprecatedSince()->format(DateTime::RFC1123);
  115.     }
  116.     /**
  117.      * @param VersionMetadata $metadata
  118.      *
  119.      * @return string | null
  120.      *
  121.      * @throws Exception
  122.      */
  123.     private function getUpgradeToVersion(VersionMetadata $metadata): ?string
  124.     {
  125.         $serviceMetadata $this->metadataStore->getServiceMetadata();
  126.         $versionIterator $serviceMetadata->getVersions()->getIterator();
  127.         $versionNumber $metadata->getNumber();
  128.         // Recommend always the LTS version
  129.         foreach ($versionIterator as $version) {
  130.             if ($version->isLongTermSupport()) {
  131.                 return $version->getNumber();
  132.             }
  133.         }
  134.         // If no LTS version is declared, then choose the immediate version
  135.         // number which is not deprecated
  136.         foreach ($versionIterator as $version) {
  137.             if ($version->getNumber() > $versionNumber && ! $version->isDeprecated()) {
  138.                 return $version->getNumber();
  139.             }
  140.         }
  141.         // Return the default service version, if it's different from the
  142.         // deprecated version
  143.         if ($serviceMetadata->getDefaultVersionMetadata() > $versionNumber) {
  144.             return $serviceMetadata->getDefaultVersion();
  145.         }
  146.         // Cannot find a version to upgrade to
  147.         return null;
  148.     }
  149. }