sfViewConfigHandler.class.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. <?php
  2. /*
  3. * This file is part of the symfony package.
  4. * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * sfViewConfigHandler allows you to configure views.
  11. *
  12. * @package symfony
  13. * @subpackage config
  14. * @author Fabien Potencier <fabien.potencier@symfony-project.com>
  15. * @version SVN: $Id: sfViewConfigHandler.class.php 9085 2008-05-20 01:53:23Z Carl.Vondrick $
  16. */
  17. class sfViewConfigHandler extends sfYamlConfigHandler
  18. {
  19. /**
  20. * Executes this configuration handler.
  21. *
  22. * @param array $configFiles An array of absolute filesystem path to a configuration file
  23. *
  24. * @return string Data to be written to a cache file
  25. *
  26. * @throws <b>sfConfigurationException</b> If a requested configuration file does not exist or is not readable
  27. * @throws <b>sfParseException</b> If a requested configuration file is improperly formatted
  28. * @throws <b>sfInitializationException</b> If a view.yml key check fails
  29. */
  30. public function execute($configFiles)
  31. {
  32. // parse the yaml
  33. $this->yamlConfig = self::getConfiguration($configFiles);
  34. // init our data array
  35. $data = array();
  36. $data[] = "\$response = \$this->context->getResponse();\n\n";
  37. // first pass: iterate through all view names to determine the real view name
  38. $first = true;
  39. foreach ($this->yamlConfig as $viewName => $values)
  40. {
  41. if ($viewName == 'all')
  42. {
  43. continue;
  44. }
  45. $data[] = ($first ? '' : 'else ')."if (\$this->actionName.\$this->viewName == '$viewName')\n".
  46. "{\n";
  47. $data[] = $this->addTemplate($viewName);
  48. $data[] = "}\n";
  49. $first = false;
  50. }
  51. // general view configuration
  52. $data[] = ($first ? '' : "else\n{")."\n";
  53. $data[] = $this->addTemplate($viewName);
  54. $data[] = ($first ? '' : "}")."\n\n";
  55. // second pass: iterate through all real view names
  56. $first = true;
  57. foreach ($this->yamlConfig as $viewName => $values)
  58. {
  59. if ($viewName == 'all')
  60. {
  61. continue;
  62. }
  63. $data[] = ($first ? '' : 'else ')."if (\$templateName.\$this->viewName == '$viewName')\n".
  64. "{\n";
  65. $data[] = $this->addLayout($viewName);
  66. $data[] = $this->addComponentSlots($viewName);
  67. $data[] = $this->addHtmlHead($viewName);
  68. $data[] = $this->addEscaping($viewName);
  69. $data[] = $this->addHtmlAsset($viewName);
  70. $data[] = "}\n";
  71. $first = false;
  72. }
  73. // general view configuration
  74. $data[] = ($first ? '' : "else\n{")."\n";
  75. $data[] = $this->addLayout();
  76. $data[] = $this->addComponentSlots();
  77. $data[] = $this->addHtmlHead();
  78. $data[] = $this->addEscaping();
  79. $data[] = $this->addHtmlAsset();
  80. $data[] = ($first ? '' : "}")."\n";
  81. // compile data
  82. $retval = sprintf("<?php\n".
  83. "// auto-generated by sfViewConfigHandler\n".
  84. "// date: %s\n%s\n",
  85. date('Y/m/d H:i:s'), implode('', $data));
  86. return $retval;
  87. }
  88. /**
  89. * Adds a component slot statement to the data.
  90. *
  91. * @param string $viewName The view name
  92. *
  93. * @return string The PHP statement
  94. */
  95. protected function addComponentSlots($viewName = '')
  96. {
  97. $data = '';
  98. $components = $this->mergeConfigValue('components', $viewName);
  99. foreach ($components as $name => $component)
  100. {
  101. if (!is_array($component) || count($component) < 1)
  102. {
  103. $component = array(null, null);
  104. }
  105. $data .= " \$this->setComponentSlot('$name', '{$component[0]}', '{$component[1]}');\n";
  106. $data .= " if (sfConfig::get('sf_logging_enabled')) \$this->context->getEventDispatcher()->notify(new sfEvent(\$this, 'application.log', array(sprintf('Set component \"%s\" (%s/%s)', '$name', '{$component[0]}', '{$component[1]}'))));\n";
  107. }
  108. return $data;
  109. }
  110. /**
  111. * Adds a template setting statement to the data.
  112. *
  113. * @param string $viewName The view name
  114. *
  115. * @return string The PHP statement
  116. */
  117. protected function addTemplate($viewName = '')
  118. {
  119. $data = '';
  120. $templateName = $this->getConfigValue('template', $viewName);
  121. $defaultTemplateName = $templateName ? "'$templateName'" : '$this->actionName';
  122. $data .= " \$templateName = sfConfig::get('symfony.view.'.\$this->moduleName.'_'.\$this->actionName.'_template', $defaultTemplateName);\n";
  123. $data .= " \$this->setTemplate(\$templateName.\$this->viewName.\$this->getExtension());\n";
  124. return $data;
  125. }
  126. /**
  127. * Adds a layout statement statement to the data.
  128. *
  129. * @param string $viewName The view name
  130. *
  131. * @return string The PHP statement
  132. */
  133. protected function addLayout($viewName = '')
  134. {
  135. // true if the user set 'has_layout' to true or set a 'layout' name for this specific action
  136. $hasLocalLayout = isset($this->yamlConfig[$viewName]['layout']) || (isset($this->yamlConfig[$viewName]) && array_key_exists('has_layout', $this->yamlConfig[$viewName]));
  137. // the layout value
  138. $layout = $this->getConfigValue('has_layout', $viewName) ? $this->getConfigValue('layout', $viewName) : false;
  139. // the user set a decorator in the action
  140. $data = <<<EOF
  141. if (!is_null(\$layout = sfConfig::get('symfony.view.'.\$this->moduleName.'_'.\$this->actionName.'_layout')))
  142. {
  143. \$this->setDecoratorTemplate(false === \$layout ? false : \$layout.\$this->getExtension());
  144. }
  145. EOF;
  146. if ($hasLocalLayout)
  147. {
  148. // the user set a decorator in view.yml for this action
  149. $data .= <<<EOF
  150. else
  151. {
  152. \$this->setDecoratorTemplate('' == '$layout' ? false : '$layout'.\$this->getExtension());
  153. }
  154. EOF;
  155. }
  156. else
  157. {
  158. // no specific configuration
  159. // set the layout to the 'all' view.yml value except if:
  160. // * the decorator template has already been set by "someone" (via view.configure_format for example)
  161. // * the request is an XMLHttpRequest request
  162. $data .= <<<EOF
  163. else if (is_null(\$this->getDecoratorTemplate()) && !\$this->context->getRequest()->isXmlHttpRequest())
  164. {
  165. \$this->setDecoratorTemplate('' == '$layout' ? false : '$layout'.\$this->getExtension());
  166. }
  167. EOF;
  168. }
  169. return $data;
  170. }
  171. /**
  172. * Adds http metas and metas statements to the data.
  173. *
  174. * @param string $viewName The view name
  175. *
  176. * @return string The PHP statement
  177. */
  178. protected function addHtmlHead($viewName = '')
  179. {
  180. $data = array();
  181. foreach ($this->mergeConfigValue('http_metas', $viewName) as $httpequiv => $content)
  182. {
  183. $data[] = sprintf(" \$response->addHttpMeta('%s', '%s', false);", $httpequiv, str_replace('\'', '\\\'', $content));
  184. }
  185. foreach ($this->mergeConfigValue('metas', $viewName) as $name => $content)
  186. {
  187. $data[] = sprintf(" \$response->addMeta('%s', '%s', false, false);", $name, str_replace('\'', '\\\'', preg_replace('/&amp;(?=\w+;)/', '&', htmlspecialchars($content, ENT_QUOTES, sfConfig::get('sf_charset')))));
  188. }
  189. return implode("\n", $data)."\n";
  190. }
  191. /**
  192. * Adds stylesheets and javascripts statements to the data.
  193. *
  194. * @param string $viewName The view name
  195. *
  196. * @return string The PHP statement
  197. */
  198. protected function addHtmlAsset($viewName = '')
  199. {
  200. $data = array();
  201. $omit = array();
  202. $delete = array();
  203. $delete_all = false;
  204. // Merge the current view's stylesheets with the app's default stylesheets
  205. $stylesheets = $this->mergeConfigValue('stylesheets', $viewName);
  206. $tmp = array();
  207. foreach ((array) $stylesheets as $css)
  208. {
  209. $position = '';
  210. if (is_array($css))
  211. {
  212. $key = key($css);
  213. $options = $css[$key];
  214. if (isset($options['position']))
  215. {
  216. $position = $options['position'];
  217. unset($options['position']);
  218. }
  219. }
  220. else
  221. {
  222. $key = $css;
  223. $options = array();
  224. }
  225. if ('-*' == $key)
  226. {
  227. $tmp = array();
  228. }
  229. else if ('-' == $key[0])
  230. {
  231. unset($tmp[substr($key, 1)]);
  232. }
  233. else
  234. {
  235. $tmp[$key] = sprintf(" \$response->addStylesheet('%s', '%s', %s);", $key, $position, str_replace("\n", '', var_export($options, true)));
  236. }
  237. }
  238. $data = array_merge($data, array_values($tmp));
  239. $omit = array();
  240. $delete_all = false;
  241. // Merge the current view's javascripts with the app's default javascripts
  242. $javascripts = $this->mergeConfigValue('javascripts', $viewName);
  243. $tmp = array();
  244. foreach ((array) $javascripts as $js)
  245. {
  246. $position = '';
  247. if (is_array($js))
  248. {
  249. $key = key($js);
  250. $options = $js[$key];
  251. if (isset($options['position']))
  252. {
  253. $position = $options['position'];
  254. unset($options['position']);
  255. }
  256. }
  257. else
  258. {
  259. $key = $js;
  260. $options = array();
  261. }
  262. if ('-*' == $key)
  263. {
  264. $tmp = array();
  265. }
  266. else if ('-' == $key[0])
  267. {
  268. unset($tmp[substr($key, 1)]);
  269. }
  270. else
  271. {
  272. $tmp[$key] = sprintf(" \$response->addJavascript('%s', '%s', %s);", $key, $position, str_replace("\n", '', var_export($options, true)));
  273. }
  274. }
  275. $data = array_merge($data, array_values($tmp));
  276. return implode("\n", $data)."\n";
  277. }
  278. /**
  279. * Adds an escaping statement to the data.
  280. *
  281. * @param string $viewName The view name
  282. *
  283. * @return string The PHP statement
  284. */
  285. protected function addEscaping($viewName = '')
  286. {
  287. $data = array();
  288. $escaping = $this->getConfigValue('escaping', $viewName);
  289. if (isset($escaping['method']))
  290. {
  291. $data[] = sprintf(" \$this->getAttributeHolder()->setEscapingMethod(%s);", var_export($escaping['method'], true));
  292. }
  293. return implode("\n", $data)."\n";
  294. }
  295. /**
  296. * @see sfConfigHandler
  297. */
  298. static public function getConfiguration(array $configFiles)
  299. {
  300. return self::mergeConfig(self::parseYamls($configFiles));
  301. }
  302. static protected function mergeConfig($config)
  303. {
  304. // merge javascripts and stylesheets
  305. $config['all']['stylesheets'] = array_merge(isset($config['default']['stylesheets']) && is_array($config['default']['stylesheets']) ? $config['default']['stylesheets'] : array(), isset($config['all']['stylesheets']) && is_array($config['all']['stylesheets']) ? $config['all']['stylesheets'] : array());
  306. unset($config['default']['stylesheets']);
  307. $config['all']['javascripts'] = array_merge(isset($config['default']['javascripts']) && is_array($config['default']['javascripts']) ? $config['default']['javascripts'] : array(), isset($config['all']['javascripts']) && is_array($config['all']['javascripts']) ? $config['all']['javascripts'] : array());
  308. unset($config['default']['javascripts']);
  309. // merge default and all
  310. $config['all'] = sfToolkit::arrayDeepMerge(
  311. isset($config['default']) && is_array($config['default']) ? $config['default'] : array(),
  312. isset($config['all']) && is_array($config['all']) ? $config['all'] : array()
  313. );
  314. unset($config['default']);
  315. return self::replaceConstants($config);
  316. }
  317. }