core/lib/Thelia/Core/Hook/BaseHook.php line 110

  1. <?php
  2. /*
  3.  * This file is part of the Thelia package.
  4.  * http://www.thelia.net
  5.  *
  6.  * (c) OpenStudio <info@thelia.net>
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace Thelia\Core\Hook;
  12. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  13. use Thelia\Core\Event\Hook\HookRenderEvent;
  14. use Thelia\Core\HttpFoundation\Request;
  15. use Thelia\Core\HttpFoundation\Session\Session;
  16. use Thelia\Core\Template\Assets\AssetResolverInterface;
  17. use Thelia\Core\Template\ParserInterface;
  18. use Thelia\Core\Translation\Translator;
  19. use Thelia\Model\Cart;
  20. use Thelia\Model\Currency;
  21. use Thelia\Model\Customer;
  22. use Thelia\Model\Lang;
  23. use Thelia\Model\ModuleQuery;
  24. use Thelia\Model\Order;
  25. use Thelia\Module\BaseModule;
  26. use TheliaSmarty\Template\SmartyParser;
  27. /**
  28.  * The base class for hook. If you provide hooks in your module you have to extends
  29.  * this class.
  30.  *
  31.  * These class provides some helper functions to retrieve object from the current session
  32.  * of the current user. It also provides a render function that allows you to get the right
  33.  * template file from different locations and allows you to override templates in your current
  34.  * template.
  35.  *
  36.  * Class BaseHook
  37.  *
  38.  * @author  Julien Chanséaume <jchanseaume@openstudio.fr>
  39.  */
  40. abstract class BaseHook implements BaseHookInterface
  41. {
  42.     public const INJECT_TEMPLATE_METHOD_NAME 'insertTemplate';
  43.     /** @var BaseModule */
  44.     public $module;
  45.     /** @var array list of templates automatically injected */
  46.     protected $templates = [];
  47.     /** @var \Thelia\Core\Template\ParserInterface */
  48.     public $parser;
  49.     /** @var TranslatorInterface */
  50.     public $translator;
  51.     /** @var AssetResolverInterface */
  52.     public $assetsResolver;
  53.     /** @var EventDispatcherInterface */
  54.     public $dispatcher;
  55.     /** @var Request */
  56.     protected $request;
  57.     /** @var Session */
  58.     protected $session;
  59.     /** @var Customer */
  60.     protected $customer;
  61.     /** @var Cart */
  62.     protected $cart;
  63.     /** @var Order */
  64.     protected $order;
  65.     /** @var Lang */
  66.     protected $lang;
  67.     /** @var Currency */
  68.     protected $currency;
  69.     public function __construct(SmartyParser $parser nullAssetResolverInterface $resolver nullEventDispatcherInterface $eventDispatcher null)
  70.     {
  71.         if (null !== $parser) {
  72.             $this->parser $parser;
  73.         }
  74.         if (null !== $resolver) {
  75.             $this->assetsResolver $resolver;
  76.         }
  77.         if (null !== $eventDispatcher) {
  78.             $this->dispatcher $eventDispatcher;
  79.         }
  80.         $moduleCode explode('\\', static::class)[0];
  81.         $module ModuleQuery::create()->findOneByCode($moduleCode);
  82.         $this->module $module;
  83.         $this->translator Translator::getInstance();
  84.     }
  85.     /**
  86.      * This function is called when hook uses the automatic insert template.
  87.      *
  88.      * @param string $code
  89.      */
  90.     public function insertTemplate(HookRenderEvent $event$code): void
  91.     {
  92.         if (\array_key_exists($code$this->templates)) {
  93.             $templates explode(';'$this->templates[$code]);
  94.             // Concatenate arguments and template variables,
  95.             // giving the precedence to arguments.
  96.             $allArguments $event->getTemplateVars() + $event->getArguments();
  97.             foreach ($templates as $template) {
  98.                 [$type$filepath] = $this->getTemplateParams($template);
  99.                 if ('render' === $type) {
  100.                     $event->add($this->render($filepath$allArguments));
  101.                     continue;
  102.                 }
  103.                 if ('dump' === $type) {
  104.                     $event->add($this->render($filepath));
  105.                     continue;
  106.                 }
  107.                 if ('css' === $type) {
  108.                     $event->add($this->addCSS($filepath));
  109.                     continue;
  110.                 }
  111.                 if ('js' === $type) {
  112.                     $event->add($this->addJS($filepath));
  113.                     continue;
  114.                 }
  115.                 if (method_exists($this$type)) {
  116.                     $this->{$type}($filepath$allArguments);
  117.                 }
  118.             }
  119.         }
  120.     }
  121.     /**
  122.      * helper function allowing you to render a template using a template engine.
  123.      *
  124.      * @param string $templateName the template path of the template
  125.      * @param array  $parameters   an array of parameters to assign to a template engine
  126.      *
  127.      * @return string the content generated by a template engine
  128.      */
  129.     public function render($templateName, array $parameters = [])
  130.     {
  131.         $templateDir $this->assetsResolver->resolveAssetSourcePath($this->module->getCode(), false$templateName$this->parser);
  132.         if (null !== $templateDir) {
  133.             // retrieve the template
  134.             $content $this->parser->render($templateDir.DS.$templateName$parameters);
  135.         } else {
  136.             $content sprintf('ERR: Unknown template %s for module %s'$templateName$this->module->getCode());
  137.         }
  138.         return $content;
  139.     }
  140.     /**
  141.      * helper function allowing you to get the content of a file.
  142.      *
  143.      * @param string $fileName the template path of the template
  144.      *
  145.      * @return string the content of the file
  146.      */
  147.     public function dump($fileName)
  148.     {
  149.         $fileDir $this->assetsResolver->resolveAssetSourcePath($this->module->getCode(), false$fileName$this->parser);
  150.         if (null !== $fileDir) {
  151.             $content file_get_contents($fileDir.DS.$fileName);
  152.             if (false === $content) {
  153.                 $content '';
  154.             }
  155.         } else {
  156.             $content sprintf('ERR: Unknown file %s for module %s'$fileName$this->module->getCode());
  157.         }
  158.         return $content;
  159.     }
  160.     /**
  161.      * helper function allowing you to generate the HTML link tag.
  162.      *
  163.      * @param string $fileName   the path to the css file
  164.      * @param array  $attributes the attributes of the tag
  165.      * @param array  $filters    an array of assets processing filters (less, sass, etc.)
  166.      *
  167.      * @return string the link tag
  168.      */
  169.     public function addCSS($fileName$attributes = [], $filters = [])
  170.     {
  171.         $tag '';
  172.         $url $this->assetsResolver->resolveAssetURL($this->module->getCode(), $fileName'css'$this->parser$filters);
  173.         if ('' !== $url) {
  174.             $tags = [];
  175.             $tags[] = '<link rel="stylesheet" type="text/css" ';
  176.             $tags[] = ' href="'.$url.'" ';
  177.             foreach ($attributes as $name => $val) {
  178.                 if (\is_string($name) && !\in_array($name, ['href''rel''type'])) {
  179.                     $tags[] = $name.'="'.$val.'" ';
  180.                 }
  181.             }
  182.             $tags[] = '/>';
  183.             $tag implode(''$tags);
  184.         }
  185.         return $tag;
  186.     }
  187.     /**
  188.      * helper function allowing you to generate the HTML script tag.
  189.      *
  190.      * @param string $fileName   the path to the js file
  191.      * @param array  $attributes the attributes of the tag
  192.      * @param array  $filters    an array of assets processing filters (cofeescript, compress, etc.)
  193.      *
  194.      * @return string the script tag
  195.      */
  196.     public function addJS($fileName$attributes = [], $filters = [])
  197.     {
  198.         $tag '';
  199.         $url $this->assetsResolver->resolveAssetURL($this->module->getCode(), $fileName'js'$this->parser$filters);
  200.         if ('' !== $url) {
  201.             $tags = [];
  202.             $tags[] = '<script type="text/javascript" ';
  203.             $tags[] = ' src="'.$url.'" ';
  204.             foreach ($attributes as $name => $val) {
  205.                 if (\is_string($name) && !\in_array($name, ['src''type'])) {
  206.                     $tags[] = $name.'="'.$val.'" ';
  207.                 }
  208.             }
  209.             $tags[] = '></script>';
  210.             $tag implode(''$tags);
  211.         }
  212.         return $tag;
  213.     }
  214.     /**
  215.      * @param \Thelia\Module\BaseModule $module
  216.      */
  217.     public function setModule($module): void
  218.     {
  219.         $this->module $module;
  220.     }
  221.     /**
  222.      * @return \Thelia\Module\BaseModule
  223.      */
  224.     public function getModule()
  225.     {
  226.         return $this->module;
  227.     }
  228.     public function setParser(ParserInterface $parser): void
  229.     {
  230.         $this->parser $parser;
  231.     }
  232.     /**
  233.      * @return \Thelia\Core\Template\ParserInterface
  234.      */
  235.     public function getParser()
  236.     {
  237.         return $this->parser;
  238.     }
  239.     /**
  240.      * Translates the given message.
  241.      *
  242.      * @param string $id         The message id (may also be an object that can be cast to string)
  243.      * @param array  $parameters An array of parameters for the message
  244.      * @param string $domain     The domain for the message
  245.      * @param string $locale     The locale
  246.      *
  247.      * @return string The translated string
  248.      *
  249.      * @api
  250.      */
  251.     protected function trans($id, array $parameters = [], $domain null$locale null)
  252.     {
  253.         return $this->translator->trans($id$parameters$domain$locale);
  254.     }
  255.     /**
  256.      * get the request.
  257.      *
  258.      * @return Request
  259.      */
  260.     protected function getRequest()
  261.     {
  262.         if (null === $this->request) {
  263.             $this->request $this->getParser()->getRequest();
  264.         }
  265.         return $this->request;
  266.     }
  267.     /**
  268.      * get the session.
  269.      *
  270.      * @return Session
  271.      */
  272.     protected function getSession()
  273.     {
  274.         if (null === $this->session) {
  275.             if (null !== $this->getRequest()) {
  276.                 $this->session $this->request->getSession();
  277.             }
  278.         }
  279.         return $this->session;
  280.     }
  281.     /**
  282.      * Get the view argument for the request.
  283.      *
  284.      * It allows you to identify the page currently displayed. eg: index, category, ...
  285.      *
  286.      * @return string the current view
  287.      */
  288.     protected function getView()
  289.     {
  290.         $ret '';
  291.         if (null !== $this->getRequest()) {
  292.             $ret $this->getRequest()->attributes->get('_view''');
  293.         }
  294.         return $ret;
  295.     }
  296.     /**
  297.      * Get the cart from the session.
  298.      *
  299.      * @return \Thelia\Model\Cart|null
  300.      */
  301.     protected function getCart()
  302.     {
  303.         if (null === $this->cart) {
  304.             $this->cart $this->getSession() ? $this->getSession()->getSessionCart($this->dispatcher) : null;
  305.         }
  306.         return $this->cart;
  307.     }
  308.     /**
  309.      * Get the order from the session.
  310.      *
  311.      * @return \Thelia\Model\Order|null
  312.      */
  313.     protected function getOrder()
  314.     {
  315.         if (null === $this->order) {
  316.             $this->order $this->getSession() ? $this->getSession()->getOrder() : null;
  317.         }
  318.         return $this->order;
  319.     }
  320.     /**
  321.      * Get the current currency used or if not present the default currency for the shop.
  322.      *
  323.      * @return \Thelia\Model\Currency
  324.      */
  325.     protected function getCurrency()
  326.     {
  327.         if (null === $this->currency) {
  328.             $this->currency $this->getSession() ? $this->getSession()->getCurrency(true) : Currency::getDefaultCurrency();
  329.         }
  330.         return $this->currency;
  331.     }
  332.     /**
  333.      * Get the current customer logged in. If no customer is logged return null.
  334.      *
  335.      * @return \Thelia\Model\Customer|null
  336.      */
  337.     protected function getCustomer()
  338.     {
  339.         if (null === $this->customer) {
  340.             $this->customer $this->getSession() ? $this->getSession()->getCustomerUser() : null;
  341.         }
  342.         return $this->customer;
  343.     }
  344.     /**
  345.      * Get the current lang used or if not present the default lang for the shop.
  346.      *
  347.      * @return \Thelia\Model\Lang
  348.      */
  349.     protected function getLang()
  350.     {
  351.         if (null === $this->lang) {
  352.             $this->lang $this->getSession() ? $this->getSession()->getLang(true) : $this->lang Lang::getDefaultLanguage();
  353.         }
  354.         return $this->lang;
  355.     }
  356.     /**
  357.      * Add a new template for automatic render.
  358.      *
  359.      * @param string $hookCode the code of the hook (the name of the event used to render) : 'hook.{type}.{hook code}'
  360.      * @param string $value    list of the template to render or add.
  361.      *                         eg: 'render:mytemplate.html;css:assets/css/mycss.css;js:assets/js/myjs.js'
  362.      */
  363.     public function addTemplate($hookCode$value): void
  364.     {
  365.         if (\array_key_exists($hookCode$this->templates)) {
  366.             throw new \InvalidArgumentException(sprintf("The hook '%s' is already used in this class."$hookCode));
  367.         }
  368.         $this->templates[$hookCode] = $value;
  369.     }
  370.     /**
  371.      * @return array templates
  372.      */
  373.     public function getTemplates()
  374.     {
  375.         return $this->templates;
  376.     }
  377.     /**
  378.      * @return array
  379.      */
  380.     protected function getTemplateParams($template)
  381.     {
  382.         $templateParams explode(':'$template);
  383.         if (\count($templateParams) > 1) {
  384.             $type $templateParams[0];
  385.             $filepath $templateParams[1];
  386.         } else {
  387.             $type 'render';
  388.             $filepath $templateParams[0];
  389.         }
  390.         return [$type$filepath];
  391.     }
  392.     /**
  393.      *  A hook is basically an Event, this function returns an array of hooks this hook subscriber wants to listen to.
  394.      *
  395.      *  Example:
  396.      *  [
  397.      *      'hook.event.name' => [
  398.      *          [
  399.      *              type => "back",
  400.      *              method => "onModuleConfiguration"
  401.      *          ],
  402.      *          [
  403.      *              type => "front",
  404.      *              template => "render:module_configuration.html"
  405.      *          ],
  406.      *          [
  407.      *              type => "front",
  408.      *              method => "displaySomething"
  409.      *          ],
  410.      *      ],
  411.      *      'another.hook' => [[...]]
  412.      *  ]
  413.      *
  414.      * @return array
  415.      */
  416.     public static function getSubscribedHooks()
  417.     {
  418.         return [];
  419.     }
  420. }