src/Cms/WidgetBundle/Service/Twig/WidgetExtension.php line 259

Open in your IDE?
  1. <?php
  2. namespace Cms\WidgetBundle\Service\Twig;
  3. use Cms\AssetsBundle\Service\AssetCatalog;
  4. use Cms\ContentBundle\Service\FrontendRenderer;
  5. use Cms\CoreBundle\Service\SceneRenderer;
  6. use Cms\CoreBundle\Service\Transcoding\TranscodedObject;
  7. use Cms\CoreBundle\Service\Transcoding\Transcoder;
  8. use Cms\FileBundle\Service\FileManager;
  9. use Cms\FrontendBundle\Model\FrontendGlobals;
  10. use Cms\ThemeBundle\Service\Twig\Loader\DatabaseLoader;
  11. use Cms\WidgetBundle\Model\Widget;
  12. use Cms\WidgetBundle\Model\WidgetContainer;
  13. use Cms\WidgetBundle\Model\WidgetObject;
  14. use Twig\Extension\AbstractExtension;
  15. use Twig\TwigFunction;
  16. /**
  17.  * Provides Twig helpers to work with widgets easily inside of Twig files.
  18.  *
  19.  * Class WidgetExtension
  20.  * @package Cms\WidgetBundle\Service\Twig
  21.  */
  22. final class WidgetExtension extends AbstractExtension
  23. {
  24.     /**
  25.      * @var FileManager
  26.      */
  27.     private $fileManager;
  28.     /**
  29.      * @var AssetCatalog
  30.      */
  31.     private $assetCatalog;
  32.     /**
  33.      * @param Transcoder $transcoder
  34.      * @param SceneRenderer $sceneRenderer
  35.      * @param FileManager $fileManager
  36.      * @param AssetCatalog $assetCatalog
  37.      */
  38.     public function __construct(Transcoder $transcoderSceneRenderer $sceneRendererFileManager $fileManagerAssetCatalog $assetCatalog)
  39.     {
  40.         $this->fileManager $fileManager;
  41.         $this->assetCatalog $assetCatalog;
  42.     }
  43.     /**
  44.      * {@inheritdoc}
  45.      */
  46.     public function getFunctions(): array
  47.     {
  48.         $functions = array(
  49.             new TwigFunction(
  50.                 'cms_widgetChildren',
  51.                 array($this'functionWidgetChildren'),
  52.                 array(
  53.                     'needs_context' => true,
  54.                     'is_safe' => array(
  55.                         'all',
  56.                     ),
  57.                 )
  58.             ),
  59.             new TwigFunction(
  60.                 'cms_widgetContainer',
  61.                 array($this'functionWidgetContainer'),
  62.                 array(
  63.                     'is_safe' => array(
  64.                         'all',
  65.                     ),
  66.                 )
  67.             ),
  68.             new TwigFunction(
  69.                 'cms_widgetTrigger',
  70.                 array($this'functionWidgetTrigger'),
  71.                 array(
  72.                     'is_safe' => array(
  73.                         'all',
  74.                     ),
  75.                 )
  76.             ),
  77.             new TwigFunction(
  78.                 'cms_widgetRender',
  79.                 array($this'functionRenderWidget'),
  80.                 array(
  81.                     'needs_context' => true,
  82.                     'is_safe' => array(
  83.                         'all',
  84.                     ),
  85.                 )
  86.             ),
  87.             new TwigFunction(
  88.                 'cms_widgetsRender',
  89.                 array($this'functionRenderWidgets'),
  90.                 array(
  91.                     'needs_context' => true,
  92.                     'is_safe' => array(
  93.                         'all',
  94.                     ),
  95.                 )
  96.             ),
  97.             new TwigFunction(
  98.                 'cms_widgetsBuildInclude',
  99.                 array($this'cms_widgetsBuildInclude'),
  100.                 array(
  101.                     'needs_context' => true,
  102.                     'is_safe' => array(
  103.                         'all',
  104.                     ),
  105.                 )
  106.             ),
  107.             new TwigFunction(
  108.                 'cms_widgetsBaseInclude',
  109.                 array($this'cms_widgetsBaseInclude'),
  110.                 array(
  111.                     'needs_context' => true,
  112.                     'is_safe' => array(
  113.                         'all',
  114.                     ),
  115.                 )
  116.             ),
  117.         );
  118.         return $functions;
  119.     }
  120.     public function cms_widgetsBaseInclude(array $context$include)
  121.     {
  122.         // we should also have access to globals
  123.         if ( ! isset($context['_globals'])) {
  124.             throw new \Exception();
  125.         }
  126.         $globals $context['_globals'];
  127.         if ( ! $globals instanceof FrontendGlobals) {
  128.             throw new \Exception();
  129.         }
  130.         // return the determined include path
  131.         // TODO: make flexible base
  132.         return sprintf(
  133.             '@package$/%s',
  134.             ltrim($include'/')
  135.         );
  136.     }
  137.     /**
  138.      * @param array $context
  139.      * @param string $include
  140.      * @return string
  141.      * @throws \Exception
  142.      */
  143.     public function cms_widgetsBuildInclude(array $context$include)
  144.     {
  145.         // in the context, we should have a _loader; this function should only be used in widget rendering contexts
  146.         if ( ! isset($context['_loader'])) {
  147.             throw new \Exception();
  148.         }
  149.         $loader $context['_loader'];
  150.         if ( ! $loader instanceof DatabaseLoader) {
  151.             throw new \Exception();
  152.         }
  153.         // we should also have access to globals
  154.         if ( ! isset($context['_globals'])) {
  155.             throw new \Exception();
  156.         }
  157.         $globals $context['_globals'];
  158.         if ( ! $globals instanceof FrontendGlobals) {
  159.             throw new \Exception();
  160.         }
  161.         // return the determined include path
  162.         return $loader->determine(
  163.             $globals->getTheme(),
  164.             $include
  165.         );
  166.     }
  167.     /**
  168.      * @param Widget $handler
  169.      * @param array $options
  170.      * @param string $id
  171.      * @param array $styles
  172.      * @param array $scripts
  173.      * @return string
  174.      * @throws \Cms\CoreBundle\Service\Transcoding\TranscodingException
  175.      */
  176.     public function functionWidgetTrigger(Widget $handler, array $options$id, array $styles = [], array $scripts = [])
  177.     {
  178.         return json_encode(
  179.             array(
  180.                 'styles' => array_merge(
  181.                     $this->assetCatalog->expandAssets($handler->getStyles()),
  182.                     $styles
  183.                 ),
  184.                 'scripts' => array_merge(
  185.                     $this->assetCatalog->expandAssets($handler->getScripts()),
  186.                     $scripts
  187.                 ),
  188.                 'plugin' => ($handler->hasPlugin()) ? $handler->getKey() : null,
  189.                 'pluginId' => $id,
  190.                 'pluginOptions' => (object) $options,
  191.             ),
  192.             JSON_PRETTY_PRINT
  193.         );
  194.     }
  195.     /**
  196.      * @param array $context
  197.      * @param TranscodedObject $widget
  198.      * @return string
  199.      * @throws \Exception
  200.      */
  201.     public function functionRenderWidget(array $contextTranscodedObject $widget)
  202.     {
  203.         /** @var FrontendRenderer $renderer */
  204.         $renderer $context['_renderer'];
  205.         if ( ! $widget instanceof WidgetObject) {
  206.             throw new \Exception();
  207.         }
  208.         return $renderer->renderWidget($widget);
  209.     }
  210.     /**
  211.      * @param array $context
  212.      * @param array $widgets
  213.      * @return string
  214.      * @throws \Exception
  215.      */
  216.     public function functionRenderWidgets(array $context, array $widgets)
  217.     {
  218.         /** @var FrontendRenderer $renderer */
  219.         $renderer $context['_renderer'];
  220.         $output '';
  221.         foreach ($widgets as $widget) {
  222.             if ( ! $widget instanceof WidgetObject) {
  223.                 throw new \Exception();
  224.             }
  225.             $output .= $renderer->renderWidget($widget);
  226.         }
  227.         return $output;
  228.     }
  229.     /**
  230.      * @param array $context
  231.      * @param TranscodedObject $widget
  232.      * @return string
  233.      * @throws \Exception
  234.      */
  235.     public function functionWidgetChildren(array $contextTranscodedObject $widget)
  236.     {
  237.         /** @var FrontendRenderer $renderer */
  238.         $renderer $context['_renderer'];
  239.         /** @var WidgetObject $widget */
  240.         $children $widget->getChildren();
  241.         if ($children === null || (is_array($children) && count($children) === 0)) {
  242.             return '';
  243.         }
  244.         return $renderer->renderWidgets($children);
  245.     }
  246.     /**
  247.      * @param WidgetContainer $container
  248.      * @param string $defaultId
  249.      * @return string
  250.      * @throws \Exception
  251.      */
  252.     public function functionWidgetContainer(WidgetContainer $container null$defaultId)
  253.     {
  254.         // holders for styles and classes we need
  255.         $id '';
  256.         $styles = [];
  257.         $classes = [];
  258.         // do this part only if the container is not null
  259.         if ($container !== null) {
  260.             // handle id
  261.             if ( ! empty($container->getHtmlId())) {
  262.                 $id $container->getHtmlId();
  263.             }
  264.             // custom css classes
  265.             if ( ! empty($container->getCustomClasses())) {
  266.                 $classes array_merge(
  267.                     $classes,
  268.                     explode(' '$container->getCustomClasses())
  269.                 );
  270.             }
  271.             // background color
  272.             if ( ! empty($container->getBackgroundColor())) {
  273.                 $classes[] = 'bg-' $container->getBackgroundColor();
  274.             }
  275.             // background image
  276.             if ( ! empty($container->getBackgroundImage())) {
  277.                 $styles['background-image'] = sprintf(
  278.                     'url(\'%s\')',
  279.                     $this->fileManager->identUrl($container->getBackgroundImage())
  280.                 );
  281.                 $styles['background-size'] = $container->getBackgroundImageSize();
  282.                 $styles['background-repeat'] = $container->getBackgroundImageRepeat();
  283.                 $styles['background-position'] = $container->getBackgroundImagePosition();
  284.             }
  285.             // border width
  286.             if ( ! empty($container->getBorderWidth())) {
  287.                 $classes[] = 'b-' $container->getBorderWidth();
  288.             }
  289.             // border color
  290.             if ( ! empty($container->getBorderColor())) {
  291.                 $classes[] = 'b-' $container->getBorderColor();
  292.             }
  293.             // handle border styles
  294.             if ($container->getBorderStyleAdvanced() !== true) {
  295.                 if ( ! empty($container->getBorderStyle())) {
  296.                     $classes[] = 'b-' $container->getBorderStyle();
  297.                 }
  298.             } else {
  299.                 if ( ! empty($container->getBorderStyleTop())) {
  300.                     $classes[] = 'bt-' $container->getBorderStyleTop();
  301.                 }
  302.                 if ( ! empty($container->getBorderStyleBottom())) {
  303.                     $classes[] = 'bb-' $container->getBorderStyleBottom();
  304.                 }
  305.                 if ( ! empty($container->getBorderStyleLeft())) {
  306.                     $classes[] = 'bl-' $container->getBorderStyleLeft();
  307.                 }
  308.                 if ( ! empty($container->getBorderStyleRight())) {
  309.                     $classes[] = 'br-' $container->getBorderStyleRight();
  310.                 }
  311.             }
  312.             // handle padding
  313.             if ($container->getPaddingAdvanced() !== true) {
  314.                 if ( ! empty($container->getPadding())) {
  315.                     $classes[] = 'p-' $container->getPadding();
  316.                 }
  317.             } else {
  318.                 if ( ! empty($container->getPaddingTop())) {
  319.                     $classes[] = 'pt-' $container->getPaddingTop();
  320.                 }
  321.                 if ( ! empty($container->getPaddingBottom())) {
  322.                     $classes[] = 'pb-' $container->getPaddingBottom();
  323.                 }
  324.                 if ( ! empty($container->getPaddingLeft())) {
  325.                     $classes[] = 'pl-' $container->getPaddingLeft();
  326.                 }
  327.                 if ( ! empty($container->getPaddingRight())) {
  328.                     $classes[] = 'pr-' $container->getPaddingRight();
  329.                 }
  330.             }
  331.             // handle margin
  332.             if ($container->getMarginAdvanced() !== true) {
  333.                 if ( ! empty($container->getMargin())) {
  334.                     $classes[] = 'm-' $container->getMargin();
  335.                 }
  336.             } else {
  337.                 if ( ! empty($container->getMarginTop())) {
  338.                     $classes[] = 'mt-' $container->getMarginTop();
  339.                 }
  340.                 if ( ! empty($container->getMarginBottom())) {
  341.                     $classes[] = 'mb-' $container->getMarginBottom();
  342.                 }
  343.                 if ( ! empty($container->getMarginLeft())) {
  344.                     $classes[] = 'ml-' $container->getMarginLeft();
  345.                 }
  346.                 if ( ! empty($container->getMarginRight())) {
  347.                     $classes[] = 'mr-' $container->getMarginRight();
  348.                 }
  349.             }
  350.         }
  351.         // default id
  352.         if (empty($id)) {
  353.             $id $defaultId;
  354.         }
  355.         // compile final result
  356.         $result = [];
  357.         // handle id
  358.         if ( ! empty($id)) {
  359.             $result[] = 'id="'.trim(trim($id'#')).'"';
  360.         }
  361.         // handle classes
  362.         if (count($classes) > 0) {
  363.             $result[] = 'class="'.trim(implode(' '$classes)).'"';
  364.         }
  365.         // handle inline styles
  366.         if (count($styles) > 0) {
  367.             $result[] = 'style="'.trim(implode(' 'array_map(
  368.                 function($v$k)
  369.                 {
  370.                     return $k.': '.$v.';';
  371.                 },
  372.                 $styles,
  373.                 array_keys($styles)
  374.             ))).'"';
  375.         }
  376.         // send back container options
  377.         return trim(implode(' '$result));
  378.     }
  379. }