vendor/shopware/core/Framework/Script/Execution/ScriptExecutor.php line 87

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Script\Execution;
  3. use Psr\Log\LoggerInterface;
  4. use Shopware\Core\DevOps\Environment\EnvironmentHelper;
  5. use Shopware\Core\Framework\Adapter\Twig\Extension\PhpSyntaxExtension;
  6. use Shopware\Core\Framework\Adapter\Twig\TwigEnvironment;
  7. use Shopware\Core\Framework\App\Event\Hooks\AppLifecycleHook;
  8. use Shopware\Core\Framework\Script\Debugging\Debug;
  9. use Shopware\Core\Framework\Script\Debugging\ScriptTraces;
  10. use Shopware\Core\Framework\Script\Exception\NoHookServiceFactoryException;
  11. use Shopware\Core\Framework\Script\Exception\ScriptExecutionFailedException;
  12. use Shopware\Core\Framework\Script\Execution\Awareness\AppSpecificHook;
  13. use Shopware\Core\Framework\Script\Execution\Awareness\HookServiceFactory;
  14. use Shopware\Core\Framework\Script\Execution\Awareness\StoppableHook;
  15. use Shopware\Core\Framework\Script\ServiceStubs;
  16. use Symfony\Bridge\Twig\Extension\TranslationExtension;
  17. use Symfony\Component\DependencyInjection\ContainerInterface;
  18. use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
  19. use Twig\Environment;
  20. use Twig\Extension\DebugExtension;
  21. /**
  22.  * @package core
  23.  */
  24. class ScriptExecutor
  25. {
  26.     public static bool $isInScriptExecutionContext false;
  27.     private LoggerInterface $logger;
  28.     private ScriptLoader $loader;
  29.     private ScriptTraces $traces;
  30.     private ContainerInterface $container;
  31.     private TranslationExtension $translationExtension;
  32.     /**
  33.      * @internal
  34.      */
  35.     public function __construct(
  36.         ScriptLoader $loader,
  37.         LoggerInterface $logger,
  38.         ScriptTraces $traces,
  39.         ContainerInterface $container,
  40.         TranslationExtension $translationExtension
  41.     ) {
  42.         $this->logger $logger;
  43.         $this->loader $loader;
  44.         $this->traces $traces;
  45.         $this->container $container;
  46.         $this->translationExtension $translationExtension;
  47.     }
  48.     public function execute(Hook $hook): void
  49.     {
  50.         if (EnvironmentHelper::getVariable('DISABLE_EXTENSIONS'false)) {
  51.             return;
  52.         }
  53.         if ($hook instanceof InterfaceHook) {
  54.             throw new \RuntimeException(sprintf(
  55.                 'Tried to execute InterfaceHook "%s", butInterfaceHooks should not be executed, execute the functions of the hook instead',
  56.                 \get_class($hook)
  57.             ));
  58.         }
  59.         $scripts $this->loader->get($hook->getName());
  60.         $this->traces->initHook($hook);
  61.         foreach ($scripts as $script) {
  62.             $scriptAppInfo $script->getScriptAppInformation();
  63.             if ($scriptAppInfo && $hook instanceof AppSpecificHook && $hook->getAppId() !== $scriptAppInfo->getAppId()) {
  64.                 // only execute scripts from the app the hook specifies
  65.                 continue;
  66.             }
  67.             if (!$hook instanceof AppLifecycleHook && !$script->isActive()) {
  68.                 continue;
  69.             }
  70.             try {
  71.                 static::$isInScriptExecutionContext true;
  72.                 $this->render($hook$script);
  73.             } catch (\Throwable $e) {
  74.                 $scriptException = new ScriptExecutionFailedException($hook->getName(), $script->getName(), $e);
  75.                 $this->logger->error($scriptException->getMessage(), ['exception' => $e]);
  76.                 throw $scriptException;
  77.             } finally {
  78.                 static::$isInScriptExecutionContext false;
  79.             }
  80.             if ($hook instanceof StoppableHook && $hook->isPropagationStopped()) {
  81.                 break;
  82.             }
  83.         }
  84.     }
  85.     private function render(Hook $hookScript $script): void
  86.     {
  87.         $twig $this->initEnv($script);
  88.         $services $this->initServices($hook$script);
  89.         $twig->addGlobal('services'$services);
  90.         $this->traces->trace($hook$script, function (Debug $debug) use ($twig$script$hook): void {
  91.             $twig->addGlobal('debug'$debug);
  92.             if ($hook instanceof DeprecatedHook) {
  93.                 ScriptTraces::addDeprecationNotice($hook->getDeprecationNotice());
  94.             }
  95.             $template $twig->load($script->getName());
  96.             if (!$hook instanceof FunctionHook) {
  97.                 $template->render(['hook' => $hook]);
  98.                 return;
  99.             }
  100.             $blockName $hook->getFunctionName();
  101.             if ($template->hasBlock($blockName)) {
  102.                 $template->renderBlock($blockName, ['hook' => $hook]);
  103.                 return;
  104.             }
  105.             if (!$hook instanceof OptionalFunctionHook) {
  106.                 throw new \RuntimeException(sprintf(
  107.                     'Required function "%s" missing in script "%s", please make sure you add the required block in your script.',
  108.                     $hook->getFunctionName(),
  109.                     $script->getName()
  110.                 ));
  111.             }
  112.             $requiredFromVersion $hook->willBeRequiredInVersion();
  113.             if ($requiredFromVersion) {
  114.                 ScriptTraces::addDeprecationNotice(sprintf(
  115.                     'Function "%s" will be required from %s onward, but is not implemented in script "%s", please make sure you add the block in your script.',
  116.                     $hook->getFunctionName(),
  117.                     $requiredFromVersion,
  118.                     $script->getName()
  119.                 ));
  120.             }
  121.         });
  122.         $this->callAfter($services$hook$script);
  123.     }
  124.     private function initEnv(Script $script): Environment
  125.     {
  126.         $twig = new TwigEnvironment(
  127.             new ScriptTwigLoader($script),
  128.             $script->getTwigOptions()
  129.         );
  130.         $twig->addExtension(new PhpSyntaxExtension());
  131.         $twig->addExtension($this->translationExtension);
  132.         if ($script->getTwigOptions()['debug'] ?? false) {
  133.             $twig->addExtension(new DebugExtension());
  134.         }
  135.         return $twig;
  136.     }
  137.     private function initServices(Hook $hookScript $script): ServiceStubs
  138.     {
  139.         $services = new ServiceStubs($hook->getName());
  140.         $deprecatedServices $hook->getDeprecatedServices();
  141.         foreach ($hook->getServiceIds() as $serviceId) {
  142.             if (!$this->container->has($serviceId)) {
  143.                 throw new ServiceNotFoundException($serviceId'Hook: ' $hook->getName());
  144.             }
  145.             $service $this->container->get($serviceId);
  146.             if (!$service instanceof HookServiceFactory) {
  147.                 throw new NoHookServiceFactoryException($serviceId);
  148.             }
  149.             $services->add($service->getName(), $service->factory($hook$script), $deprecatedServices[$serviceId] ?? null);
  150.         }
  151.         return $services;
  152.     }
  153.     private function callAfter(ServiceStubs $servicesHook $hookScript $script): void
  154.     {
  155.         foreach ($hook->getServiceIds() as $serviceId) {
  156.             if (!$this->container->has($serviceId)) {
  157.                 throw new ServiceNotFoundException($serviceId'Hook: ' $hook->getName());
  158.             }
  159.             $factory $this->container->get($serviceId);
  160.             if (!$factory instanceof HookServiceFactory) {
  161.                 throw new NoHookServiceFactoryException($serviceId);
  162.             }
  163.             $service $services->get($factory->getName());
  164.             $factory->after($service$hook$script);
  165.         }
  166.     }
  167. }