sfViewConfigHandler.class.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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 17858 2009-05-01 21:22:50Z FabianLange $
  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. // Merge the current view's stylesheets with the app's default stylesheets
  201. $stylesheets = $this->mergeConfigValue('stylesheets', $viewName);
  202. $css = $this->addAssets('Stylesheet', $stylesheets);
  203. // Merge the current view's javascripts with the app's default javascripts
  204. $javascripts = $this->mergeConfigValue('javascripts', $viewName);
  205. $js = $this->addAssets('Javascript', $javascripts);
  206. return implode("\n", array_merge($css, $js))."\n";
  207. }
  208. /**
  209. * Creates a list of add$Type PHP statements for the given type and config.
  210. *
  211. * @param string $type of asset. Requires an sfWebResponse->add$Type(string, string, array) method
  212. *
  213. * @return array ist of add$Type PHP statements
  214. */
  215. private function addAssets($type, $assets){
  216. $tmp = array();
  217. foreach ((array) $assets as $asset)
  218. {
  219. $position = '';
  220. if (is_array($asset))
  221. {
  222. $key = key($asset);
  223. $options = $asset[$key];
  224. if (isset($options['position']))
  225. {
  226. $position = $options['position'];
  227. unset($options['position']);
  228. }
  229. }
  230. else
  231. {
  232. $key = $asset;
  233. $options = array();
  234. }
  235. if ('-*' == $key)
  236. {
  237. $tmp = array();
  238. }
  239. else if ('-' == $key[0])
  240. {
  241. unset($tmp[substr($key, 1)]);
  242. }
  243. else
  244. {
  245. $tmp[$key] = sprintf(" \$response->add%s('%s', '%s', %s);", $type, $key, $position, str_replace("\n", '', var_export($options, true)));
  246. }
  247. }
  248. return array_values($tmp);
  249. }
  250. /**
  251. * Adds an escaping statement to the data.
  252. *
  253. * @param string $viewName The view name
  254. *
  255. * @return string The PHP statement
  256. */
  257. protected function addEscaping($viewName = '')
  258. {
  259. $data = array();
  260. $escaping = $this->getConfigValue('escaping', $viewName);
  261. if (isset($escaping['method']))
  262. {
  263. $data[] = sprintf(" \$this->getAttributeHolder()->setEscapingMethod(%s);", var_export($escaping['method'], true));
  264. }
  265. return implode("\n", $data)."\n";
  266. }
  267. /**
  268. * @see sfConfigHandler
  269. */
  270. static public function getConfiguration(array $configFiles)
  271. {
  272. return self::mergeConfig(self::parseYamls($configFiles));
  273. }
  274. static protected function mergeConfig($config)
  275. {
  276. // merge javascripts and stylesheets
  277. $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());
  278. unset($config['default']['stylesheets']);
  279. $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());
  280. unset($config['default']['javascripts']);
  281. // merge default and all
  282. $config['all'] = sfToolkit::arrayDeepMerge(
  283. isset($config['default']) && is_array($config['default']) ? $config['default'] : array(),
  284. isset($config['all']) && is_array($config['all']) ? $config['all'] : array()
  285. );
  286. unset($config['default']);
  287. return self::replaceConstants($config);
  288. }
  289. }