vendor/shopware/core/Framework/Api/Controller/InfoController.php line 109

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Api\Controller;
  3. use Doctrine\DBAL\Connection;
  4. use Shopware\Core\Content\Flow\Api\FlowActionCollector;
  5. use Shopware\Core\Framework\Api\ApiDefinition\DefinitionService;
  6. use Shopware\Core\Framework\Api\ApiDefinition\Generator\EntitySchemaGenerator;
  7. use Shopware\Core\Framework\Api\ApiDefinition\Generator\OpenApi3Generator;
  8. use Shopware\Core\Framework\Bundle;
  9. use Shopware\Core\Framework\Context;
  10. use Shopware\Core\Framework\Event\BusinessEventCollector;
  11. use Shopware\Core\Framework\Feature;
  12. use Shopware\Core\Framework\Increment\Exception\IncrementGatewayNotFoundException;
  13. use Shopware\Core\Framework\Increment\IncrementGatewayRegistry;
  14. use Shopware\Core\Framework\Plugin;
  15. use Shopware\Core\Framework\Routing\Annotation\Since;
  16. use Shopware\Core\Framework\Routing\Exception\InvalidRequestParameterException;
  17. use Shopware\Core\Kernel;
  18. use Shopware\Core\PlatformRequest;
  19. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  20. use Symfony\Component\Asset\PackageInterface;
  21. use Symfony\Component\Asset\Packages;
  22. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  23. use Symfony\Component\HttpFoundation\JsonResponse;
  24. use Symfony\Component\HttpFoundation\Request;
  25. use Symfony\Component\HttpFoundation\Response;
  26. use Symfony\Component\Routing\Annotation\Route;
  27. /**
  28.  * @Route(defaults={"_routeScope"={"api"}})
  29.  */
  30. class InfoController extends AbstractController
  31. {
  32.     private DefinitionService $definitionService;
  33.     private ParameterBagInterface $params;
  34.     private Packages $packages;
  35.     private Kernel $kernel;
  36.     private bool $enableUrlFeature;
  37.     /**
  38.      * @var array{administration?: string}
  39.      */
  40.     private array $cspTemplates;
  41.     private BusinessEventCollector $eventCollector;
  42.     private ?FlowActionCollector $flowActionCollector;
  43.     private IncrementGatewayRegistry $incrementGatewayRegistry;
  44.     private Connection $connection;
  45.     /**
  46.      * @param array{administration?: string} $cspTemplates
  47.      *
  48.      * @internal
  49.      */
  50.     public function __construct(
  51.         DefinitionService $definitionService,
  52.         ParameterBagInterface $params,
  53.         Kernel $kernel,
  54.         Packages $packages,
  55.         BusinessEventCollector $eventCollector,
  56.         IncrementGatewayRegistry $incrementGatewayRegistry,
  57.         Connection $connection,
  58.         ?FlowActionCollector $flowActionCollector null,
  59.         bool $enableUrlFeature true,
  60.         array $cspTemplates = []
  61.     ) {
  62.         $this->definitionService $definitionService;
  63.         $this->params $params;
  64.         $this->packages $packages;
  65.         $this->kernel $kernel;
  66.         $this->enableUrlFeature $enableUrlFeature;
  67.         $this->flowActionCollector $flowActionCollector;
  68.         $this->cspTemplates $cspTemplates;
  69.         $this->eventCollector $eventCollector;
  70.         $this->incrementGatewayRegistry $incrementGatewayRegistry;
  71.         $this->connection $connection;
  72.     }
  73.     /**
  74.      * @Since("6.0.0.0")
  75.      * @Route("/api/_info/openapi3.json", defaults={"auth_required"="%shopware.api.api_browser.auth_required_str%"}, name="api.info.openapi3", methods={"GET"})
  76.      */
  77.     public function info(Request $request): JsonResponse
  78.     {
  79.         $apiType $request->query->getAlpha('type'DefinitionService::TypeJsonApi);
  80.         $apiType $this->definitionService->toApiType($apiType);
  81.         if ($apiType === null) {
  82.             throw new InvalidRequestParameterException('type');
  83.         }
  84.         $data $this->definitionService->generate(OpenApi3Generator::FORMATDefinitionService::API$apiType);
  85.         return new JsonResponse($data);
  86.     }
  87.     /**
  88.      * @Since("6.4.6.0")
  89.      * @Route("/api/_info/queue.json", name="api.info.queue", methods={"GET"})
  90.      */
  91.     public function queue(): JsonResponse
  92.     {
  93.         try {
  94.             $gateway $this->incrementGatewayRegistry->get(IncrementGatewayRegistry::MESSAGE_QUEUE_POOL);
  95.         } catch (IncrementGatewayNotFoundException $exception) {
  96.             // In case message_queue pool is disabled
  97.             return new JsonResponse([]);
  98.         }
  99.         // Fetch unlimited message_queue_stats
  100.         $entries $gateway->list('message_queue_stats', -1);
  101.         return new JsonResponse(array_map(function (array $entry) {
  102.             return [
  103.                 'name' => $entry['key'],
  104.                 'size' => (int) $entry['count'],
  105.             ];
  106.         }, array_values($entries)));
  107.     }
  108.     /**
  109.      * @Since("6.0.0.0")
  110.      * @Route("/api/_info/open-api-schema.json", defaults={"auth_required"="%shopware.api.api_browser.auth_required_str%"}, name="api.info.open-api-schema", methods={"GET"})
  111.      */
  112.     public function openApiSchema(): JsonResponse
  113.     {
  114.         $data $this->definitionService->getSchema(OpenApi3Generator::FORMATDefinitionService::API);
  115.         return new JsonResponse($data);
  116.     }
  117.     /**
  118.      * @Since("6.0.0.0")
  119.      * @Route("/api/_info/entity-schema.json", name="api.info.entity-schema", methods={"GET"})
  120.      */
  121.     public function entitySchema(): JsonResponse
  122.     {
  123.         $data $this->definitionService->getSchema(EntitySchemaGenerator::FORMATDefinitionService::API);
  124.         return new JsonResponse($data);
  125.     }
  126.     /**
  127.      * @Since("6.3.2.0")
  128.      * @Route("/api/_info/events.json", name="api.info.business-events", methods={"GET"})
  129.      */
  130.     public function businessEvents(Context $context): JsonResponse
  131.     {
  132.         $events $this->eventCollector->collect($context);
  133.         return $this->json($events);
  134.     }
  135.     /**
  136.      * @Since("6.0.0.0")
  137.      * @Route("/api/_info/swagger.html", defaults={"auth_required"="%shopware.api.api_browser.auth_required_str%"}, name="api.info.swagger", methods={"GET"})
  138.      */
  139.     public function infoHtml(Request $request): Response
  140.     {
  141.         $nonce $request->attributes->get(PlatformRequest::ATTRIBUTE_CSP_NONCE);
  142.         $apiType $request->query->getAlpha('type'DefinitionService::TypeJson);
  143.         $response $this->render(
  144.             '@Framework/swagger.html.twig',
  145.             [
  146.                 'schemaUrl' => 'api.info.openapi3',
  147.                 'cspNonce' => $nonce,
  148.                 'apiType' => $apiType,
  149.             ]
  150.         );
  151.         $cspTemplate $this->cspTemplates['administration'] ?? '';
  152.         $cspTemplate trim($cspTemplate);
  153.         if ($cspTemplate !== '') {
  154.             $csp str_replace('%nonce%'$nonce$cspTemplate);
  155.             $csp str_replace(["\n""\r"], ' '$csp);
  156.             $response->headers->set('Content-Security-Policy'$csp);
  157.         }
  158.         return $response;
  159.     }
  160.     /**
  161.      * @Since("6.0.0.0")
  162.      * @Route("/api/_info/config", name="api.info.config", methods={"GET"})
  163.      *
  164.      * @deprecated tag:v6.5.0 $context param will be required
  165.      */
  166.     public function config(?Context $context null): JsonResponse
  167.     {
  168.         if (!$context) {
  169.             Feature::triggerDeprecationOrThrow(
  170.                 'v6.5.0.0',
  171.                 'First parameter `$context` will be required in method `config()` in `InfoController` in v6.5.0.0'
  172.             );
  173.             $context Context::createDefaultContext();
  174.         }
  175.         return new JsonResponse([
  176.             'version' => $this->params->get('kernel.shopware_version'),
  177.             'versionRevision' => $this->params->get('kernel.shopware_version_revision'),
  178.             'adminWorker' => [
  179.                 'enableAdminWorker' => $this->params->get('shopware.admin_worker.enable_admin_worker'),
  180.                 'transports' => $this->params->get('shopware.admin_worker.transports'),
  181.             ],
  182.             'bundles' => $this->getBundles($context),
  183.             'settings' => [
  184.                 'enableUrlFeature' => $this->enableUrlFeature,
  185.             ],
  186.         ]);
  187.     }
  188.     /**
  189.      * @Since("6.3.5.0")
  190.      * @Route("/api/_info/version", name="api.info.shopware.version", methods={"GET"})
  191.      * @Route("/api/v1/_info/version", name="api.info.shopware.version_old_version", methods={"GET"})
  192.      */
  193.     public function infoShopwareVersion(): JsonResponse
  194.     {
  195.         return new JsonResponse([
  196.             'version' => $this->params->get('kernel.shopware_version'),
  197.         ]);
  198.     }
  199.     /**
  200.      * @Since("6.4.5.0")
  201.      * @Route("/api/_info/flow-actions.json", name="api.info.actions", methods={"GET"})
  202.      */
  203.     public function flowActions(Context $context): JsonResponse
  204.     {
  205.         if (!$this->flowActionCollector) {
  206.             return $this->json([]);
  207.         }
  208.         $events $this->flowActionCollector->collect($context);
  209.         return $this->json($events);
  210.     }
  211.     /**
  212.      * @return array<string, array{type: 'plugin', css: string[], js: string[], baseUrl: ?string }|array{type: 'app', name: string, active: bool, integrationId: string, baseUrl: string, version: string, permissions: array<string,string[]>}>
  213.      */
  214.     private function getBundles(Context $context): array
  215.     {
  216.         $assets = [];
  217.         $package $this->packages->getPackage('asset');
  218.         foreach ($this->kernel->getBundles() as $bundle) {
  219.             if (!$bundle instanceof Bundle) {
  220.                 continue;
  221.             }
  222.             $bundleDirectoryName preg_replace('/bundle$/'''mb_strtolower($bundle->getName()));
  223.             if ($bundleDirectoryName === null) {
  224.                 throw new \RuntimeException(sprintf('Unable to generate bundle directory for bundle "%s"'$bundle->getName()));
  225.             }
  226.             $styles array_map(static function (string $filename) use ($package$bundleDirectoryName) {
  227.                 $url 'bundles/' $bundleDirectoryName '/' $filename;
  228.                 return $package->getUrl($url);
  229.             }, $this->getAdministrationStyles($bundle));
  230.             $scripts array_map(static function (string $filename) use ($package$bundleDirectoryName) {
  231.                 $url 'bundles/' $bundleDirectoryName '/' $filename;
  232.                 return $package->getUrl($url);
  233.             }, $this->getAdministrationScripts($bundle));
  234.             $baseUrl $this->getBaseUrl($bundle$package$bundleDirectoryName);
  235.             if (empty($styles) && empty($scripts)) {
  236.                 if ($baseUrl === null) {
  237.                     continue;
  238.                 }
  239.             }
  240.             $assets[$bundle->getName()] = [
  241.                 'css' => $styles,
  242.                 'js' => $scripts,
  243.                 'baseUrl' => $baseUrl,
  244.                 'type' => 'plugin',
  245.             ];
  246.         }
  247.         foreach ($this->getActiveApps() as $app) {
  248.             $assets[$app['name']] = [
  249.                 'active' => (bool) $app['active'],
  250.                 'integrationId' => $app['integrationId'],
  251.                 'type' => 'app',
  252.                 'baseUrl' => $app['baseUrl'],
  253.                 'permissions' => $app['privileges'],
  254.                 'version' => $app['version'],
  255.                 'name' => $app['name'],
  256.             ];
  257.         }
  258.         return $assets;
  259.     }
  260.     /**
  261.      * @return list<string>
  262.      */
  263.     private function getAdministrationStyles(Bundle $bundle): array
  264.     {
  265.         $path 'administration/css/' str_replace('_''-'$bundle->getContainerPrefix()) . '.css';
  266.         $bundlePath $bundle->getPath();
  267.         if (!file_exists($bundlePath '/Resources/public/' $path)) {
  268.             return [];
  269.         }
  270.         return [$path];
  271.     }
  272.     /**
  273.      * @return list<string>
  274.      */
  275.     private function getAdministrationScripts(Bundle $bundle): array
  276.     {
  277.         $path 'administration/js/' str_replace('_''-'$bundle->getContainerPrefix()) . '.js';
  278.         $bundlePath $bundle->getPath();
  279.         if (!file_exists($bundlePath '/Resources/public/' $path)) {
  280.             return [];
  281.         }
  282.         return [$path];
  283.     }
  284.     private function getBaseUrl(Bundle $bundlePackageInterface $packagestring $bundleDirectoryName): ?string
  285.     {
  286.         if (!$bundle instanceof Plugin) {
  287.             return null;
  288.         }
  289.         if ($bundle->getAdminBaseUrl()) {
  290.             return $bundle->getAdminBaseUrl();
  291.         }
  292.         $defaultEntryFile 'administration/index.html';
  293.         $bundlePath $bundle->getPath();
  294.         if (!file_exists($bundlePath '/Resources/public/' $defaultEntryFile)) {
  295.             return null;
  296.         }
  297.         $url 'bundles/' $bundleDirectoryName '/' $defaultEntryFile;
  298.         return $package->getUrl($url);
  299.     }
  300.     /**
  301.      * @return list<array{name: string, active: int, integrationId: string, baseUrl: string, version: string, privileges: array<string,list<string>>}>
  302.      */
  303.     private function getActiveApps(): array
  304.     {
  305.         /** @var list<array{name: string, active: int, integrationId: string, baseUrl: string, version: string, privileges: ?string}> $apps */
  306.         $apps $this->connection->fetchAllAssociative('SELECT
  307.     app.name,
  308.     app.active,
  309.     LOWER(HEX(app.integration_id)) as integrationId,
  310.     app.base_app_url as baseUrl,
  311.     app.version,
  312.     ar.privileges as privileges
  313. FROM app
  314. LEFT JOIN acl_role ar on app.acl_role_id = ar.id
  315. WHERE app.active = 1 AND app.base_app_url is not null');
  316.         return array_map(static function (array $item) {
  317.             $privileges $item['privileges'] ? json_decode($item['privileges'], true512, \JSON_THROW_ON_ERROR) : [];
  318.             $item['privileges'] = [];
  319.             foreach ($privileges as $privilege) {
  320.                 if (substr_count($privilege':') !== 1) {
  321.                     $item['privileges']['additional'][] = $privilege;
  322.                     continue;
  323.                 }
  324.                 [$entity$key] = \explode(':'$privilege);
  325.                 $item['privileges'][$key][] = $entity;
  326.             }
  327.             return $item;
  328.         }, $apps);
  329.     }
  330. }