123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- <?php
- /*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
- namespace Symfony\Bridge\Twig\Extension;
- use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
- use Symfony\Component\Form\FormView;
- use Symfony\Component\Form\Exception\FormException;
- use Symfony\Component\Form\Util\FormUtil;
- /**
- * FormExtension extends Twig with form capabilities.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Bernhard Schussek <bernhard.schussek@symfony.com>
- */
- class FormExtension extends \Twig_Extension
- {
- protected $resources;
- protected $blocks;
- protected $environment;
- protected $themes;
- protected $varStack;
- protected $template;
- public function __construct(array $resources = array())
- {
- $this->themes = new \SplObjectStorage();
- $this->varStack = new \SplObjectStorage();
- $this->blocks = new \SplObjectStorage();
- $this->resources = $resources;
- }
- /**
- * {@inheritdoc}
- */
- public function initRuntime(\Twig_Environment $environment)
- {
- $this->environment = $environment;
- }
- /**
- * Sets a theme for a given view.
- *
- * @param FormView $view A FormView instance
- * @param array $resources An array of resources
- */
- public function setTheme(FormView $view, array $resources)
- {
- $this->themes->attach($view, $resources);
- $this->blocks = new \SplObjectStorage();
- }
- /**
- * Returns the token parser instance to add to the existing list.
- *
- * @return array An array of Twig_TokenParser instances
- */
- public function getTokenParsers()
- {
- return array(
- // {% form_theme form "SomeBungle::widgets.twig" %}
- new FormThemeTokenParser(),
- );
- }
- public function getFunctions()
- {
- return array(
- 'form_enctype' => new \Twig_Function_Method($this, 'renderEnctype', array('is_safe' => array('html'))),
- 'form_widget' => new \Twig_Function_Method($this, 'renderWidget', array('is_safe' => array('html'))),
- 'form_errors' => new \Twig_Function_Method($this, 'renderErrors', array('is_safe' => array('html'))),
- 'form_label' => new \Twig_Function_Method($this, 'renderLabel', array('is_safe' => array('html'))),
- 'form_row' => new \Twig_Function_Method($this, 'renderRow', array('is_safe' => array('html'))),
- 'form_rest' => new \Twig_Function_Method($this, 'renderRest', array('is_safe' => array('html'))),
- '_form_is_choice_group' => new \Twig_Function_Method($this, 'isChoiceGroup', array('is_safe' => array('html'))),
- '_form_is_choice_selected' => new \Twig_Function_Method($this, 'isChoiceSelected', array('is_safe' => array('html'))),
- );
- }
- public function isChoiceGroup($label)
- {
- return FormUtil::isChoiceGroup($label);
- }
- public function isChoiceSelected(FormView $view, $choice)
- {
- return FormUtil::isChoiceSelected($choice, $view->get('value'));
- }
- /**
- * Renders the HTML enctype in the form tag, if necessary
- *
- * Example usage in Twig templates:
- *
- * <form action="..." method="post" {{ form_enctype(form) }}>
- *
- * @param FormView $view The view for which to render the encoding type
- *
- * @return string The html markup
- */
- public function renderEnctype(FormView $view)
- {
- return $this->render($view, 'enctype');
- }
- /**
- * Renders a row for the view.
- *
- * @param FormView $view The view to render as a row
- * @param array $variables An array of variables
- *
- * @return string The html markup
- */
- public function renderRow(FormView $view, array $variables = array())
- {
- return $this->render($view, 'row', $variables);
- }
- /**
- * Renders views which have not already been rendered.
- *
- * @param FormView $view The parent view
- * @param array $variables An array of variables
- *
- * @return string The html markup
- */
- public function renderRest(FormView $view, array $variables = array())
- {
- return $this->render($view, 'rest', $variables);
- }
- /**
- * Renders the HTML for a given view
- *
- * Example usage in Twig:
- *
- * {{ form_widget(view) }}
- *
- * You can pass options during the call:
- *
- * {{ form_widget(view, {'attr': {'class': 'foo'}}) }}
- *
- * {{ form_widget(view, {'separator': '+++++'}) }}
- *
- * @param FormView $view The view to render
- * @param array $variables Additional variables passed to the template
- *
- * @return string The html markup
- */
- public function renderWidget(FormView $view, array $variables = array())
- {
- return $this->render($view, 'widget', $variables);
- }
- /**
- * Renders the errors of the given view
- *
- * @param FormView $view The view to render the errors for
- *
- * @return string The html markup
- */
- public function renderErrors(FormView $view)
- {
- return $this->render($view, 'errors');
- }
- /**
- * Renders the label of the given view
- *
- * @param FormView $view The view to render the label for
- * @param string $label Label name
- * @param array $variables Additional variables passed to the template
- *
- * @return string The html markup
- */
- public function renderLabel(FormView $view, $label = null, array $variables = array())
- {
- if ($label !== null) {
- $variables += array('label' => $label);
- }
- return $this->render($view, 'label', $variables);
- }
- /**
- * Renders a template.
- *
- * 1. This function first looks for a block named "_<view id>_<section>",
- * 2. if such a block is not found the function will look for a block named
- * "<type name>_<section>",
- * 3. the type name is recursively replaced by the parent type name until a
- * corresponding block is found
- *
- * @param FormView $view The form view
- * @param string $section The section to render (i.e. 'row', 'widget', 'label', ...)
- * @param array $variables Additional variables
- *
- * @return string The html markup
- *
- * @throws FormException if no template block exists to render the given section of the view
- */
- protected function render(FormView $view, $section, array $variables = array())
- {
- $mainTemplate = in_array($section, array('widget', 'row'));
- if ($mainTemplate && $view->isRendered()) {
- return '';
- }
- if (null === $this->template) {
- $this->template = reset($this->resources);
- if (!$this->template instanceof \Twig_Template) {
- $this->template = $this->environment->loadTemplate($this->template);
- }
- }
- $blocks = $this->getBlocks($view);
- $types = $view->get('types');
- array_unshift($types, '_'.$view->get('id'));
- foreach ($types as $type) {
- $block = $type.'_'.$section;
- if (isset($blocks[$block])) {
- $this->varStack[$view] = array_replace(
- $view->all(),
- isset($this->varStack[$view]) ? $this->varStack[$view] : array(),
- $variables
- );
- $html = $this->template->renderBlock($block, $this->varStack[$view], $blocks);
- if ($mainTemplate) {
- $view->setRendered();
- }
- unset($this->varStack[$view]);
- return $html;
- }
- }
- throw new FormException(sprintf('Unable to render form as none of the following blocks exist: "%s".', implode('", "', $blocks)));
- }
- /**
- * Returns the blocks used to render the view.
- *
- * Templates are looked for in the resources in the following order:
- * * resources from the themes (and its parents)
- * * resources from the themes of parent views (up to the root view)
- * * default resources
- *
- * @param FormView $view The view
- *
- * @return array An array of Twig_TemplateInterface instances
- */
- protected function getBlocks(FormView $view)
- {
- if (!$this->blocks->contains($view)) {
- $rootView = !$view->hasParent();
- $templates = $rootView ? $this->resources : array();
- if (isset($this->themes[$view])) {
- $templates = array_merge($templates, $this->themes[$view]);
- }
- $blocks = array();
- foreach ($templates as $template) {
- if (!$template instanceof \Twig_Template) {
- $template = $this->environment->loadTemplate($template);
- }
- $templateBlocks = array();
- do {
- $templateBlocks = array_merge($template->getBlocks(), $templateBlocks);
- } while (false !== $template = $template->getParent(array()));
- $blocks = array_merge($blocks, $templateBlocks);
- }
- if (!$rootView) {
- $blocks = array_merge($this->getBlocks($view->getParent()), $blocks);
- }
- $this->blocks->attach($view, $blocks);
- } else {
- $blocks = $this->blocks[$view];
- }
- return $blocks;
- }
- /**
- * Returns the name of the extension.
- *
- * @return string The extension name
- */
- public function getName()
- {
- return 'form';
- }
- }
|