vendor/pimcore/pimcore/lib/Twig/Extension/Templating/HeadMeta.php line 456

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. /**
  15.  * ----------------------------------------------------------------------------------
  16.  * based on @author ZF1 Zend_View_Helper_HeadMeta
  17.  * ----------------------------------------------------------------------------------
  18.  */
  19. /**
  20.  * Zend Framework
  21.  *
  22.  * LICENSE
  23.  *
  24.  * This source file is subject to the new BSD license that is bundled
  25.  * with this package in the file LICENSE.txt.
  26.  * It is also available through the world-wide-web at this URL:
  27.  * http://framework.zend.com/license/new-bsd
  28.  * If you did not receive a copy of the license and are unable to
  29.  * obtain it through the world-wide-web, please send an email
  30.  * to license@zend.com so we can send you a copy immediately.
  31.  *
  32.  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  33.  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  34.  */
  35. namespace Pimcore\Twig\Extension\Templating;
  36. use Pimcore\Twig\Extension\Templating\Placeholder\AbstractExtension;
  37. use Pimcore\Twig\Extension\Templating\Placeholder\Container;
  38. use Pimcore\Twig\Extension\Templating\Placeholder\ContainerService;
  39. use Pimcore\Twig\Extension\Templating\Placeholder\Exception;
  40. use Pimcore\Twig\Extension\Templating\Traits\TextUtilsTrait;
  41. use Twig\Extension\RuntimeExtensionInterface;
  42. /**
  43.  * @method $this appendHttpEquiv($keyValue, $content, $conditionalHttpEquiv=[])
  44.  * @method $this appendName($keyValue, $content, $conditionalName=[])
  45.  * @method $this appendProperty($property, $content, $modifiers=[])
  46.  * @method $this offsetSetHttpEquiv($index, $keyValue, $content, $conditionalHttpEquiv=[])
  47.  * @method $this offsetSetName($index, $keyValue, $content, $conditionalName=[])
  48.  * @method $this offsetSetProperty($index, $property, $content, $modifiers=[])
  49.  * @method $this prependHttpEquiv($keyValue, $content, $conditionalHttpEquiv=[])
  50.  * @method $this prependName($keyValue, $content, $conditionalName=[])
  51.  * @method $this prependProperty($property, $content, $modifiers=[])
  52.  * @method $this setHttpEquiv($keyValue, $content, $modifiers=[])
  53.  * @method $this setName($keyValue, $content, $modifiers=[])
  54.  * @method $this setProperty($property, $content, $modifiers=[])
  55.  *
  56.  */
  57. class HeadMeta extends AbstractExtension implements RuntimeExtensionInterface
  58. {
  59.     use TextUtilsTrait;
  60.     /**
  61.      * Types of attributes
  62.      *
  63.      * @var array
  64.      */
  65.     protected $_typeKeys = ['name', 'http-equiv', 'charset', 'property'];
  66.     protected $_requiredKeys = ['content'];
  67.     protected $_modifierKeys = ['lang', 'scheme'];
  68.     protected $rawItems = [];
  69.     /**
  70.      * @var string registry key
  71.      */
  72.     protected $_regKey = 'HeadMeta';
  73.     /**
  74.      * HeadMeta constructor.
  75.      *
  76.      * Set separator to PHP_EOL.
  77.      *
  78.      * @param ContainerService $containerService
  79.      */
  80.     public function __construct(ContainerService $containerService)
  81.     {
  82.         parent::__construct($containerService);
  83.         $this->setSeparator(PHP_EOL);
  84.     }
  85.     /**
  86.      * Retrieve object instance; optionally add meta tag
  87.      *
  88.      * @param  string $content
  89.      * @param  string $keyValue
  90.      * @param  string $keyType
  91.      * @param  array $modifiers
  92.      * @param  string $placement
  93.      *
  94.      * @return HeadMeta
  95.      */
  96.     public function __invoke($content = null, $keyValue = null, $keyType = 'name', $modifiers = [], $placement = Container::APPEND)
  97.     {
  98.         if ((null !== $content) && (null !== $keyValue)) {
  99.             $item = $this->createData($keyType, $keyValue, $content, $modifiers);
  100.             $action = strtolower($placement);
  101.             switch ($action) {
  102.                 case 'append':
  103.                 case 'prepend':
  104.                 case 'set':
  105.                     $this->$action($item);
  106.                     break;
  107.                 default:
  108.                     $this->append($item);
  109.                     break;
  110.             }
  111.         }
  112.         return $this;
  113.     }
  114.     protected function _normalizeType($type)
  115.     {
  116.         switch ($type) {
  117.             case 'Name':
  118.                 return 'name';
  119.             case 'HttpEquiv':
  120.                 return 'http-equiv';
  121.             case 'Property':
  122.                 return 'property';
  123.             default:
  124.                 throw new Exception(sprintf('Invalid type "%s" passed to _normalizeType', $type));
  125.         }
  126.     }
  127.     /**
  128.      * @param string $type
  129.      * @param string $keyValue
  130.      *
  131.      * @return mixed
  132.      */
  133.     public function getItem($type, $keyValue)
  134.     {
  135.         foreach ($this->getContainer() as $item) {
  136.             if (isset($item->$type) && $item->$type == $keyValue) {
  137.                 return $item->content;
  138.             }
  139.         }
  140.     }
  141.     /**
  142.      * Overload method access
  143.      *
  144.      * Allows the following 'virtual' methods:
  145.      * - appendName($keyValue, $content, $modifiers = array())
  146.      * - prependName($keyValue, $content, $modifiers = array())
  147.      * - setName($keyValue, $content, $modifiers = array())
  148.      * - appendHttpEquiv($keyValue, $content, $modifiers = array())
  149.      * - prependHttpEquiv($keyValue, $content, $modifiers = array())
  150.      * - setHttpEquiv($keyValue, $content, $modifiers = array())
  151.      * - appendProperty($keyValue, $content, $modifiers = array())
  152.      * - prependProperty($keyValue, $content, $modifiers = array())
  153.      * - setProperty($keyValue, $content, $modifiers = array())
  154.      *
  155.      * @param  string $method
  156.      * @param  array $args
  157.      *
  158.      * @return HeadMeta
  159.      */
  160.     public function __call($method, $args)
  161.     {
  162.         if (preg_match('/^(?P<action>set|(pre|ap)pend|offsetSet)(?P<type>Name|HttpEquiv|Property)$/', $method, $matches)) {
  163.             $action = $matches['action'];
  164.             $type = $this->_normalizeType($matches['type']);
  165.             $argc = count($args);
  166.             $index = null;
  167.             if ('offsetSet' == $action) {
  168.                 if (0 < $argc) {
  169.                     $index = array_shift($args);
  170.                     --$argc;
  171.                 }
  172.             }
  173.             if (2 > $argc) {
  174.                 throw new Exception('Too few arguments provided; requires key value, and content');
  175.             }
  176.             if (3 > $argc) {
  177.                 $args[] = [];
  178.             }
  179.             $item = $this->createData($type, $args[0], $args[1], $args[2]);
  180.             if ('offsetSet' == $action) {
  181.                 $this->offsetSet($index, $item);
  182.                 return $this;
  183.             }
  184.             $this->$action($item);
  185.             return $this;
  186.         }
  187.         return parent::__call($method, $args);
  188.     }
  189.     /**
  190.      * Determine if item is valid
  191.      *
  192.      * @param  mixed $item
  193.      *
  194.      * @return bool
  195.      */
  196.     protected function _isValid($item)
  197.     {
  198.         return true;
  199.     }
  200.     /**
  201.      * Append
  202.      *
  203.      * @param  string $value
  204.      *
  205.      * @return void
  206.      *
  207.      * @throws Exception
  208.      */
  209.     public function append($value)
  210.     {
  211.         if (!$this->_isValid($value)) {
  212.             throw new Exception('Invalid value passed to append; please use appendMeta()');
  213.         }
  214.         $this->getContainer()->append($value);
  215.     }
  216.     /**
  217.      * OffsetSet
  218.      *
  219.      * @param  string|int $index
  220.      * @param  string $value
  221.      *
  222.      * @return void
  223.      *
  224.      * @throws Exception
  225.      */
  226.     #[\ReturnTypeWillChange]
  227.     public function offsetSet($index, $value)// : void
  228.     {
  229.         if (!$this->_isValid($value)) {
  230.             throw new Exception('Invalid value passed to offsetSet; please use offsetSetName() or offsetSetHttpEquiv()');
  231.         }
  232.         $this->getContainer()->offsetSet($index, $value);
  233.     }
  234.     /**
  235.      * OffsetUnset
  236.      *
  237.      * @param  string|int $index
  238.      *
  239.      * @return void
  240.      *
  241.      * @throws Exception
  242.      */
  243.     #[\ReturnTypeWillChange]
  244.     public function offsetUnset($index)// : void
  245.     {
  246.         if (!in_array($index, $this->getContainer()->getKeys())) {
  247.             throw new Exception('Invalid index passed to offsetUnset()');
  248.         }
  249.         $this->getContainer()->offsetUnset($index);
  250.     }
  251.     /**
  252.      * Prepend
  253.      *
  254.      * @param  string $value
  255.      *
  256.      * @return void
  257.      *
  258.      * @throws Exception
  259.      */
  260.     public function prepend($value)
  261.     {
  262.         if (!$this->_isValid($value)) {
  263.             throw new Exception('Invalid value passed to prepend; please use prependMeta()');
  264.         }
  265.         $this->getContainer()->prepend($value);
  266.     }
  267.     /**
  268.      * Set
  269.      *
  270.      * @param mixed $value
  271.      *
  272.      * @return void
  273.      *
  274.      * @throws Exception
  275.      */
  276.     public function set($value)
  277.     {
  278.         if (!$this->_isValid($value)) {
  279.             throw new Exception('Invalid value passed to set; please use setMeta()');
  280.         }
  281.         $container = $this->getContainer();
  282.         foreach ($container->getArrayCopy() as $index => $item) {
  283.             if ($item->type == $value->type && $item->{$item->type} == $value->{$value->type}) {
  284.                 $this->offsetUnset($index);
  285.             }
  286.         }
  287.         $this->append($value);
  288.     }
  289.     /**
  290.      * Build meta HTML string
  291.      *
  292.      * @param \stdClass $item
  293.      *
  294.      * @return string
  295.      */
  296.     public function itemToString(\stdClass $item)
  297.     {
  298.         if (!in_array($item->type, $this->_typeKeys)) {
  299.             throw new Exception(sprintf('Invalid type "%s" provided for meta', $item->type));
  300.         }
  301.         $type = $item->type;
  302.         $modifiersString = '';
  303.         foreach ($item->modifiers as $key => $value) {
  304.             if (!in_array($key, $this->_modifierKeys)) {
  305.                 continue;
  306.             }
  307.             $modifiersString .= $key . '="' . $this->_escape($value) . '" ';
  308.         }
  309.         $tpl = '<meta %s="%s" content="%s" %s/>';
  310.         $meta = sprintf(
  311.             $tpl,
  312.             $type,
  313.             $this->_escape($item->$type),
  314.             $this->_escape($item->content),
  315.             $modifiersString
  316.         );
  317.         if (isset($item->modifiers['conditional'])
  318.             && !empty($item->modifiers['conditional'])
  319.             && is_string($item->modifiers['conditional'])) {
  320.             if (str_replace(' ', '', $item->modifiers['conditional']) === '!IE') {
  321.                 $meta = '<!-->' . $meta . '<!--';
  322.             }
  323.             $meta = '<!--[if ' . $this->_escape($item->modifiers['conditional']) . ']>' . $meta . '<![endif]-->';
  324.         }
  325.         return $meta;
  326.     }
  327.     /**
  328.      * Render placeholder as string
  329.      *
  330.      * @param  string|int $indent
  331.      *
  332.      * @return string
  333.      */
  334.     public function toString($indent = null)
  335.     {
  336.         $indent = (null !== $indent)
  337.             ? $this->getWhitespace($indent)
  338.             : $this->getIndent();
  339.         $items = [];
  340.         $this->getContainer()->ksort();
  341.         try {
  342.             foreach ($this as $item) {
  343.                 $items[] = $this->itemToString($item);
  344.             }
  345.         } catch (Exception $e) {
  346.             trigger_error($e->getMessage(), E_USER_WARNING);
  347.             return '';
  348.         }
  349.         $metaString = $indent . implode($this->_escape($this->getSeparator()) . $indent, $items);
  350.         // add raw items
  351.         $separator = $this->_escape($this->getSeparator()) . $indent;
  352.         $metaString .= ($separator . implode($separator, $this->rawItems));
  353.         return $metaString;
  354.     }
  355.     /**
  356.      * Create data item for inserting into stack
  357.      *
  358.      * @param  string $type
  359.      * @param  string $typeValue
  360.      * @param  string $content
  361.      * @param  array $modifiers
  362.      *
  363.      * @return \stdClass
  364.      */
  365.     public function createData($type, $typeValue, $content, array $modifiers)
  366.     {
  367.         $data = new \stdClass;
  368.         $data->type = $type;
  369.         $data->$type = $typeValue;
  370.         $data->content = $content;
  371.         $data->modifiers = $modifiers;
  372.         return $data;
  373.     }
  374.     /**
  375.      * @param string $html
  376.      *
  377.      * @return $this
  378.      */
  379.     public function addRaw($html)
  380.     {
  381.         $this->rawItems[] = $html;
  382.         return $this;
  383.     }
  384.     /**
  385.      * @return array
  386.      */
  387.     public function getRaw()
  388.     {
  389.         return $this->rawItems;
  390.     }
  391.     /**
  392.      * @param string $string
  393.      * @param int $length
  394.      * @param string $suffix
  395.      *
  396.      * @return $this
  397.      */
  398.     public function setDescription($string, $length = null, $suffix = '')
  399.     {
  400.         $string = $this->normalizeString($string, $length, $suffix);
  401.         return $this->setName('description', $string);
  402.     }
  403. }