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

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