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

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