1<?php 2/** 3 * Zend Framework (http://framework.zend.com/) 4 * 5 * @link http://github.com/zendframework/zf2 for the canonical source repository 6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 7 * @license http://framework.zend.com/license/new-bsd New BSD License 8 */ 9 10namespace Zend\View\Helper\Placeholder\Container; 11 12use ArrayAccess; 13use Countable; 14use IteratorAggregate; 15use Zend\Escaper\Escaper; 16use Zend\View\Exception; 17use Zend\View\Helper\AbstractHelper; 18use Zend\View\Renderer\RendererInterface; 19 20/** 21 * Base class for targeted placeholder helpers 22 */ 23abstract class AbstractStandalone extends AbstractHelper implements 24 IteratorAggregate, 25 Countable, 26 ArrayAccess 27{ 28 /** 29 * Flag whether to automatically escape output, must also be 30 * enforced in the child class if __toString/toString is overridden 31 * 32 * @var bool 33 */ 34 protected $autoEscape = true; 35 36 /** 37 * @var AbstractContainer 38 */ 39 protected $container; 40 41 /** 42 * Default container class 43 * @var string 44 */ 45 protected $containerClass = 'Zend\View\Helper\Placeholder\Container'; 46 47 /** 48 * @var Escaper[] 49 */ 50 protected $escapers = array(); 51 52 /** 53 * Constructor 54 * 55 */ 56 public function __construct() 57 { 58 $this->setContainer($this->getContainer()); 59 } 60 61 /** 62 * Overload 63 * 64 * Proxy to container methods 65 * 66 * @param string $method 67 * @param array $args 68 * @throws Exception\BadMethodCallException 69 * @return mixed 70 */ 71 public function __call($method, $args) 72 { 73 $container = $this->getContainer(); 74 if (method_exists($container, $method)) { 75 $return = call_user_func_array(array($container, $method), $args); 76 if ($return === $container) { 77 // If the container is returned, we really want the current object 78 return $this; 79 } 80 return $return; 81 } 82 83 throw new Exception\BadMethodCallException('Method "' . $method . '" does not exist'); 84 } 85 86 /** 87 * Overloading: set property value 88 * 89 * @param string $key 90 * @param mixed $value 91 * @return void 92 */ 93 public function __set($key, $value) 94 { 95 $container = $this->getContainer(); 96 $container[$key] = $value; 97 } 98 99 /** 100 * Overloading: retrieve property 101 * 102 * @param string $key 103 * @return mixed 104 */ 105 public function __get($key) 106 { 107 $container = $this->getContainer(); 108 if (isset($container[$key])) { 109 return $container[$key]; 110 } 111 112 return; 113 } 114 115 /** 116 * Overloading: check if property is set 117 * 118 * @param string $key 119 * @return bool 120 */ 121 public function __isset($key) 122 { 123 $container = $this->getContainer(); 124 return isset($container[$key]); 125 } 126 127 /** 128 * Overloading: unset property 129 * 130 * @param string $key 131 * @return void 132 */ 133 public function __unset($key) 134 { 135 $container = $this->getContainer(); 136 if (isset($container[$key])) { 137 unset($container[$key]); 138 } 139 } 140 141 /** 142 * Cast to string representation 143 * 144 * @return string 145 */ 146 public function __toString() 147 { 148 return $this->toString(); 149 } 150 151 /** 152 * String representation 153 * 154 * @return string 155 */ 156 public function toString() 157 { 158 return $this->getContainer()->toString(); 159 } 160 161 /** 162 * Escape a string 163 * 164 * @param string $string 165 * @return string 166 */ 167 protected function escape($string) 168 { 169 if ($this->getView() instanceof RendererInterface 170 && method_exists($this->getView(), 'getEncoding') 171 ) { 172 $escaper = $this->getView()->plugin('escapeHtml'); 173 return $escaper((string) $string); 174 } 175 176 return $this->getEscaper()->escapeHtml((string) $string); 177 } 178 179 /** 180 * Set whether or not auto escaping should be used 181 * 182 * @param bool $autoEscape whether or not to auto escape output 183 * @return AbstractStandalone 184 */ 185 public function setAutoEscape($autoEscape = true) 186 { 187 $this->autoEscape = (bool) $autoEscape; 188 return $this; 189 } 190 191 /** 192 * Return whether autoEscaping is enabled or disabled 193 * 194 * return bool 195 */ 196 public function getAutoEscape() 197 { 198 return $this->autoEscape; 199 } 200 201 /** 202 * Set container on which to operate 203 * 204 * @param AbstractContainer $container 205 * @return AbstractStandalone 206 */ 207 public function setContainer(AbstractContainer $container) 208 { 209 $this->container = $container; 210 return $this; 211 } 212 213 /** 214 * Retrieve placeholder container 215 * 216 * @return AbstractContainer 217 */ 218 public function getContainer() 219 { 220 if (!$this->container instanceof AbstractContainer) { 221 $this->container = new $this->containerClass(); 222 } 223 return $this->container; 224 } 225 226 /** 227 * Delete a container 228 * 229 * @return bool 230 */ 231 public function deleteContainer() 232 { 233 if (null != $this->container) { 234 $this->container = null; 235 return true; 236 } 237 238 return false; 239 } 240 241 /** 242 * Set the container class to use 243 * 244 * @param string $name 245 * @throws Exception\InvalidArgumentException 246 * @throws Exception\DomainException 247 * @return \Zend\View\Helper\Placeholder\Container\AbstractStandalone 248 */ 249 public function setContainerClass($name) 250 { 251 if (!class_exists($name)) { 252 throw new Exception\DomainException( 253 sprintf( 254 '%s expects a valid container class name; received "%s", which did not resolve', 255 __METHOD__, 256 $name 257 ) 258 ); 259 } 260 261 if (!in_array('Zend\View\Helper\Placeholder\Container\AbstractContainer', class_parents($name))) { 262 throw new Exception\InvalidArgumentException('Invalid Container class specified'); 263 } 264 265 $this->containerClass = $name; 266 return $this; 267 } 268 269 /** 270 * Retrieve the container class 271 * 272 * @return string 273 */ 274 public function getContainerClass() 275 { 276 return $this->containerClass; 277 } 278 279 /** 280 * Set Escaper instance 281 * 282 * @param Escaper $escaper 283 * @return AbstractStandalone 284 */ 285 public function setEscaper(Escaper $escaper) 286 { 287 $encoding = $escaper->getEncoding(); 288 $this->escapers[$encoding] = $escaper; 289 290 return $this; 291 } 292 293 /** 294 * Get Escaper instance 295 * 296 * Lazy-loads one if none available 297 * 298 * @param string|null $enc Encoding to use 299 * @return mixed 300 */ 301 public function getEscaper($enc = 'UTF-8') 302 { 303 $enc = strtolower($enc); 304 if (!isset($this->escapers[$enc])) { 305 $this->setEscaper(new Escaper($enc)); 306 } 307 308 return $this->escapers[$enc]; 309 } 310 311 /** 312 * Countable 313 * 314 * @return int 315 */ 316 public function count() 317 { 318 $container = $this->getContainer(); 319 return count($container); 320 } 321 322 /** 323 * ArrayAccess: offsetExists 324 * 325 * @param string|int $offset 326 * @return bool 327 */ 328 public function offsetExists($offset) 329 { 330 return $this->getContainer()->offsetExists($offset); 331 } 332 333 /** 334 * ArrayAccess: offsetGet 335 * 336 * @param string|int $offset 337 * @return mixed 338 */ 339 public function offsetGet($offset) 340 { 341 return $this->getContainer()->offsetGet($offset); 342 } 343 344 /** 345 * ArrayAccess: offsetSet 346 * 347 * @param string|int $offset 348 * @param mixed $value 349 * @return void 350 */ 351 public function offsetSet($offset, $value) 352 { 353 return $this->getContainer()->offsetSet($offset, $value); 354 } 355 356 /** 357 * ArrayAccess: offsetUnset 358 * 359 * @param string|int $offset 360 * @return void 361 */ 362 public function offsetUnset($offset) 363 { 364 return $this->getContainer()->offsetUnset($offset); 365 } 366 367 /** 368 * IteratorAggregate: get Iterator 369 * 370 * @return \Iterator 371 */ 372 public function getIterator() 373 { 374 return $this->getContainer()->getIterator(); 375 } 376} 377