1. sfView.class.php
  2. /** * A view represents the presentation layer of an action. Output can be * customized by supplying attributes, which a template can manipulate and * display. * * @package symfony * @subpackage view * @author Fabien Potencier * @author Sean Kerr * @version SVN: $Id: sfView.class.php 23940 2009-11-14 17:58:19Z fabien $ */
  3. abstract class sfView
  4. {
  5. /**
  6. * Show an alert view.
  7. */
  8. const ALERT = 'Alert';
  9. /**
  10. * Show an error view.
  11. */
  12. const ERROR = 'Error';
  13. /**
  14. * Show a form input view.
  15. */
  16. const INPUT = 'Input';
  17. /**
  18. * Skip view execution.
  19. */
  20. const NONE = 'None';
  21. /**
  22. * Show a success view.
  23. */
  24. const SUCCESS = 'Success';
  25. /**
  26. * Do not render the presentation.
  27. */
  28. const RENDER_NONE = 1;
  29. /**
  30. * Render the presentation to the client.
  31. */
  32. const RENDER_CLIENT = 2;
  33. /**
  34. * Render the presentation to a variable.
  35. */
  36. const RENDER_VAR = 4;
  37. /**
  38. * Skip view rendering but output http headers
  39. */
  40. const HEADER_ONLY = 8;
  41. protected
  42. $context = null,
  43. $dispatcher = null,
  44. $decorator = false,
  45. $decoratorDirectory = null,
  46. $decoratorTemplate = null,
  47. $directory = null,
  48. $componentSlots = array(),
  49. $template = null,
  50. $attributeHolder = null,
  51. $parameterHolder = null,
  52. $moduleName = '',
  53. $actionName = '',
  54. $viewName = '',
  55. $extension = '.php';
  56. /**
  57. * Class constructor.
  58. *
  59. * @see initialize()
  60. */
  61. public function __construct($context, $moduleName, $actionName, $viewName)
  62. {
  63. $this->initialize($context, $moduleName, $actionName, $viewName);
  64. }
  65. /**
  66. * Initializes this view.
  67. *
  68. * @param sfContext $context The current application context
  69. * @param string $moduleName The module name for this view
  70. * @param string $actionName The action name for this view
  71. * @param string $viewName The view name
  72. *
  73. * @return bool true, if initialization completes successfully, otherwise false
  74. */
  75. public function initialize($context, $moduleName, $actionName, $viewName)
  76. {
  77. $this->moduleName = $moduleName;
  78. $this->actionName = $actionName;
  79. $this->viewName = $viewName;
  80. $this->context = $context;
  81. $this->dispatcher = $context->getEventDispatcher();
  82. sfOutputEscaper::markClassesAsSafe(array('sfForm', 'sfFormField', 'sfFormFieldSchema', 'sfModelGeneratorHelper'));
  83. $this->attributeHolder = $this->initializeAttributeHolder();
  84. $this->parameterHolder = new sfParameterHolder();
  85. $this->parameterHolder->add(sfConfig::get('mod_'.strtolower($moduleName).'_view_param', array()));
  86. $request = $context->getRequest();
  87. $format = $request->getRequestFormat();
  88. if (null !== $format)
  89. {
  90. if ('html' != $format)
  91. {
  92. $this->setExtension('.'.$format.$this->getExtension());
  93. }
  94. if ($mimeType = $request->getMimeType($format))
  95. {
  96. $this->context->getResponse()->setContentType($mimeType);
  97. if ('html' != $format)
  98. {
  99. $this->setDecorator(false);
  100. }
  101. }
  102. }
  103. $this->dispatcher->notify(new sfEvent($this, 'view.configure_format', array('format' => $format, 'response' => $context->getResponse(), 'request' => $context->getRequest())));
  104. // include view configuration
  105. $this->configure();
  106. return true;
  107. }
  108. protected function initializeAttributeHolder($attributes = array())
  109. {
  110. $attributeHolder = new sfViewParameterHolder($this->dispatcher, $attributes, array(
  111. 'escaping_method' => sfConfig::get('sf_escaping_method'),
  112. 'escaping_strategy' => sfConfig::get('sf_escaping_strategy'),
  113. ));
  114. return $attributeHolder;
  115. }
  116. /**
  117. * Executes any presentation logic and set template attributes.
  118. */
  119. abstract function execute();
  120. /**
  121. * Configures template.
  122. */
  123. abstract function configure();
  124. /**
  125. * Retrieves this views decorator template directory.
  126. *
  127. * @return string An absolute filesystem path to this views decorator template directory
  128. */
  129. public function getDecoratorDirectory()
  130. {
  131. return $this->decoratorDirectory;
  132. }
  133. /**
  134. * Retrieves this views decorator template.
  135. *
  136. * @return string A template filename, if a template has been set, otherwise null
  137. */
  138. public function getDecoratorTemplate()
  139. {
  140. return $this->decoratorTemplate;
  141. }
  142. /**
  143. * Retrieves this view template directory.
  144. *
  145. * @return string An absolute filesystem path to this views template directory
  146. */
  147. public function getDirectory()
  148. {
  149. return $this->directory;
  150. }
  151. /**
  152. * Retrieves the template engine associated with this view.
  153. *
  154. * Note: This will return null for PHPView instances.
  155. *
  156. * @return mixed A template engine instance
  157. */
  158. abstract function getEngine();
  159. /**
  160. * Retrieves this views template.
  161. *
  162. * @return string A template filename, if a template has been set, otherwise null
  163. */
  164. public function getTemplate()
  165. {
  166. return $this->template;
  167. }
  168. /**
  169. * Retrieves attributes for the current view.
  170. *
  171. * @return sfParameterHolder The attribute parameter holder
  172. */
  173. public function getAttributeHolder()
  174. {
  175. return $this->attributeHolder;
  176. }
  177. /**
  178. * Retrieves an attribute for the current view.
  179. *
  180. * @param string $name Name of the attribute
  181. * @param string $default Value of the attribute
  182. *
  183. * @return mixed Attribute
  184. */
  185. public function getAttribute($name, $default = null)
  186. {
  187. return $this->attributeHolder->get($name, $default);
  188. }
  189. /**
  190. * Returns true if the view have attributes.
  191. *
  192. * @param string $name Name of the attribute
  193. *
  194. * @return mixed Attribute of the view
  195. */
  196. public function hasAttribute($name)
  197. {
  198. return $this->attributeHolder->has($name);
  199. }
  200. /**
  201. * Sets an attribute of the view.
  202. *
  203. * @param string $name Attribute name
  204. * @param string $value Value for the attribute
  205. */
  206. public function setAttribute($name, $value)
  207. {
  208. $this->attributeHolder->set($name, $value);
  209. }
  210. /**
  211. * Retrieves the parameters for the current view.
  212. *
  213. * @return sfParameterHolder The parameter holder
  214. */
  215. public function getParameterHolder()
  216. {
  217. return $this->parameterHolder;
  218. }
  219. /**
  220. * Retrieves a parameter from the current view.
  221. *
  222. * @param string $name Parameter name
  223. * @param string $default Default parameter value
  224. *
  225. * @return mixed A parameter value
  226. */
  227. public function getParameter($name, $default = null)
  228. {
  229. return $this->parameterHolder->get($name, $default);
  230. }
  231. /**
  232. * Indicates whether or not a parameter exist for the current view.
  233. *
  234. * @param string $name Name of the paramater
  235. *
  236. * @return bool true, if the parameter exists otherwise false
  237. */
  238. public function hasParameter($name)
  239. {
  240. return $this->parameterHolder->has($name);
  241. }
  242. /**
  243. * Sets a parameter for the view.
  244. *
  245. * @param string $name Name of the parameter
  246. * @param string $value The parameter value
  247. */
  248. public function setParameter($name, $value)
  249. {
  250. $this->parameterHolder->set($name, $value);
  251. }
  252. /**
  253. * Indicates that this view is a decorating view.
  254. *
  255. * @return bool true, if this view is a decorating view, otherwise false
  256. */
  257. public function isDecorator()
  258. {
  259. return $this->decorator;
  260. }
  261. /**
  262. * Sets the decorating mode for the current view.
  263. *
  264. * @param bool $boolean Set the decorating mode for the view
  265. */
  266. public function setDecorator($boolean)
  267. {
  268. $this->decorator = (boolean) $boolean;
  269. if (false === $boolean)
  270. {
  271. $this->decoratorTemplate = false;
  272. }
  273. }
  274. /**
  275. * Executes a basic pre-render check to verify all required variables exist
  276. * and that the template is readable.
  277. *
  278. * @throws sfRenderException If the pre-render check fails
  279. */
  280. protected function preRenderCheck()
  281. {
  282. if (null === $this->template)
  283. {
  284. // a template has not been set
  285. throw new sfRenderException('A template has not been set.');
  286. }
  287. if (!is_readable($this->directory.'/'.$this->template))
  288. {
  289. // 404?
  290. if ('404' == $this->context->getResponse()->getStatusCode())
  291. {
  292. // use default exception templates
  293. $this->template = sfException::getTemplatePathForError($this->context->getRequest()->getRequestFormat(), false);
  294. $this->directory = dirname($this->template);
  295. $this->template = basename($this->template);
  296. $this->setAttribute('code', '404');
  297. $this->setAttribute('text', 'Not Found');
  298. }
  299. else
  300. {
  301. throw new sfRenderException(sprintf('The template "%s" does not exist or is unreadable in "%s".', $this->template, $this->directory));
  302. }
  303. }
  304. // check to see if this is a decorator template
  305. if ($this->decorator && !is_readable($this->decoratorDirectory.'/'.$this->decoratorTemplate))
  306. {
  307. throw new sfRenderException(sprintf('The decorator template "%s" does not exist or is unreadable in "%s".', $this->decoratorTemplate, $this->decoratorDirectory));
  308. }
  309. }
  310. /**
  311. * Renders the presentation.
  312. *
  313. * @return string A string representing the rendered presentation
  314. */
  315. abstract function render();
  316. /**
  317. * Sets the decorator template directory for this view.
  318. *
  319. * @param string $directory An absolute filesystem path to a template directory
  320. */
  321. public function setDecoratorDirectory($directory)
  322. {
  323. $this->decoratorDirectory = $directory;
  324. }
  325. /**
  326. * Sets the decorator template for this view.
  327. *
  328. * If the template path is relative, it will be based on the currently
  329. * executing module's template sub-directory.
  330. *
  331. * @param string $template An absolute or relative filesystem path to a template
  332. */
  333. public function setDecoratorTemplate($template)
  334. {
  335. if (false === $template)
  336. {
  337. $this->setDecorator(false);
  338. return;
  339. }
  340. else if (null === $template)
  341. {
  342. return;
  343. }
  344. if (!strpos($template, '.'))
  345. {
  346. $template .= $this->getExtension();
  347. }
  348. if (sfToolkit::isPathAbsolute($template))
  349. {
  350. $this->decoratorDirectory = dirname($template);
  351. $this->decoratorTemplate = basename($template);
  352. }
  353. else
  354. {
  355. $this->decoratorDirectory = $this->context->getConfiguration()->getDecoratorDir($template);
  356. $this->decoratorTemplate = $template;
  357. }
  358. // set decorator status
  359. $this->decorator = true;
  360. }
  361. /**
  362. * Sets the template directory for this view.
  363. *
  364. * @param string $directory An absolute filesystem path to a template directory
  365. */
  366. public function setDirectory($directory)
  367. {
  368. $this->directory = $directory;
  369. }
  370. /**
  371. * Sets the module and action to be executed in place of a particular template attribute.
  372. *
  373. * @param string $attributeName A template attribute name
  374. * @param string $moduleName A module name
  375. * @param string $componentName A component name
  376. */
  377. public function setComponentSlot($attributeName, $moduleName, $componentName)
  378. {
  379. $this->componentSlots[$attributeName] = array();
  380. $this->componentSlots[$attributeName]['module_name'] = $moduleName;
  381. $this->componentSlots[$attributeName]['component_name'] = $componentName;
  382. }
  383. /**
  384. * Indicates whether or not a component slot exists.
  385. *
  386. * @param string $name The component slot name
  387. *
  388. * @return bool true, if the component slot exists, otherwise false
  389. */
  390. public function hasComponentSlot($name)
  391. {
  392. return isset($this->componentSlots[$name]);
  393. }
  394. /**
  395. * Gets a component slot
  396. *
  397. * @param string $name The component slot name
  398. *
  399. * @return array The component slot
  400. */
  401. public function getComponentSlot($name)
  402. {
  403. if (isset($this->componentSlots[$name]) && $this->componentSlots[$name]['module_name'] && $this->componentSlots[$name]['component_name'])
  404. {
  405. return array($this->componentSlots[$name]['module_name'], $this->componentSlots[$name]['component_name']);
  406. }
  407. return null;
  408. }
  409. /**
  410. * Sets the template for this view.
  411. *
  412. * If the template path is relative, it will be based on the currently
  413. * executing module's template sub-directory.
  414. *
  415. * @param string $template An absolute or relative filesystem path to a template
  416. */
  417. public function setTemplate($template)
  418. {
  419. if (sfToolkit::isPathAbsolute($template))
  420. {
  421. $this->directory = dirname($template);
  422. $this->template = basename($template);
  423. }
  424. else
  425. {
  426. $this->directory = $this->context->getConfiguration()->getTemplateDir($this->moduleName, $template);
  427. $this->template = $template;
  428. }
  429. }
  430. /**
  431. * Retrieves the current view extension.
  432. *
  433. * @return string The extension for current view.
  434. */
  435. public function getExtension()
  436. {
  437. return $this->extension;
  438. }
  439. /**
  440. * Sets an extension for the current view.
  441. *
  442. * @param string $extension The extension name.
  443. */
  444. public function setExtension($extension)
  445. {
  446. $this->extension = $extension;
  447. }
  448. /**
  449. * Gets the module name associated with this view.
  450. *
  451. * @return string A module name
  452. */
  453. public function getModuleName()
  454. {
  455. return $this->moduleName;
  456. }
  457. /**
  458. * Gets the action name associated with this view.
  459. *
  460. * @return string An action name
  461. */
  462. public function getActionName()
  463. {
  464. return $this->actionName;
  465. }
  466. /**
  467. * Gets the view name associated with this view.
  468. *
  469. * @return string An action name
  470. */
  471. public function getViewName()
  472. {
  473. return $this->viewName;
  474. }
  475. /**
  476. * Calls methods defined via sfEventDispatcher.
  477. *
  478. * @param string $method The method name
  479. * @param array $arguments The method arguments
  480. *
  481. * @return mixed The returned value of the called method
  482. *
  483. * @throws sfException< If the calls fails
  484. */
  485. public function __call($method, $arguments)
  486. {
  487. $event = $this->dispatcher->notifyUntil(new sfEvent($this, 'view.method_not_found', array('method' => $method, 'arguments' => $arguments)));
  488. if (!$event->isProcessed())
  489. {
  490. throw new sfException(sprintf('Call to undefined method %s::%s.', get_class($this), $method));
  491. }
  492. return $event->getReturnValue();
  493. }
  494. }

Debug toolbar