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  * Zend_Layout_View_Helper_HeadLink
0028  *
0029  * @see        http://www.w3.org/TR/xhtml1/dtds.html
0030  * @uses       Zend_View_Helper_Placeholder_Container_Standalone
0031  * @package    Zend_View
0032  * @subpackage Helper
0033  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0034  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0035  * @method $this appendAlternate($href, $type, $title, $extras)
0036  * @method $this appendStylesheet($href, $media = 'screen', $conditionalStylesheet = false, array $extras = array())
0037  * @method $this offsetSetAlternate($index, $href, $type, $title, $extras)
0038  * @method $this offsetSetStylesheet($index, $href, $media = 'screen', $conditionalStylesheet = false, array $extras = array())
0039  * @method $this prependAlternate($href, $type, $title, $extras)
0040  * @method $this prependStylesheet($href, $media = 'screen', $conditionalStylesheet = false, array $extras = array())
0041  * @method $this setAlternate($href, $type, $title, $extras)
0042  * @method $this setStylesheet($href, $media = 'screen', $conditionalStylesheet = false, array $extras = array())
0043  */
0044 class Zend_View_Helper_HeadLink extends Zend_View_Helper_Placeholder_Container_Standalone
0045 {
0046     /**
0047      * $_validAttributes
0048      *
0049      * @var array
0050      */
0051     protected $_itemKeys = array(
0052         'charset',
0053         'href',
0054         'hreflang',
0055         'id',
0056         'media',
0057         'rel',
0058         'rev',
0059         'type',
0060         'title',
0061         'extras',
0062         'sizes',
0063     );
0064 
0065     /**
0066      * @var string registry key
0067      */
0068     protected $_regKey = 'Zend_View_Helper_HeadLink';
0069 
0070     /**
0071      * Constructor
0072      *
0073      * Use PHP_EOL as separator
0074      *
0075      * @return void
0076      */
0077     public function __construct()
0078     {
0079         parent::__construct();
0080         $this->setSeparator(PHP_EOL);
0081     }
0082 
0083     /**
0084      * headLink() - View Helper Method
0085      *
0086      * Returns current object instance. Optionally, allows passing array of
0087      * values to build link.
0088      *
0089      * @return Zend_View_Helper_HeadLink
0090      */
0091     public function headLink(array $attributes = null, $placement = Zend_View_Helper_Placeholder_Container_Abstract::APPEND)
0092     {
0093         if (null !== $attributes) {
0094             $item = $this->createData($attributes);
0095             switch ($placement) {
0096                 case Zend_View_Helper_Placeholder_Container_Abstract::SET:
0097                     $this->set($item);
0098                     break;
0099                 case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND:
0100                     $this->prepend($item);
0101                     break;
0102                 case Zend_View_Helper_Placeholder_Container_Abstract::APPEND:
0103                 default:
0104                     $this->append($item);
0105                     break;
0106             }
0107         }
0108         return $this;
0109     }
0110 
0111     /**
0112      * Overload method access
0113      *
0114      * Creates the following virtual methods:
0115      * - appendStylesheet($href, $media, $conditionalStylesheet, $extras)
0116      * - offsetSetStylesheet($index, $href, $media, $conditionalStylesheet, $extras)
0117      * - prependStylesheet($href, $media, $conditionalStylesheet, $extras)
0118      * - setStylesheet($href, $media, $conditionalStylesheet, $extras)
0119      * - appendAlternate($href, $type, $title, $extras)
0120      * - offsetSetAlternate($index, $href, $type, $title, $extras)
0121      * - prependAlternate($href, $type, $title, $extras)
0122      * - setAlternate($href, $type, $title, $extras)
0123      *
0124      * Items that may be added in the future:
0125      * - Navigation?  need to find docs on this
0126      *   - public function appendStart()
0127      *   - public function appendContents()
0128      *   - public function appendPrev()
0129      *   - public function appendNext()
0130      *   - public function appendIndex()
0131      *   - public function appendEnd()
0132      *   - public function appendGlossary()
0133      *   - public function appendAppendix()
0134      *   - public function appendHelp()
0135      *   - public function appendBookmark()
0136      * - Other?
0137      *   - public function appendCopyright()
0138      *   - public function appendChapter()
0139      *   - public function appendSection()
0140      *   - public function appendSubsection()
0141      *
0142      * @param mixed $method
0143      * @param mixed $args
0144      * @return void
0145      */
0146     public function __call($method, $args)
0147     {
0148         if (preg_match('/^(?P<action>set|(ap|pre)pend|offsetSet)(?P<type>Stylesheet|Alternate)$/', $method, $matches)) {
0149             $argc   = count($args);
0150             $action = $matches['action'];
0151             $type   = $matches['type'];
0152             $index  = null;
0153 
0154             if ('offsetSet' == $action) {
0155                 if (0 < $argc) {
0156                     $index = array_shift($args);
0157                     --$argc;
0158                 }
0159             }
0160 
0161             if (1 > $argc) {
0162                 // require_once 'Zend/View/Exception.php';
0163                 $e =  new Zend_View_Exception(sprintf('%s requires at least one argument', $method));
0164                 $e->setView($this->view);
0165                 throw $e;
0166             }
0167 
0168             if (is_array($args[0])) {
0169                 $item = $this->createData($args[0]);
0170             } else {
0171                 $dataMethod = 'createData' . $type;
0172                 $item       = $this->$dataMethod($args);
0173             }
0174 
0175             if ($item) {
0176                 if ('offsetSet' == $action) {
0177                     $this->offsetSet($index, $item);
0178                 } else {
0179                     $this->$action($item);
0180                 }
0181             }
0182 
0183             return $this;
0184         }
0185 
0186         return parent::__call($method, $args);
0187     }
0188 
0189     /**
0190      * Check if value is valid
0191      *
0192      * @param  mixed $value
0193      * @return boolean
0194      */
0195     protected function _isValid($value)
0196     {
0197         if (!$value instanceof stdClass) {
0198             return false;
0199         }
0200 
0201         $vars         = get_object_vars($value);
0202         $keys         = array_keys($vars);
0203         $intersection = array_intersect($this->_itemKeys, $keys);
0204         if (empty($intersection)) {
0205             return false;
0206         }
0207 
0208         return true;
0209     }
0210 
0211     /**
0212      * append()
0213      *
0214      * @param  array $value
0215      * @return void
0216      */
0217     public function append($value)
0218     {
0219         if (!$this->_isValid($value)) {
0220             // require_once 'Zend/View/Exception.php';
0221             $e = new Zend_View_Exception('append() expects a data token; please use one of the custom append*() methods');
0222             $e->setView($this->view);
0223             throw $e;
0224         }
0225 
0226         return $this->getContainer()->append($value);
0227     }
0228 
0229     /**
0230      * offsetSet()
0231      *
0232      * @param  string|int $index
0233      * @param  array $value
0234      * @return void
0235      */
0236     public function offsetSet($index, $value)
0237     {
0238         if (!$this->_isValid($value)) {
0239             // require_once 'Zend/View/Exception.php';
0240             $e = new Zend_View_Exception('offsetSet() expects a data token; please use one of the custom offsetSet*() methods');
0241             $e->setView($this->view);
0242             throw $e;
0243         }
0244 
0245         return $this->getContainer()->offsetSet($index, $value);
0246     }
0247 
0248     /**
0249      * prepend()
0250      *
0251      * @param  array $value
0252      * @return Zend_Layout_ViewHelper_HeadLink
0253      */
0254     public function prepend($value)
0255     {
0256         if (!$this->_isValid($value)) {
0257             // require_once 'Zend/View/Exception.php';
0258             $e = new Zend_View_Exception('prepend() expects a data token; please use one of the custom prepend*() methods');
0259             $e->setView($this->view);
0260             throw $e;
0261         }
0262 
0263         return $this->getContainer()->prepend($value);
0264     }
0265 
0266     /**
0267      * set()
0268      *
0269      * @param  array $value
0270      * @return Zend_Layout_ViewHelper_HeadLink
0271      */
0272     public function set($value)
0273     {
0274         if (!$this->_isValid($value)) {
0275             // require_once 'Zend/View/Exception.php';
0276             $e = new Zend_View_Exception('set() expects a data token; please use one of the custom set*() methods');
0277             $e->setView($this->view);
0278             throw $e;
0279         }
0280 
0281         return $this->getContainer()->set($value);
0282     }
0283 
0284 
0285     /**
0286      * Create HTML link element from data item
0287      *
0288      * @param  stdClass $item
0289      * @return string
0290      */
0291     public function itemToString(stdClass $item)
0292     {
0293         $attributes = (array) $item;
0294         $link       = '<link ';
0295 
0296         foreach ($this->_itemKeys as $itemKey) {
0297             if (isset($attributes[$itemKey])) {
0298                 if(is_array($attributes[$itemKey])) {
0299                     foreach($attributes[$itemKey] as $key => $value) {
0300                         $link .= sprintf('%s="%s" ', $key, ($this->_autoEscape) ? $this->_escape($value) : $value);
0301                     }
0302                 } else {
0303                     $link .= sprintf('%s="%s" ', $itemKey, ($this->_autoEscape) ? $this->_escape($attributes[$itemKey]) : $attributes[$itemKey]);
0304                 }
0305             }
0306         }
0307 
0308         if ($this->view instanceof Zend_View_Abstract) {
0309             $link .= ($this->view->doctype()->isXhtml()) ? '/>' : '>';
0310         } else {
0311             $link .= '/>';
0312         }
0313 
0314         if (($link == '<link />') || ($link == '<link >')) {
0315             return '';
0316         }
0317 
0318         if (isset($attributes['conditionalStylesheet'])
0319             && !empty($attributes['conditionalStylesheet'])
0320             && is_string($attributes['conditionalStylesheet']))
0321         {
0322             if (str_replace(' ', '', $attributes['conditionalStylesheet']) === '!IE') {
0323                 $link = '<!-->' . $link . '<!--';
0324             }
0325             $link = '<!--[if ' . $attributes['conditionalStylesheet'] . ']>' . $link . '<![endif]-->';
0326         }
0327 
0328         return $link;
0329     }
0330 
0331     /**
0332      * Render link elements as string
0333      *
0334      * @param  string|int $indent
0335      * @return string
0336      */
0337     public function toString($indent = null)
0338     {
0339         $indent = (null !== $indent)
0340                 ? $this->getWhitespace($indent)
0341                 : $this->getIndent();
0342 
0343         $items = array();
0344         $this->getContainer()->ksort();
0345         foreach ($this as $item) {
0346             $items[] = $this->itemToString($item);
0347         }
0348 
0349         return $indent . implode($this->_escape($this->getSeparator()) . $indent, $items);
0350     }
0351 
0352     /**
0353      * Create data item for stack
0354      *
0355      * @param  array $attributes
0356      * @return stdClass
0357      */
0358     public function createData(array $attributes)
0359     {
0360         $data = (object) $attributes;
0361         return $data;
0362     }
0363 
0364     /**
0365      * Create item for stylesheet link item
0366      *
0367      * @param  array $args
0368      * @return stdClass|false Returns fals if stylesheet is a duplicate
0369      */
0370     public function createDataStylesheet(array $args)
0371     {
0372         $rel                   = 'stylesheet';
0373         $type                  = 'text/css';
0374         $media                 = 'screen';
0375         $conditionalStylesheet = false;
0376         $href                  = array_shift($args);
0377 
0378         if ($this->_isDuplicateStylesheet($href)) {
0379             return false;
0380         }
0381 
0382         if (0 < count($args)) {
0383             $media = array_shift($args);
0384             if(is_array($media)) {
0385                 $media = implode(',', $media);
0386             } else {
0387                 $media = (string) $media;
0388             }
0389         }
0390         if (0 < count($args)) {
0391             $conditionalStylesheet = array_shift($args);
0392             if(!empty($conditionalStylesheet) && is_string($conditionalStylesheet)) {
0393                 $conditionalStylesheet = (string) $conditionalStylesheet;
0394             } else {
0395                 $conditionalStylesheet = null;
0396             }
0397         }
0398 
0399         if(0 < count($args) && is_array($args[0])) {
0400             $extras = array_shift($args);
0401             $extras = (array) $extras;
0402         }
0403 
0404         $attributes = compact('rel', 'type', 'href', 'media', 'conditionalStylesheet', 'extras');
0405         return $this->createData($this->_applyExtras($attributes));
0406     }
0407 
0408     /**
0409      * Is the linked stylesheet a duplicate?
0410      *
0411      * @param  string $uri
0412      * @return bool
0413      */
0414     protected function _isDuplicateStylesheet($uri)
0415     {
0416         foreach ($this->getContainer() as $item) {
0417             if (($item->rel == 'stylesheet') && ($item->href == $uri)) {
0418                 return true;
0419             }
0420         }
0421         return false;
0422     }
0423 
0424     /**
0425      * Create item for alternate link item
0426      *
0427      * @param  array $args
0428      * @return stdClass
0429      */
0430     public function createDataAlternate(array $args)
0431     {
0432         if (3 > count($args)) {
0433             // require_once 'Zend/View/Exception.php';
0434             $e = new Zend_View_Exception(sprintf('Alternate tags require 3 arguments; %s provided', count($args)));
0435             $e->setView($this->view);
0436             throw $e;
0437         }
0438 
0439         $rel   = 'alternate';
0440         $href  = array_shift($args);
0441         $type  = array_shift($args);
0442         $title = array_shift($args);
0443 
0444         if(0 < count($args) && is_array($args[0])) {
0445             $extras = array_shift($args);
0446             $extras = (array) $extras;
0447 
0448             if(isset($extras['media']) && is_array($extras['media'])) {
0449                 $extras['media'] = implode(',', $extras['media']);
0450             }
0451         }
0452 
0453         $href  = (string) $href;
0454         $type  = (string) $type;
0455         $title = (string) $title;
0456 
0457         $attributes = compact('rel', 'href', 'type', 'title', 'extras');
0458         return $this->createData($this->_applyExtras($attributes));
0459     }
0460 
0461     /**
0462      * Apply any overrides specified in the 'extras' array
0463      * @param array $attributes
0464      * @return array
0465      */
0466     protected function _applyExtras($attributes)
0467     {
0468         if (isset($attributes['extras'])) {
0469             foreach ($attributes['extras'] as $eKey=>$eVal) {
0470                 if (isset($attributes[$eKey])) {
0471                     $attributes[$eKey] = $eVal;
0472                     unset($attributes['extras'][$eKey]);
0473                 }
0474             }
0475         }
0476         return $attributes;
0477     }
0478 }