FormExtension.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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\Bridge\Twig\Extension;
  11. use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
  12. use Symfony\Bridge\Twig\Form\TwigRendererInterface;
  13. use Symfony\Component\Form\Extension\Core\View\ChoiceView;
  14. /**
  15. * FormExtension extends Twig with form capabilities.
  16. *
  17. * @author Fabien Potencier <fabien@symfony.com>
  18. * @author Bernhard Schussek <bschussek@gmail.com>
  19. */
  20. class FormExtension extends \Twig_Extension
  21. {
  22. /**
  23. * This property is public so that it can be accessed directly from compiled
  24. * templates without having to call a getter, which slightly decreases performance.
  25. *
  26. * @var TwigRendererInterface
  27. */
  28. public $renderer;
  29. public function __construct(TwigRendererInterface $renderer)
  30. {
  31. $this->renderer = $renderer;
  32. }
  33. /**
  34. * {@inheritdoc}
  35. */
  36. public function initRuntime(\Twig_Environment $environment)
  37. {
  38. $this->renderer->setEnvironment($environment);
  39. }
  40. /**
  41. * {@inheritdoc}
  42. */
  43. public function getTokenParsers()
  44. {
  45. return array(
  46. // {% form_theme form "SomeBundle::widgets.twig" %}
  47. new FormThemeTokenParser(),
  48. );
  49. }
  50. /**
  51. * {@inheritdoc}
  52. */
  53. public function getFunctions()
  54. {
  55. return array(
  56. 'form_enctype' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\FormEnctypeNode', array('is_safe' => array('html'))),
  57. 'form_widget' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
  58. 'form_errors' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
  59. 'form_label' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
  60. 'form_row' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
  61. 'form_rest' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
  62. 'form' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
  63. 'form_start' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
  64. 'form_end' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
  65. 'csrf_token' => new \Twig_Function_Method($this, 'renderer->renderCsrfToken'),
  66. );
  67. }
  68. /**
  69. * {@inheritdoc}
  70. */
  71. public function getFilters()
  72. {
  73. return array(
  74. new \Twig_SimpleFilter('humanize', array($this->renderer, 'humanize')),
  75. );
  76. }
  77. /**
  78. * {@inheritdoc}
  79. */
  80. public function getTests()
  81. {
  82. return array(
  83. new \Twig_SimpleTest('selectedchoice', array($this, 'isSelectedChoice')),
  84. );
  85. }
  86. /**
  87. * Returns whether a choice is selected for a given form value.
  88. *
  89. * Unfortunately Twig does not support an efficient way to execute the
  90. * "is_selected" closure passed to the template by ChoiceType. It is faster
  91. * to implement the logic here (around 65ms for a specific form).
  92. *
  93. * Directly implementing the logic here is also faster than doing so in
  94. * ChoiceView (around 30ms).
  95. *
  96. * The worst option tested so far is to implement the logic in ChoiceView
  97. * and access the ChoiceView method directly in the template. Doing so is
  98. * around 220ms slower than doing the method call here in the filter. Twig
  99. * seems to be much more efficient at executing filters than at executing
  100. * methods of an object.
  101. *
  102. * @param ChoiceView $choice The choice to check.
  103. * @param string|array $selectedValue The selected value to compare.
  104. *
  105. * @return Boolean Whether the choice is selected.
  106. *
  107. * @see ChoiceView::isSelected()
  108. */
  109. public function isSelectedChoice(ChoiceView $choice, $selectedValue)
  110. {
  111. if (is_array($selectedValue)) {
  112. return false !== array_search($choice->value, $selectedValue, true);
  113. }
  114. return $choice->value === $selectedValue;
  115. }
  116. /**
  117. * {@inheritdoc}
  118. */
  119. public function getName()
  120. {
  121. return 'form';
  122. }
  123. }