FormHelper.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\FrameworkBundle\Templating\Helper;
  11. use Symfony\Component\Templating\Helper\Helper;
  12. use Symfony\Component\Templating\EngineInterface;
  13. use Symfony\Component\Form\FormView;
  14. use Symfony\Component\Form\Exception\FormException;
  15. use Symfony\Component\Form\Util\FormUtil;
  16. /**
  17. *
  18. *
  19. * @author Fabien Potencier <fabien@symfony.com>
  20. * @author Bernhard Schussek <bernhard.schussek@symfony.com>
  21. */
  22. class FormHelper extends Helper
  23. {
  24. static protected $cache = array();
  25. protected $engine;
  26. protected $varStack;
  27. protected $rendering;
  28. protected $context;
  29. public function __construct(EngineInterface $engine)
  30. {
  31. $this->engine = $engine;
  32. $this->varStack = new \SplObjectStorage();
  33. $this->viewStack = array();
  34. $this->rendering = array();
  35. $this->context = array();
  36. }
  37. public function isChoiceGroup($label)
  38. {
  39. return FormUtil::isChoiceGroup($label);
  40. }
  41. public function isChoiceSelected(FormView $view, $choice)
  42. {
  43. return FormUtil::isChoiceSelected($choice, $view->get('value'));
  44. }
  45. /**
  46. * Renders the HTML enctype in the form tag, if necessary.
  47. *
  48. * Example usage templates:
  49. *
  50. * <form action="..." method="post" <?php echo $view['form']->enctype() ?>>
  51. *
  52. * @param FormView $view The view for which to render the encoding type
  53. *
  54. * @return string The html markup
  55. */
  56. public function enctype(FormView $view)
  57. {
  58. return $this->renderSection($view, 'enctype');
  59. }
  60. /**
  61. * Renders the HTML for a given view.
  62. *
  63. * Example usage:
  64. *
  65. * <?php echo view['form']->widget() ?>
  66. *
  67. * You can pass options during the call:
  68. *
  69. * <?php echo view['form']->widget(array('attr' => array('class' => 'foo'))) ?>
  70. *
  71. * <?php echo view['form']->widget(array('separator' => '+++++)) ?>
  72. *
  73. * @param FormView $view The view for which to render the widget
  74. * @param array $variables Additional variables passed to the template
  75. *
  76. * @return string The html markup
  77. */
  78. public function widget(FormView $view, array $variables = array())
  79. {
  80. return trim($this->renderSection($view, 'widget', $variables));
  81. }
  82. /**
  83. * Renders the entire form field "row".
  84. *
  85. * @param FormView $view The view for which to render the row
  86. * @param array $variables Additional variables passed to the template
  87. *
  88. * @return string The html markup
  89. */
  90. public function row(FormView $view, array $variables = array())
  91. {
  92. return $this->renderSection($view, 'row', $variables);
  93. }
  94. /**
  95. * Renders the label of the given view.
  96. *
  97. * @param FormView $view The view for which to render the label
  98. * @param string $label The label
  99. * @param array $variables Additional variables passed to the template
  100. *
  101. * @return string The html markup
  102. */
  103. public function label(FormView $view, $label = null, array $variables = array())
  104. {
  105. if ($label !== null) {
  106. $variables += array('label' => $label);
  107. }
  108. return $this->renderSection($view, 'label', $variables);
  109. }
  110. /**
  111. * Renders the errors of the given view.
  112. *
  113. * @param FormView $view The view to render the errors for
  114. *
  115. * @return string The html markup
  116. */
  117. public function errors(FormView $view)
  118. {
  119. return $this->renderSection($view, 'errors');
  120. }
  121. /**
  122. * Renders views which have not already been rendered.
  123. *
  124. * @param FormView $view The parent view
  125. * @param array $variables An array of variables
  126. *
  127. * @return string The html markup
  128. */
  129. public function rest(FormView $view, array $variables = array())
  130. {
  131. return $this->renderSection($view, 'rest', $variables);
  132. }
  133. /**
  134. * Renders a template.
  135. *
  136. * 1. This function first looks for a block named "_<view id>_<section>",
  137. * 2. if such a block is not found the function will look for a block named
  138. * "<type name>_<section>",
  139. * 3. the type name is recursively replaced by the parent type name until a
  140. * corresponding block is found
  141. *
  142. * @param FormView $view The form view
  143. * @param string $section The section to render (i.e. 'row', 'widget', 'label', ...)
  144. * @param array $variables Additional variables
  145. *
  146. * @return string The html markup
  147. *
  148. * @throws FormException if no template block exists to render the given section of the view
  149. */
  150. protected function renderSection(FormView $view, $section, array $variables = array())
  151. {
  152. $mainTemplate = in_array($section, array('row', 'widget'));
  153. if ($mainTemplate && $view->isRendered()) {
  154. return '';
  155. }
  156. $template = null;
  157. $custom = '_'.$view->get('proto_id', $view->get('id'));
  158. $types = $view->get('types');
  159. $types[] = $custom;
  160. $rendering = $custom.$section;
  161. $i = isset($this->rendering[$rendering]) ? $this->rendering[$rendering] - 1 : count ($types) - 1;
  162. do {
  163. $block = $types[$i].'_'.$section;
  164. $template = $this->lookupTemplate($block);
  165. if ($template) {
  166. $this->rendering[$rendering] = $i;
  167. $this->varStack[$view] = array_replace(
  168. $view->all(),
  169. isset($this->varStack[$view]) ? $this->varStack[$view] : array(),
  170. $variables
  171. );
  172. $this->context[] = $this->varStack[$view];
  173. $html = $this->engine->render($template, $this->varStack[$view]);
  174. array_pop($this->context);
  175. unset($this->varStack[$view], $this->rendering[$rendering]);
  176. if ($mainTemplate) {
  177. $view->setRendered();
  178. }
  179. return $html;
  180. }
  181. } while (--$i >= 0);
  182. throw new FormException(sprintf('Unable to render the form as none of the following blocks exist: "%s".', implode('", "', $types)));
  183. }
  184. /**
  185. * Render a block from a form element.
  186. *
  187. * @param string $name
  188. * @param array $variables Additional variables (those would override the current context)
  189. *
  190. * @throws FormException if the block is not found
  191. * @throws FormException if the method is called out of a form element (no context)
  192. */
  193. public function renderBlock($name, $variables = array())
  194. {
  195. if (0 == count($this->context)) {
  196. throw new FormException(sprintf('This method should only be called while rendering a form element.', $name));
  197. }
  198. $template = $this->lookupTemplate($name);
  199. if (false === $template) {
  200. throw new FormException(sprintf('No block "%s" found while rendering the form.', $name));
  201. }
  202. $variables = array_replace_recursive(end($this->context), $variables);
  203. return $this->engine->render($template, $variables);
  204. }
  205. /**
  206. * Returns the name of the template to use to render the block
  207. *
  208. * @param string $blockName The name of the block
  209. *
  210. * @return string|Boolean The template logical name or false when no template is found
  211. */
  212. protected function lookupTemplate($blockName)
  213. {
  214. if (isset(self::$cache[$blockName])) {
  215. return self::$cache[$blockName];
  216. }
  217. $template = $blockName.'.html.php';
  218. /*
  219. if ($this->templateDir) {
  220. $template = $this->templateDir.':'.$template;
  221. }
  222. */
  223. $template = 'FrameworkBundle:Form:'.$template;
  224. if (!$this->engine->exists($template)) {
  225. $template = false;
  226. }
  227. self::$cache[$blockName] = $template;
  228. return $template;
  229. }
  230. public function getName()
  231. {
  232. return 'form';
  233. }
  234. }