1<?php 2/** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to license@zend.com so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_View 17 * @subpackage Helper 18 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 19 * @version $Id$ 20 * @license http://framework.zend.com/license/new-bsd New BSD License 21 */ 22 23/** Zend_View_Helper_Placeholder_Container_Standalone */ 24 25/** 26 * Helper for setting and retrieving stylesheets 27 * 28 * @uses Zend_View_Helper_Placeholder_Container_Standalone 29 * @package Zend_View 30 * @subpackage Helper 31 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 32 * @license http://framework.zend.com/license/new-bsd New BSD License 33 * @method $this appendStyle($content, array $attributes = array()) 34 * @method $this offsetSetStyle($index, $content, array $attributes = array()) 35 * @method $this prependStyle($content, array $attributes = array()) 36 * @method $this setStyle($content, array $attributes = array()) 37 */ 38class Zend_View_Helper_HeadStyle extends Zend_View_Helper_Placeholder_Container_Standalone 39{ 40 /** 41 * Registry key for placeholder 42 * @var string 43 */ 44 protected $_regKey = 'Zend_View_Helper_HeadStyle'; 45 46 /** 47 * Allowed optional attributes 48 * @var array 49 */ 50 protected $_optionalAttributes = array('lang', 'title', 'media', 'dir'); 51 52 /** 53 * Allowed media types 54 * @var array 55 */ 56 protected $_mediaTypes = array( 57 'all', 'aural', 'braille', 'handheld', 'print', 58 'projection', 'screen', 'tty', 'tv' 59 ); 60 61 /** 62 * Capture type and/or attributes (used for hinting during capture) 63 * @var string 64 */ 65 protected $_captureAttrs = null; 66 67 /** 68 * Capture lock 69 * @var bool 70 */ 71 protected $_captureLock; 72 73 /** 74 * Capture type (append, prepend, set) 75 * @var string 76 */ 77 protected $_captureType; 78 79 /** 80 * Constructor 81 * 82 * Set separator to PHP_EOL. 83 * 84 * @return void 85 */ 86 public function __construct() 87 { 88 parent::__construct(); 89 $this->setSeparator(PHP_EOL); 90 } 91 92 /** 93 * Return headStyle object 94 * 95 * Returns headStyle helper object; optionally, allows specifying 96 * 97 * @param string $content Stylesheet contents 98 * @param string $placement Append, prepend, or set 99 * @param string|array $attributes Optional attributes to utilize 100 * @return Zend_View_Helper_HeadStyle 101 */ 102 public function headStyle($content = null, $placement = 'APPEND', $attributes = array()) 103 { 104 if ((null !== $content) && is_string($content)) { 105 switch (strtoupper($placement)) { 106 case 'SET': 107 $action = 'setStyle'; 108 break; 109 case 'PREPEND': 110 $action = 'prependStyle'; 111 break; 112 case 'APPEND': 113 default: 114 $action = 'appendStyle'; 115 break; 116 } 117 $this->$action($content, $attributes); 118 } 119 120 return $this; 121 } 122 123 /** 124 * Overload method calls 125 * 126 * Allows the following method calls: 127 * - appendStyle($content, $attributes = array()) 128 * - offsetSetStyle($index, $content, $attributes = array()) 129 * - prependStyle($content, $attributes = array()) 130 * - setStyle($content, $attributes = array()) 131 * 132 * @param string $method 133 * @param array $args 134 * @return void 135 * @throws Zend_View_Exception When no $content provided or invalid method 136 */ 137 public function __call($method, $args) 138 { 139 if (preg_match('/^(?P<action>set|(ap|pre)pend|offsetSet)(Style)$/', $method, $matches)) { 140 $index = null; 141 $argc = count($args); 142 $action = $matches['action']; 143 144 if ('offsetSet' == $action) { 145 if (0 < $argc) { 146 $index = array_shift($args); 147 --$argc; 148 } 149 } 150 151 if (1 > $argc) { 152 $e = new Zend_View_Exception(sprintf('Method "%s" requires minimally content for the stylesheet', $method)); 153 $e->setView($this->view); 154 throw $e; 155 } 156 157 $content = $args[0]; 158 $attrs = array(); 159 if (isset($args[1])) { 160 $attrs = (array) $args[1]; 161 } 162 163 $item = $this->createData($content, $attrs); 164 165 if ('offsetSet' == $action) { 166 $this->offsetSet($index, $item); 167 } else { 168 $this->$action($item); 169 } 170 171 return $this; 172 } 173 174 return parent::__call($method, $args); 175 } 176 177 /** 178 * Determine if a value is a valid style tag 179 * 180 * @param mixed $value 181 * @param string $method 182 * @return boolean 183 */ 184 protected function _isValid($value) 185 { 186 if ((!$value instanceof stdClass) 187 || !isset($value->content) 188 || !isset($value->attributes)) 189 { 190 return false; 191 } 192 193 return true; 194 } 195 196 /** 197 * Override append to enforce style creation 198 * 199 * @param mixed $value 200 * @return void 201 */ 202 public function append($value) 203 { 204 if (!$this->_isValid($value)) { 205 $e = new Zend_View_Exception('Invalid value passed to append; please use appendStyle()'); 206 $e->setView($this->view); 207 throw $e; 208 } 209 210 return $this->getContainer()->append($value); 211 } 212 213 /** 214 * Override offsetSet to enforce style creation 215 * 216 * @param string|int $index 217 * @param mixed $value 218 * @return void 219 */ 220 public function offsetSet($index, $value) 221 { 222 if (!$this->_isValid($value)) { 223 $e = new Zend_View_Exception('Invalid value passed to offsetSet; please use offsetSetStyle()'); 224 $e->setView($this->view); 225 throw $e; 226 } 227 228 return $this->getContainer()->offsetSet($index, $value); 229 } 230 231 /** 232 * Override prepend to enforce style creation 233 * 234 * @param mixed $value 235 * @return void 236 */ 237 public function prepend($value) 238 { 239 if (!$this->_isValid($value)) { 240 $e = new Zend_View_Exception('Invalid value passed to prepend; please use prependStyle()'); 241 $e->setView($this->view); 242 throw $e; 243 } 244 245 return $this->getContainer()->prepend($value); 246 } 247 248 /** 249 * Override set to enforce style creation 250 * 251 * @param mixed $value 252 * @return void 253 */ 254 public function set($value) 255 { 256 if (!$this->_isValid($value)) { 257 $e = new Zend_View_Exception('Invalid value passed to set; please use setStyle()'); 258 $e->setView($this->view); 259 throw $e; 260 } 261 262 return $this->getContainer()->set($value); 263 } 264 265 /** 266 * Start capture action 267 * 268 * @param mixed $captureType 269 * @param string $typeOrAttrs 270 * @return void 271 */ 272 public function captureStart($type = Zend_View_Helper_Placeholder_Container_Abstract::APPEND, $attrs = null) 273 { 274 if ($this->_captureLock) { 275 $e = new Zend_View_Helper_Placeholder_Container_Exception('Cannot nest headStyle captures'); 276 $e->setView($this->view); 277 throw $e; 278 } 279 280 $this->_captureLock = true; 281 $this->_captureAttrs = $attrs; 282 $this->_captureType = $type; 283 ob_start(); 284 } 285 286 /** 287 * End capture action and store 288 * 289 * @return void 290 */ 291 public function captureEnd() 292 { 293 $content = ob_get_clean(); 294 $attrs = $this->_captureAttrs; 295 $this->_captureAttrs = null; 296 $this->_captureLock = false; 297 298 switch ($this->_captureType) { 299 case Zend_View_Helper_Placeholder_Container_Abstract::SET: 300 $this->setStyle($content, $attrs); 301 break; 302 case Zend_View_Helper_Placeholder_Container_Abstract::PREPEND: 303 $this->prependStyle($content, $attrs); 304 break; 305 case Zend_View_Helper_Placeholder_Container_Abstract::APPEND: 306 default: 307 $this->appendStyle($content, $attrs); 308 break; 309 } 310 } 311 312 /** 313 * Convert content and attributes into valid style tag 314 * 315 * @param stdClass $item Item to render 316 * @param string $indent Indentation to use 317 * @return string 318 */ 319 public function itemToString(stdClass $item, $indent) 320 { 321 $attrString = ''; 322 if (!empty($item->attributes)) { 323 $enc = 'UTF-8'; 324 if ($this->view instanceof Zend_View_Interface 325 && method_exists($this->view, 'getEncoding') 326 ) { 327 $enc = $this->view->getEncoding(); 328 } 329 foreach ($item->attributes as $key => $value) { 330 if (!in_array($key, $this->_optionalAttributes)) { 331 continue; 332 } 333 if ('media' == $key) { 334 if(false === strpos($value, ',')) { 335 if (!in_array($value, $this->_mediaTypes)) { 336 continue; 337 } 338 } else { 339 $media_types = explode(',', $value); 340 $value = ''; 341 foreach($media_types as $type) { 342 $type = trim($type); 343 if (!in_array($type, $this->_mediaTypes)) { 344 continue; 345 } 346 $value .= $type .','; 347 } 348 $value = substr($value, 0, -1); 349 } 350 } 351 $attrString .= sprintf(' %s="%s"', $key, htmlspecialchars($value, ENT_COMPAT, $enc)); 352 } 353 } 354 355 $escapeStart = $indent . '<!--'. PHP_EOL; 356 $escapeEnd = $indent . '-->'. PHP_EOL; 357 if (isset($item->attributes['conditional']) 358 && !empty($item->attributes['conditional']) 359 && is_string($item->attributes['conditional']) 360 ) { 361 $escapeStart = null; 362 $escapeEnd = null; 363 } 364 365 $html = '<style type="text/css"' . $attrString . '>' . PHP_EOL 366 . $escapeStart . $indent . $item->content . PHP_EOL . $escapeEnd 367 . '</style>'; 368 369 if (null == $escapeStart && null == $escapeEnd) { 370 if (str_replace(' ', '', $item->attributes['conditional']) === '!IE') { 371 $html = '<!-->' . $html . '<!--'; 372 } 373 $html = '<!--[if ' . $item->attributes['conditional'] . ']>' . $html . '<![endif]-->'; 374 } 375 376 return $html; 377 } 378 379 /** 380 * Create string representation of placeholder 381 * 382 * @param string|int $indent 383 * @return string 384 */ 385 public function toString($indent = null) 386 { 387 $indent = (null !== $indent) 388 ? $this->getWhitespace($indent) 389 : $this->getIndent(); 390 391 $items = array(); 392 $this->getContainer()->ksort(); 393 foreach ($this as $item) { 394 if (!$this->_isValid($item)) { 395 continue; 396 } 397 $items[] = $this->itemToString($item, $indent); 398 } 399 400 $return = $indent . implode($this->getSeparator() . $indent, $items); 401 $return = preg_replace("/(\r\n?|\n)/", '$1' . $indent, $return); 402 return $return; 403 } 404 405 /** 406 * Create data item for use in stack 407 * 408 * @param string $content 409 * @param array $attributes 410 * @return stdClass 411 */ 412 public function createData($content, array $attributes) 413 { 414 if (!isset($attributes['media'])) { 415 $attributes['media'] = 'screen'; 416 } else if(is_array($attributes['media'])) { 417 $attributes['media'] = implode(',', $attributes['media']); 418 } 419 420 $data = new stdClass(); 421 $data->content = $content; 422 $data->attributes = $attributes; 423 424 return $data; 425 } 426} 427