File indexing completed on 2024-12-22 05:37:13

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_View
0017  * @subpackage Helper
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @version    $Id$
0020  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0021  */
0022 
0023 /** Zend_View_Helper_Placeholder_Container_Standalone */
0024 // require_once 'Zend/View/Helper/Placeholder/Container/Standalone.php';
0025 
0026 /**
0027  * Helper for setting and retrieving stylesheets
0028  *
0029  * @uses       Zend_View_Helper_Placeholder_Container_Standalone
0030  * @package    Zend_View
0031  * @subpackage Helper
0032  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0033  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0034  * @method $this appendStyle($content, array $attributes = array())
0035  * @method $this offsetSetStyle($index, $content, array $attributes = array())
0036  * @method $this prependStyle($content, array $attributes = array())
0037  * @method $this setStyle($content, array $attributes = array())
0038  */
0039 class Zend_View_Helper_HeadStyle extends Zend_View_Helper_Placeholder_Container_Standalone
0040 {
0041     /**
0042      * Registry key for placeholder
0043      * @var string
0044      */
0045     protected $_regKey = 'Zend_View_Helper_HeadStyle';
0046 
0047     /**
0048      * Allowed optional attributes
0049      * @var array
0050      */
0051     protected $_optionalAttributes = array('lang', 'title', 'media', 'dir');
0052 
0053     /**
0054      * Allowed media types
0055      * @var array
0056      */
0057     protected $_mediaTypes = array(
0058         'all', 'aural', 'braille', 'handheld', 'print',
0059         'projection', 'screen', 'tty', 'tv'
0060     );
0061 
0062     /**
0063      * Capture type and/or attributes (used for hinting during capture)
0064      * @var string
0065      */
0066     protected $_captureAttrs = null;
0067 
0068     /**
0069      * Capture lock
0070      * @var bool
0071      */
0072     protected $_captureLock;
0073 
0074     /**
0075      * Capture type (append, prepend, set)
0076      * @var string
0077      */
0078     protected $_captureType;
0079 
0080     /**
0081      * Constructor
0082      *
0083      * Set separator to PHP_EOL.
0084      *
0085      * @return void
0086      */
0087     public function __construct()
0088     {
0089         parent::__construct();
0090         $this->setSeparator(PHP_EOL);
0091     }
0092 
0093     /**
0094      * Return headStyle object
0095      *
0096      * Returns headStyle helper object; optionally, allows specifying
0097      *
0098      * @param  string $content Stylesheet contents
0099      * @param  string $placement Append, prepend, or set
0100      * @param  string|array $attributes Optional attributes to utilize
0101      * @return Zend_View_Helper_HeadStyle
0102      */
0103     public function headStyle($content = null, $placement = 'APPEND', $attributes = array())
0104     {
0105         if ((null !== $content) && is_string($content)) {
0106             switch (strtoupper($placement)) {
0107                 case 'SET':
0108                     $action = 'setStyle';
0109                     break;
0110                 case 'PREPEND':
0111                     $action = 'prependStyle';
0112                     break;
0113                 case 'APPEND':
0114                 default:
0115                     $action = 'appendStyle';
0116                     break;
0117             }
0118             $this->$action($content, $attributes);
0119         }
0120 
0121         return $this;
0122     }
0123 
0124     /**
0125      * Overload method calls
0126      *
0127      * Allows the following method calls:
0128      * - appendStyle($content, $attributes = array())
0129      * - offsetSetStyle($index, $content, $attributes = array())
0130      * - prependStyle($content, $attributes = array())
0131      * - setStyle($content, $attributes = array())
0132      *
0133      * @param  string $method
0134      * @param  array $args
0135      * @return void
0136      * @throws Zend_View_Exception When no $content provided or invalid method
0137      */
0138     public function __call($method, $args)
0139     {
0140         if (preg_match('/^(?P<action>set|(ap|pre)pend|offsetSet)(Style)$/', $method, $matches)) {
0141             $index  = null;
0142             $argc   = count($args);
0143             $action = $matches['action'];
0144 
0145             if ('offsetSet' == $action) {
0146                 if (0 < $argc) {
0147                     $index = array_shift($args);
0148                     --$argc;
0149                 }
0150             }
0151 
0152             if (1 > $argc) {
0153                 // require_once 'Zend/View/Exception.php';
0154                 $e = new Zend_View_Exception(sprintf('Method "%s" requires minimally content for the stylesheet', $method));
0155                 $e->setView($this->view);
0156                 throw $e;
0157             }
0158 
0159             $content = $args[0];
0160             $attrs   = array();
0161             if (isset($args[1])) {
0162                 $attrs = (array) $args[1];
0163             }
0164 
0165             $item = $this->createData($content, $attrs);
0166 
0167             if ('offsetSet' == $action) {
0168                 $this->offsetSet($index, $item);
0169             } else {
0170                 $this->$action($item);
0171             }
0172 
0173             return $this;
0174         }
0175 
0176         return parent::__call($method, $args);
0177     }
0178 
0179     /**
0180      * Determine if a value is a valid style tag
0181      *
0182      * @param  mixed $value
0183      * @param  string $method
0184      * @return boolean
0185      */
0186     protected function _isValid($value)
0187     {
0188         if ((!$value instanceof stdClass)
0189             || !isset($value->content)
0190             || !isset($value->attributes))
0191         {
0192             return false;
0193         }
0194 
0195         return true;
0196     }
0197 
0198     /**
0199      * Override append to enforce style creation
0200      *
0201      * @param  mixed $value
0202      * @return void
0203      */
0204     public function append($value)
0205     {
0206         if (!$this->_isValid($value)) {
0207             // require_once 'Zend/View/Exception.php';
0208             $e = new Zend_View_Exception('Invalid value passed to append; please use appendStyle()');
0209             $e->setView($this->view);
0210             throw $e;
0211         }
0212 
0213         return $this->getContainer()->append($value);
0214     }
0215 
0216     /**
0217      * Override offsetSet to enforce style creation
0218      *
0219      * @param  string|int $index
0220      * @param  mixed $value
0221      * @return void
0222      */
0223     public function offsetSet($index, $value)
0224     {
0225         if (!$this->_isValid($value)) {
0226             // require_once 'Zend/View/Exception.php';
0227             $e = new Zend_View_Exception('Invalid value passed to offsetSet; please use offsetSetStyle()');
0228             $e->setView($this->view);
0229             throw $e;
0230         }
0231 
0232         return $this->getContainer()->offsetSet($index, $value);
0233     }
0234 
0235     /**
0236      * Override prepend to enforce style creation
0237      *
0238      * @param  mixed $value
0239      * @return void
0240      */
0241     public function prepend($value)
0242     {
0243         if (!$this->_isValid($value)) {
0244             // require_once 'Zend/View/Exception.php';
0245             $e = new Zend_View_Exception('Invalid value passed to prepend; please use prependStyle()');
0246             $e->setView($this->view);
0247             throw $e;
0248         }
0249 
0250         return $this->getContainer()->prepend($value);
0251     }
0252 
0253     /**
0254      * Override set to enforce style creation
0255      *
0256      * @param  mixed $value
0257      * @return void
0258      */
0259     public function set($value)
0260     {
0261         if (!$this->_isValid($value)) {
0262             // require_once 'Zend/View/Exception.php';
0263             $e = new Zend_View_Exception('Invalid value passed to set; please use setStyle()');
0264             $e->setView($this->view);
0265             throw $e;
0266         }
0267 
0268         return $this->getContainer()->set($value);
0269     }
0270 
0271     /**
0272      * Start capture action
0273      *
0274      * @param  mixed $captureType
0275      * @param  string $typeOrAttrs
0276      * @return void
0277      */
0278     public function captureStart($type = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $attrs = null)
0279     {
0280         if ($this->_captureLock) {
0281             // require_once 'Zend/View/Helper/Placeholder/Container/Exception.php';
0282             $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest headStyle captures');
0283             $e->setView($this->view);
0284             throw $e;
0285         }
0286 
0287         $this->_captureLock        = true;
0288         $this->_captureAttrs       = $attrs;
0289         $this->_captureType        = $type;
0290         ob_start();
0291     }
0292 
0293     /**
0294      * End capture action and store
0295      *
0296      * @return void
0297      */
0298     public function captureEnd()
0299     {
0300         $content             = ob_get_clean();
0301         $attrs               = $this->_captureAttrs;
0302         $this->_captureAttrs = null;
0303         $this->_captureLock  = false;
0304 
0305         switch ($this->_captureType) {
0306             case Zend_View_Helper_Placeholder_Container_Abstract::SET:
0307                 $this->setStyle($content, $attrs);
0308                 break;
0309             case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND:
0310                 $this->prependStyle($content, $attrs);
0311                 break;
0312             case Zend_View_Helper_Placeholder_Container_Abstract::APPEND:
0313             default:
0314                 $this->appendStyle($content, $attrs);
0315                 break;
0316         }
0317     }
0318 
0319     /**
0320      * Convert content and attributes into valid style tag
0321      *
0322      * @param  stdClass $item Item to render
0323      * @param  string $indent Indentation to use
0324      * @return string
0325      */
0326     public function itemToString(stdClass $item, $indent)
0327     {
0328         $attrString = '';
0329         if (!empty($item->attributes)) {
0330             $enc = 'UTF-8';
0331             if ($this->view instanceof Zend_View_Interface
0332                 && method_exists($this->view, 'getEncoding')
0333             ) {
0334                 $enc = $this->view->getEncoding();
0335             }
0336             foreach ($item->attributes as $key => $value) {
0337                 if (!in_array($key, $this->_optionalAttributes)) {
0338                     continue;
0339                 }
0340                 if ('media' == $key) {
0341                     if(false === strpos($value, ',')) {
0342                         if (!in_array($value, $this->_mediaTypes)) {
0343                             continue;
0344                         }
0345                     } else {
0346                         $media_types = explode(',', $value);
0347                         $value = '';
0348                         foreach($media_types as $type) {
0349                             $type = trim($type);
0350                             if (!in_array($type, $this->_mediaTypes)) {
0351                                 continue;
0352                             }
0353                             $value .= $type .',';
0354                         }
0355                         $value = substr($value, 0, -1);
0356                     }
0357                 }
0358                 $attrString .= sprintf(' %s="%s"', $key, htmlspecialchars($value, ENT_COMPAT, $enc));
0359             }
0360         }
0361 
0362         $escapeStart = $indent . '<!--'. PHP_EOL;
0363         $escapeEnd = $indent . '-->'. PHP_EOL;
0364         if (isset($item->attributes['conditional'])
0365             && !empty($item->attributes['conditional'])
0366             && is_string($item->attributes['conditional'])
0367         ) {
0368             $escapeStart = null;
0369             $escapeEnd = null;
0370         }
0371 
0372         $html = '<style type="text/css"' . $attrString . '>' . PHP_EOL
0373               . $escapeStart . $indent . $item->content . PHP_EOL . $escapeEnd
0374               . '</style>';
0375 
0376         if (null == $escapeStart && null == $escapeEnd) {
0377             if (str_replace(' ', '', $item->attributes['conditional']) === '!IE') {
0378                 $html = '<!-->' . $html . '<!--';
0379             }
0380             $html = '<!--[if ' . $item->attributes['conditional'] . ']>' . $html . '<![endif]-->';
0381         }
0382 
0383         return $html;
0384     }
0385 
0386     /**
0387      * Create string representation of placeholder
0388      *
0389      * @param  string|int $indent
0390      * @return string
0391      */
0392     public function toString($indent = null)
0393     {
0394         $indent = (null !== $indent)
0395                 ? $this->getWhitespace($indent)
0396                 : $this->getIndent();
0397 
0398         $items = array();
0399         $this->getContainer()->ksort();
0400         foreach ($this as $item) {
0401             if (!$this->_isValid($item)) {
0402                 continue;
0403             }
0404             $items[] = $this->itemToString($item, $indent);
0405         }
0406 
0407         $return = $indent . implode($this->getSeparator() . $indent, $items);
0408         $return = preg_replace("/(\r\n?|\n)/", '$1' . $indent, $return);
0409         return $return;
0410     }
0411 
0412     /**
0413      * Create data item for use in stack
0414      *
0415      * @param  string $content
0416      * @param  array $attributes
0417      * @return stdClass
0418      */
0419     public function createData($content, array $attributes)
0420     {
0421         if (!isset($attributes['media'])) {
0422             $attributes['media'] = 'screen';
0423         } else if(is_array($attributes['media'])) {
0424             $attributes['media'] = implode(',', $attributes['media']);
0425         }
0426 
0427         $data = new stdClass();
0428         $data->content    = $content;
0429         $data->attributes = $attributes;
0430 
0431         return $data;
0432     }
0433 }