vendor/shopware/core/Framework/Api/EventListener/ExpectationSubscriber.php line 49

  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Api\EventListener;
  3. use Composer\InstalledVersions;
  4. use Composer\Semver\Semver;
  5. use Shopware\Core\Framework\Api\Exception\ExpectationFailedException;
  6. use Shopware\Core\Framework\Log\Package;
  7. use Shopware\Core\Framework\Routing\ApiRouteScope;
  8. use Shopware\Core\Framework\Routing\KernelListenerPriorities;
  9. use Shopware\Core\PlatformRequest;
  10. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  11. use Symfony\Component\HttpFoundation\Request;
  12. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  13. use Symfony\Component\HttpKernel\KernelEvents;
  14. /**
  15.  * @internal
  16.  *
  17.  * @phpstan-type PluginData array{'composerName': string, 'active': bool, 'version': string}
  18.  */
  19. #[Package('core')]
  20. class ExpectationSubscriber implements EventSubscriberInterface
  21. {
  22.     private const SHOPWARE_CORE_PACKAGES = [
  23.         'shopware/platform',
  24.         'shopware/core',
  25.         'shopware/administration',
  26.         'shopware/elasticsearch',
  27.         'shopware/storefront',
  28.     ];
  29.     /**
  30.      * @internal
  31.      *
  32.      * @param list<PluginData> $plugins
  33.      */
  34.     public function __construct(private readonly string $shopwareVersion, private readonly array $plugins)
  35.     {
  36.     }
  37.     public static function getSubscribedEvents(): array
  38.     {
  39.         return [
  40.             KernelEvents::CONTROLLER => ['checkExpectations'KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_SCOPE_VALIDATE_POST],
  41.         ];
  42.     }
  43.     public function checkExpectations(ControllerEvent $event): void
  44.     {
  45.         $request $event->getRequest();
  46.         if (!$request->attributes->has(PlatformRequest::ATTRIBUTE_ROUTE_SCOPE)) {
  47.             return;
  48.         }
  49.         /** @var list<string> $scope */
  50.         $scope $request->attributes->get(PlatformRequest::ATTRIBUTE_ROUTE_SCOPE, []);
  51.         if (!\in_array(ApiRouteScope::ID$scopetrue)) {
  52.             return;
  53.         }
  54.         $expectations $this->checkPackages($request);
  55.         if (\count($expectations)) {
  56.             throw new ExpectationFailedException($expectations);
  57.         }
  58.     }
  59.     /**
  60.      * @return list<string>
  61.      */
  62.     private function checkPackages(Request $request): array
  63.     {
  64.         // swag/plugin1:~6.1,swag/plugin2:~6.1
  65.         $extensionConstraints array_filter(explode(',', (string) $request->headers->get(PlatformRequest::HEADER_EXPECT_PACKAGES)));
  66.         if ($extensionConstraints === []) {
  67.             return [];
  68.         }
  69.         $plugins $this->getIndexedPackages();
  70.         $fails = [];
  71.         foreach ($extensionConstraints as $extension) {
  72.             $explode explode(':'$extension);
  73.             if (\count($explode) !== 2) {
  74.                 $fails[] = sprintf('Got invalid string: "%s"'$extension);
  75.                 continue;
  76.             }
  77.             $name $explode[0];
  78.             $constraint $explode[1];
  79.             if (isset($plugins[$name])) {
  80.                 $installedVersion $plugins[$name];
  81.             } else {
  82.                 try {
  83.                     $installedVersion InstalledVersions::getPrettyVersion($name);
  84.                 } catch (\OutOfBoundsException) {
  85.                     $fails[] = sprintf('Requested package: %s is not available'$name);
  86.                     continue;
  87.                 }
  88.                 if (\in_array($nameself::SHOPWARE_CORE_PACKAGEStrue)) {
  89.                     $installedVersion $this->shopwareVersion;
  90.                 }
  91.             }
  92.             if ($installedVersion === null) {
  93.                 // should never happen, but phpstan would complain otherwise
  94.                 continue;
  95.             }
  96.             if (Semver::satisfies($installedVersion$constraint)) {
  97.                 continue;
  98.             }
  99.             $fails[] = sprintf('Version constraint for %s is failed. Installed is: %s'$name$installedVersion);
  100.         }
  101.         return $fails;
  102.     }
  103.     /**
  104.      * Plugins are not in the InstalledPackages file until now
  105.      *
  106.      * @return array<string, string>
  107.      */
  108.     private function getIndexedPackages(): array
  109.     {
  110.         $versions = [];
  111.         foreach ($this->plugins as $plugin) {
  112.             if (!$plugin['active']) {
  113.                 continue;
  114.             }
  115.             $versions[$plugin['composerName']] = $plugin['version'];
  116.         }
  117.         return $versions;
  118.     }
  119. }