PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Zend/View/PhpRenderer.php

https://github.com/mrbanzai/zf2
PHP | 455 lines | 207 code | 45 blank | 203 comment | 25 complexity | 4c1e2b3d6e1cba8649c61a47e98fab69 MD5 | raw file
  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. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. */
  20. /**
  21. * @namespace
  22. */
  23. namespace Zend\View;
  24. use Zend\Filter\FilterChain,
  25. Zend\Loader\Pluggable,
  26. ArrayAccess;
  27. /**
  28. * Abstract class for Zend_View to help enforce private constructs.
  29. *
  30. * @todo Allow specifying string names for broker, filter chain, variables
  31. * @category Zend
  32. * @package Zend_View
  33. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  34. * @license http://framework.zend.com/license/new-bsd New BSD License
  35. */
  36. class PhpRenderer implements Renderer, Pluggable
  37. {
  38. /**
  39. * Template resolver
  40. *
  41. * @var TemplateResolver
  42. */
  43. private $templateResolver;
  44. /**
  45. * Script file name to execute
  46. *
  47. * @var string
  48. */
  49. private $file = null;
  50. /**
  51. * Helper broker
  52. *
  53. * @var HelperBroker
  54. */
  55. private $helperBroker;
  56. /**
  57. * @var Zend\Filter\FilterChain
  58. */
  59. private $filterChain;
  60. /**
  61. * @var ArrayAccess|array ArrayAccess or associative array representing available variables
  62. */
  63. private $vars;
  64. /**
  65. * @var array Temporary variable stack; used when variables passed to render()
  66. */
  67. private $varsCache = array();
  68. /**
  69. * Constructor.
  70. *
  71. *
  72. * @todo handle passing helper broker, options
  73. * @todo handle passing filter chain, options
  74. * @todo handle passing variables object, options
  75. * @todo handle passing resolver object, options
  76. * @param array $config Configuration key-value pairs.
  77. */
  78. public function __construct($config = array())
  79. {
  80. $this->init();
  81. }
  82. /**
  83. * Return the template engine object
  84. *
  85. * Returns the object instance, as it is its own template engine
  86. *
  87. * @return \Zend\View\PhpRenderer
  88. */
  89. public function getEngine()
  90. {
  91. return $this;
  92. }
  93. /**
  94. * Allow custom object initialization when extending Zend_View_Abstract or
  95. * Zend_View
  96. *
  97. * Triggered by {@link __construct() the constructor} as its final action.
  98. *
  99. * @return void
  100. */
  101. public function init()
  102. {
  103. }
  104. /**
  105. * Set script resolver
  106. *
  107. * @param string|TemplateResolver $resolver
  108. * @param mixed $options
  109. * @return PhpRenderer
  110. * @throws Exception\InvalidArgumentException
  111. */
  112. public function setResolver($resolver, $options = null)
  113. {
  114. if (is_string($resolver)) {
  115. if (!class_exists($resolver)) {
  116. throw new Exception\InvalidArgumentException('Class passed as resolver could not be found');
  117. }
  118. $resolver = new $resolver($options);
  119. }
  120. if (!$resolver instanceof TemplateResolver) {
  121. throw new Exception\InvalidArgumentException(sprintf(
  122. 'Expected resolver to implement TemplateResolver; received "%s"',
  123. (is_object($resolver) ? get_class($resolver) : gettype($resolver))
  124. ));
  125. }
  126. $this->templateResolver = $resolver;
  127. return $this;
  128. }
  129. /**
  130. * Retrieve template name or template resolver
  131. *
  132. * @param null|string $name
  133. * @return string|TemplateResolver
  134. */
  135. public function resolver($name = null)
  136. {
  137. if (null === $this->templateResolver) {
  138. $this->setResolver(new TemplatePathStack());
  139. }
  140. if (null !== $name) {
  141. return $this->templateResolver->getScriptPath($name);
  142. }
  143. return $this->templateResolver;
  144. }
  145. /**
  146. * Set variable storage
  147. *
  148. * Expects either an array, or an object implementing ArrayAccess.
  149. *
  150. * @param array|ArrayAccess $variables
  151. * @return PhpRenderer
  152. * @throws Exception\InvalidArgumentException
  153. */
  154. public function setVars($variables)
  155. {
  156. if (!is_array($variables) && !$variables instanceof ArrayAccess) {
  157. throw new Exception\InvalidArgumentException(sprintf(
  158. 'Expected array or ArrayAccess object; received "%s"',
  159. (is_object($variables) ? get_class($variables) : gettype($variables))
  160. ));
  161. }
  162. // Enforce a Variables container
  163. if (!$variables instanceof Variables) {
  164. $variablesAsArray = array();
  165. foreach ($variables as $key => $value) {
  166. $variablesAsArray[$key] = $value;
  167. }
  168. $variables = new Variables($variablesAsArray);
  169. }
  170. $broker = $this->getBroker();
  171. $loader = $broker->getClassLoader();
  172. if ($loader->isLoaded('escape')) {
  173. $escaper = $broker->load('escape');
  174. if (is_callable($escaper)) {
  175. $variables->setEscapeCallback($escaper);
  176. }
  177. }
  178. $this->vars = $variables;
  179. return $this;
  180. }
  181. /**
  182. * Get a single variable, or all variables
  183. *
  184. * @param mixed $key
  185. * @return mixed
  186. */
  187. public function vars($key = null)
  188. {
  189. if (null === $this->vars) {
  190. $this->setVars(new Variables());
  191. }
  192. if (null === $key) {
  193. return $this->vars;
  194. }
  195. return $this->vars[$key];
  196. }
  197. /**
  198. * Get a single variable
  199. *
  200. * @param mixed $key
  201. * @return mixed
  202. */
  203. public function get($key)
  204. {
  205. if (null === $this->vars) {
  206. $this->setVars(new Variables());
  207. }
  208. return $this->vars[$key];
  209. }
  210. /**
  211. * Get a single raw (unescaped) value
  212. *
  213. * @param mixed $key
  214. * @return mixed
  215. */
  216. public function raw($key)
  217. {
  218. if (null === $this->vars) {
  219. $this->setVars(new Variables());
  220. }
  221. if (!$this->vars instanceof Variables) {
  222. if (isset($this->vars[$key])) {
  223. return $this->vars[$key];
  224. }
  225. return null;
  226. }
  227. return $this->vars->getRawValue($key);
  228. }
  229. /**
  230. * Overloading: proxy to Variables container
  231. *
  232. * @param string $name
  233. * @return mixed
  234. */
  235. public function __get($name)
  236. {
  237. $vars = $this->vars();
  238. return $vars[$name];
  239. }
  240. /**
  241. * Overloading: proxy to Variables container
  242. *
  243. * @param string $name
  244. * @param mixed $value
  245. * @return void
  246. */
  247. public function __set($name, $value)
  248. {
  249. $vars = $this->vars();
  250. $vars[$name] = $value;
  251. }
  252. /**
  253. * Overloading: proxy to Variables container
  254. *
  255. * @param string $name
  256. * @return bool
  257. */
  258. public function __isset($name)
  259. {
  260. $vars = $this->vars();
  261. return isset($vars[$name]);
  262. }
  263. /**
  264. * Overloading: proxy to Variables container
  265. *
  266. * @param string $name
  267. * @return void
  268. */
  269. public function __unset($name)
  270. {
  271. $vars = $this->vars();
  272. if (!isset($vars[$name])) {
  273. return;
  274. }
  275. unset($vars[$name]);
  276. }
  277. /**
  278. * Set plugin broker instance
  279. *
  280. * @param string|HelperBroker $broker
  281. * @return Zend\View\Abstract
  282. * @throws Exception\InvalidArgumentException
  283. */
  284. public function setBroker($broker)
  285. {
  286. if (is_string($broker)) {
  287. if (!class_exists($broker)) {
  288. throw new Exception\InvalidArgumentException(sprintf(
  289. 'Invalid helper broker class provided (%s)',
  290. $broker
  291. ));
  292. }
  293. $broker = new $broker();
  294. }
  295. if (!$broker instanceof HelperBroker) {
  296. throw new Exception\InvalidArgumentException(sprintf(
  297. 'Helper broker must extend Zend\View\HelperBroker; got type "%s" instead',
  298. (is_object($broker) ? get_class($broker) : gettype($broker))
  299. ));
  300. }
  301. $broker->setView($this);
  302. $this->helperBroker = $broker;
  303. }
  304. /**
  305. * Get plugin broker instance
  306. *
  307. * @return HelperBroker
  308. */
  309. public function getBroker()
  310. {
  311. if (null === $this->helperBroker) {
  312. $this->setBroker(new HelperBroker());
  313. }
  314. return $this->helperBroker;
  315. }
  316. /**
  317. * Get plugin instance
  318. *
  319. * @param string $plugin Name of plugin to return
  320. * @param null|array $options Options to pass to plugin constructor (if not already instantiated)
  321. * @return Helper
  322. */
  323. public function plugin($name, array $options = null)
  324. {
  325. return $this->getBroker()->load($name, $options);
  326. }
  327. /**
  328. * Overloading: proxy to helpers
  329. *
  330. * Proxies to the attached plugin broker to retrieve, return, and potentially
  331. * execute helpers.
  332. *
  333. * * If the helper does not define __invoke, it will be returned
  334. * * If the helper does define __invoke, it will be called as a functor
  335. *
  336. * @param string $method
  337. * @param array $argv
  338. * @return mixed
  339. */
  340. public function __call($method, $argv)
  341. {
  342. $helper = $this->plugin($method);
  343. if (is_callable($helper)) {
  344. return call_user_func_array($helper, $argv);
  345. }
  346. return $helper;
  347. }
  348. /**
  349. * Set filter chain
  350. *
  351. * @param FilterChain $filters
  352. * @return Zend\View\PhpRenderer
  353. */
  354. public function setFilterChain(FilterChain $filters)
  355. {
  356. $this->filterChain = $filters;
  357. return $this;
  358. }
  359. /**
  360. * Retrieve filter chain for post-filtering script content
  361. *
  362. * @return FilterChain
  363. */
  364. public function getFilterChain()
  365. {
  366. if (null === $this->filterChain) {
  367. $this->setFilterChain(new FilterChain());
  368. }
  369. return $this->filterChain;
  370. }
  371. /**
  372. * Processes a view script and returns the output.
  373. *
  374. * @param string $name The script name to process.
  375. * @return string The script output.
  376. */
  377. public function render($name, $vars = null)
  378. {
  379. // find the script file name using the parent private method
  380. $this->file = $this->resolver($name);
  381. unset($name); // remove $name from local scope
  382. $this->varsCache[] = $this->vars();
  383. if (null !== $vars) {
  384. $this->setVars($vars);
  385. }
  386. unset($vars);
  387. // extract all assigned vars (pre-escaped), but not 'this'.
  388. // assigns to a double-underscored variable, to prevent naming collisions
  389. $__vars = $this->vars()->getArrayCopy();
  390. if (array_key_exists('this', $__vars)) {
  391. unset($__vars['this']);
  392. }
  393. extract($__vars);
  394. unset($__vars); // remove $__vars from local scope
  395. ob_start();
  396. include $this->file;
  397. $content = ob_get_clean();
  398. $this->setVars(array_pop($this->varsCache));
  399. return $this->getFilterChain()->filter($content); // filter output
  400. }
  401. /**
  402. * Make sure View variables are cloned when the view is cloned.
  403. *
  404. * @return PhpRenderer
  405. */
  406. public function __clone()
  407. {
  408. $this->vars = clone $this->vars();
  409. }
  410. }