diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/form.html.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/form.html.twig index 734799759c..68c5ae2171 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/form.html.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/form.html.twig @@ -1,23 +1,12 @@ -{% block field_row %} +{% block row %} {% spaceless %}
- {# TODO: would be nice to rename this variable to "field" #} - {{ form_label(child) }} - {{ form_errors(child) }} - {{ form_field(child) }} + {{ field.renderer.label }} + {{ field.renderer.errors }} + {{ field.renderer.widget }}
{% endspaceless %} -{% endblock field_row %} - -{% block form %} -{% spaceless %} - {{ form_errors(field) }} - {% for child in field.visibleFields %} - {{ block('field_row') }} - {% endfor %} - {{ form_hidden(field) }} -{% endspaceless %} -{% endblock form %} +{% endblock row %} {% block errors %} {% spaceless %} @@ -34,7 +23,7 @@ {% block hidden %} {% spaceless %} {% for child in field.allHiddenFields %} - {{ form_field(child) }} + {{ child.renderer.widget }} {% endfor %} {% endspaceless %} {% endblock hidden %} @@ -60,35 +49,49 @@ {% endspaceless %} {% endblock field_attributes %} -{% block text_field %} +{% block form__widget %} +{% spaceless %} + {{ field.renderer.errors }} + {% for child in field.visibleFields %} + {{ child.renderer.row }} + {% endfor %} + {{ field.renderer.hidden }} +{% endspaceless %} +{% endblock form__widget %} + +{% block collection__widget %} + {{ block('form__widget') }} +{% endblock collection__widget %} + +{% block text__widget %} {% spaceless %} {% if attr.type is defined and attr.type != "text" %} {% else %} - {% set attr = attr|merge({ 'maxlength': attr.maxlength|default(field.maxlength) }) %} + {% set attr = attr|merge({ 'maxlength': attr.maxlength|default(max_length) }) %} {% endif %} {% endspaceless %} -{% endblock text_field %} +{% endblock text__widget %} -{% block password_field %} +{% block password__widget %} {% spaceless %} {% set attr = attr|merge({ 'maxlength': attr.maxlength|default(field.maxlength) }) %} {% endspaceless %} -{% endblock password_field %} +{% endblock password__widget %} -{% block hidden_field %} +{% block hidden__widget %} {% spaceless %} {% endspaceless %} -{% endblock hidden_field %} +{% endblock hidden__widget %} -{% block textarea_field %} +{% block textarea__widget %} {% spaceless %} {% endspaceless %} -{% endblock textarea_field %} +{% endblock textarea__widget %} {% block options %} {% spaceless %} @@ -106,11 +109,11 @@ {% endspaceless %} {% endblock options %} -{% block choice_field %} +{% block choice__widget %} {% spaceless %} {% if field.isExpanded %} {% for choice, child in field %} - {{ form_field(child) }} + {{ child.renderer.widget }} {% endfor %} {% else %} @@ -125,79 +128,79 @@ {% endif %} {% endspaceless %} -{% endblock choice_field %} +{% endblock choice__widget %} -{% block checkbox_field %} +{% block checkbox__widget %} {% spaceless %} {% endspaceless %} -{% endblock checkbox_field %} +{% endblock checkbox__widget %} -{% block radio_field %} +{% block radio__widget %} {% spaceless %} {% endspaceless %} -{% endblock radio_field %} +{% endblock radio__widget %} -{% block date_time_field %} +{% block date_time__widget %} {% spaceless %} - {{ form_errors(field.date) }} - {{ form_errors(field.time) }} - {{ form_field(field.date) }} - {{ form_field(field.time) }} + {{ field.date.renderer.errors }} + {{ field.time.renderer.errors }} + {{ field.date.renderer.widget }} + {{ field.time.renderer.widget }} {% endspaceless %} -{% endblock date_time_field %} +{% endblock date_time__widget %} -{% block date_field %} +{% block date__widget %} {% spaceless %} {% if field.isField %} - {{ block('text_field') }} + {{ block('text__widget') }} {% else %} - {{ field.pattern|replace({ '{{ year }}': form_field(field.year), '{{ month }}': form_field(field.month), '{{ day }}': form_field(field.day) })|raw }} + {{ field.pattern|replace({ '{{ year }}': field.year.renderer.widget, '{{ month }}': field.month.renderer.widget, '{{ day }}': field.day.renderer.widget })|raw }} {% endif %} {% endspaceless %} -{% endblock date_field %} +{% endblock date__widget %} -{% block time_field %} +{% block time__widget %} {% spaceless %} {% if field.isField %}{% set attr = attr|merge({ 'size': 1 }) %}{% endif %} - {{ form_field(field.hour, attr) }}:{{ form_field(field.minute, attr) }}{% if field.isWithSeconds %}:{{ form_field(field.second, attr) }}{% endif %} + {{ field.hour.renderer.widget(attr) }}:{{ field.minute.renderer.widget(attr) }}{% if field.isWithSeconds %}:{{ field.second.renderer.widget(attr) }}{% endif %} {% endspaceless %} -{% endblock time_field %} +{% endblock time__widget %} -{% block number_field %} +{% block number__widget %} {% spaceless %} {% set attr = attr|merge({ 'type': 'number' }) %} - {{ block('text_field') }} + {{ block('text__widget') }} {% endspaceless %} -{% endblock number_field %} +{% endblock number__widget %} -{% block money_field %} +{% block money__widget %} {% spaceless %} - {{ field.pattern|replace({ '{{ widget }}': block('number_field') })|raw }} + {{ money_pattern|replace({ '{{ widget }}': block('text__widget') })|raw }} {% endspaceless %} -{% endblock money_field %} +{% endblock money__widget %} -{% block url_field %} +{% block url__widget %} {% spaceless %} {% set attr = attr|merge({ 'type': 'url' }) %} - {{ block('text_field') }} + {{ block('text__widget') }} {% endspaceless %} -{% endblock url_field %} +{% endblock url__widget %} -{% block percent_field %} +{% block percent__widget %} {% spaceless %} - {{ block('text_field') }} % + {{ block('text__widget') }} % {% endspaceless %} -{% endblock percent_field %} +{% endblock percent__widget %} -{% block file_field %} +{% block file__widget %} {% spaceless %} {% set group = field %} {% set field = group.file %} - {{ form_field(group.token) }} - {{ form_field(group.original_name) }} + {{ group.token.renderer.widget }} + {{ group.original_name.renderer.widget }} {% endspaceless %} -{% endblock file_field %} +{% endblock file__widget %} diff --git a/src/Symfony/Component/Form/MoneyField.php b/src/Symfony/Component/Form/MoneyField.php index f2b0312a3d..986087a735 100644 --- a/src/Symfony/Component/Form/MoneyField.php +++ b/src/Symfony/Component/Form/MoneyField.php @@ -24,7 +24,7 @@ use Symfony\Component\Form\ValueTransformer\MoneyToLocalizedStringTransformer; * * currency: The currency to display the money with. This is the 3-letter * ISO 4217 currency code. * * divisor: A number to divide the money by before displaying. Default 1. - * + * * @see Symfony\Component\Form\NumberField * @author Bernhard Schussek */ @@ -45,7 +45,6 @@ class MoneyField extends NumberField */ protected function configure() { - $this->addRequiredOption('currency'); $this->addOption('precision', 2); $this->addOption('divisor', 1); @@ -57,44 +56,4 @@ class MoneyField extends NumberField 'divisor' => $this->getOption('divisor'), ))); } - - /** - * Returns the pattern for this locale - * - * The pattern contains the placeholder "{{ widget }}" where the HTML tag should - * be inserted - */ - public function getPattern() - { - if (!$this->getOption('currency')) { - return '{{ widget }}'; - } - - if (!isset(self::$patterns[\Locale::getDefault()])) { - self::$patterns[\Locale::getDefault()] = array(); - } - - if (!isset(self::$patterns[\Locale::getDefault()][$this->getOption('currency')])) { - $format = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::CURRENCY); - $pattern = $format->formatCurrency('123', $this->getOption('currency')); - - // the spacings between currency symbol and number are ignored, because - // a single space leads to better readability in combination with input - // fields - - // the regex also considers non-break spaces (0xC2 or 0xA0 in UTF-8) - - preg_match('/^([^\s\xc2\xa0]*)[\s\xc2\xa0]*123[,.]00[\s\xc2\xa0]*([^\s\xc2\xa0]*)$/', $pattern, $matches); - - if (!empty($matches[1])) { - self::$patterns[\Locale::getDefault()] = $matches[1].' {{ widget }}'; - } else if (!empty($matches[2])) { - self::$patterns[\Locale::getDefault()] = '{{ widget }} '.$matches[2]; - } else { - self::$patterns[\Locale::getDefault()] = '{{ widget }}'; - } - } - - return self::$patterns[\Locale::getDefault()]; - } } diff --git a/src/Symfony/Component/Form/Renderer/DefaultRenderer.php b/src/Symfony/Component/Form/Renderer/DefaultRenderer.php new file mode 100644 index 0000000000..d8034d7be5 --- /dev/null +++ b/src/Symfony/Component/Form/Renderer/DefaultRenderer.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Renderer; + +use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\Renderer\Theme\ThemeInterface; +use Symfony\Component\Form\Renderer\Plugin\PluginInterface; + +class DefaultRenderer implements RendererInterface +{ + private $field; + + private $template; + + private $theme; + + private $parameters = array(); + + private $plugins = array(); + + private $initialized = false; + + public function __construct(ThemeInterface $theme, $template) + { + $this->theme = $theme; + $this->template = $template; + } + + private function setUpPlugins() + { + if (!$this->initialized) { + $this->initialized = true; + + foreach ($this->plugins as $plugin) { + $plugin->setUp($this); + } + } + } + + public function setTheme(ThemeInterface $theme) + { + $this->theme = $theme; + } + + public function getTheme() + { + return $this->theme; + } + + public function addPlugin(PluginInterface $plugin) + { + $this->initialized = false; + $this->plugins[] = $plugin; + } + + public function setParameter($name, $value) + { + $this->parameters[$name] = $value; + } + + public function getWidget(array $attributes = array(), array $parameters = array()) + { + return $this->render('widget', $attributes, $parameters); + } + + public function getErrors(array $attributes = array(), array $parameters = array()) + { + return $this->render('errors', $attributes, $parameters); + } + + public function getRow(array $attributes = array(), array $parameters = array()) + { + return $this->render('row', $attributes, $parameters); + } + + public function getHidden(array $attributes = array(), array $parameters = array()) + { + return $this->render('hidden', $attributes, $parameters); + } + + /** + * Renders the label of the given field + * + * @param FieldInterface $field The field to render the label for + * @param array $params Additional variables passed to the template + */ + public function getLabel($label = null, array $attributes = array(), array $parameters = array()) + { + if (null !== $label) { + $parameters['label'] = $label; + } + + return $this->render('label', $attributes, $parameters); + } + + protected function render($block, array $attributes = array(), array $parameters = array()) + { + $this->setUpPlugins(); + + return $this->theme->render($this->template, $block, array_replace( + array('attr' => $attributes), + $this->parameters, + $parameters + )); + } +} \ No newline at end of file diff --git a/src/Symfony/Component/Form/Renderer/Engine/TwigEngine.php b/src/Symfony/Component/Form/Renderer/Engine/TwigEngine.php deleted file mode 100644 index 3a2bc8a0da..0000000000 --- a/src/Symfony/Component/Form/Renderer/Engine/TwigEngine.php +++ /dev/null @@ -1,120 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form\Renderer\Engine; - -use Symfony\Component\Form\Form; -use Symfony\Component\Form\FieldInterface; - -class TwigEngine implements EngineInterface -{ - protected $environment; - protected $resources; - - public function __construct(\Twig_Environment $environment, array $resources = array()) - { - $this->environment = $environment; - $this->resources = $resources; - } - - public function render(FieldInterface $field, $name, array $arguments, array $resources = null) - { - if ('field' === $name) { - list($name, $template) = $this->getWidget($field, $resources); - } else { - $template = $this->getTemplate($field, $name); - } - - return $template->renderBlock($name, $arguments); - } - - /** - * @param FieldInterface $field The field to get the widget for - * @param array $resources An array of template resources - * @return array - */ - protected function getWidget(FieldInterface $field, array $resources = null) - { - $class = get_class($field); - $templates = $this->getTemplates($field, $resources); - - // find a template for the given class or one of its parents - do { - $parts = explode('\\', $class); - $c = array_pop($parts); - - // convert the base class name (e.g. TextareaField) to underscores (e.g. textarea_field) - $underscore = strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($c, '_', '.'))); - - if (isset($templates[$underscore])) { - return array($underscore, $templates[$underscore]); - } - } while (false !== $class = get_parent_class($class)); - - throw new \RuntimeException(sprintf('Unable to render the "%s" field.', $field->getKey())); - } - - protected function getTemplate(FieldInterface $field, $name, array $resources = null) - { - $templates = $this->getTemplates($field, $resources); - - return $templates[$name]; - } - - protected function getTemplates(FieldInterface $field, array $resources = null) - { - // templates are looked for in the following resources: - // * resources provided directly into the function call - // * resources from the themes (and its parents) - // * default resources - - // defaults - $all = $this->resources; - - // themes - $parent = $field; - do { - if (isset($this->themes[$parent])) { - $all = array_merge($all, $this->themes[$parent]); - } - } while ($parent = $parent->getParent()); - - // local - $all = array_merge($all, null !== $resources ? (array) $resources : array()); - - $templates = array(); - foreach ($all as $resource) { - if (!$resource instanceof \Twig_Template) { - $resource = $this->environment->loadTemplate($resource); - } - - $blocks = array(); - foreach ($this->getBlockNames($resource) as $name) { - $blocks[$name] = $resource; - } - - $templates = array_replace($templates, $blocks); - } - - return $templates; - } - - protected function getBlockNames($resource) - { - $names = $resource->getBlockNames(); - $parent = $resource; - while (false !== $parent = $parent->getParent(array())) { - $names = array_merge($names, $parent->getBlockNames()); - } - - return array_unique($names); - } -} \ No newline at end of file diff --git a/src/Symfony/Component/Form/Renderer/FieldRenderer.php b/src/Symfony/Component/Form/Renderer/FieldRenderer.php deleted file mode 100644 index 4afaa532cb..0000000000 --- a/src/Symfony/Component/Form/Renderer/FieldRenderer.php +++ /dev/null @@ -1,146 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form\Renderer; - -use Symfony\Component\Form\FieldInterface; -use Symfony\Component\Form\Renderer\Engine\EngineInterface; - -class FieldRenderer implements RendererInterface -{ - private $field; - - private $engine; - - public function __construct(FieldInterface $field, EngineInterface $engine) - { - $this->field = $field; - $this->engine = $engine; - } - - protected function getField() - { - return $this->field; - } - - protected function getEngine() - { - return $this->engine; - } - - public function __toString() - { - return $this->widget(); - } - - /** - * Renders the HTML enctype in the form tag, if necessary - * - * Example usage in Twig templates: - * - *
- * - * @param Form $form The form for which to render the encoding type - */ - public function enctype() - { - return $this->field->isMultipart() ? 'enctype="multipart/form-data"' : ''; - } - - /** - * Renders a field row. - * - * @param FieldInterface $field The field to render as a row - */ - public function row() - { - return $this->engine->render($this->field, 'field_row', array( - 'child' => $this->field, - )); - } - - /** - * Renders the HTML for an individual form field - * - * Example usage in Twig: - * - * {{ form_field(field) }} - * - * You can pass attributes element during the call: - * - * {{ form_field(field, {'class': 'foo'}) }} - * - * Some fields also accept additional variables as parameters: - * - * {{ form_field(field, {}, {'separator': '+++++'}) }} - * - * @param FieldInterface $field The field to render - * @param array $attributes HTML attributes passed to the template - * @param array $parameters Additional variables passed to the template - * @param array|string $resources A resource or array of resources - */ - public function widget(array $attributes = array(), array $parameters = array(), $resources = null) - { - if (null !== $resources && !is_array($resources)) { - $resources = array($resources); - } - - return $this->engine->render($this->field, 'field', array( - 'field' => $this->field, - 'attr' => $attributes, - 'params' => $parameters, - ), $resources); - } - - /** - * Renders all hidden fields of the given field group - * - * @param FormInterface $group The field group - * @param array $params Additional variables passed to the - * template - */ - public function hidden(array $parameters = array()) - { - return $this->engine->render($this->field, 'hidden', array( - 'field' => $this->field, - 'params' => $parameters, - )); - } - - /** - * Renders the errors of the given field - * - * @param FieldInterface $field The field to render the errors for - * @param array $params Additional variables passed to the template - */ - public function errors(array $parameters = array()) - { - return $this->engine->render($this->field, 'errors', array( - 'field' => $this->field, - 'params' => $parameters, - )); - } - - /** - * Renders the label of the given field - * - * @param FieldInterface $field The field to render the label for - * @param array $params Additional variables passed to the template - */ - public function label($label = null, array $parameters = array()) - { - return $this->render($this->field, 'label', array( - 'field' => $this->field, - 'params' => $parameters, - 'label' => null !== $label ? $label : ucfirst(strtolower(str_replace('_', ' ', $this->field->getKey()))), - )); - } -} \ No newline at end of file diff --git a/src/Symfony/Component/Form/Renderer/FormRenderer.php b/src/Symfony/Component/Form/Renderer/FormRenderer.php deleted file mode 100644 index ab766a883f..0000000000 --- a/src/Symfony/Component/Form/Renderer/FormRenderer.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form\Renderer; - -use Symfony\Component\Form\FormInterface; -use Symfony\Component\Form\Renderer\Engine\EngineInterface; - -class FormRenderer extends FieldRenderer -{ - public function __construct(FormInterface $form, EngineInterface $engine) - { - parent::__construct($form, $engine); - } - - /** - * Renders the HTML enctype in the form tag, if necessary - * - * Example usage in Twig templates: - * - * - * - * @param Form $form The form for which to render the encoding type - */ - public function enctype() - { - return $this->getField()->isMultipart() ? 'enctype="multipart/form-data"' : ''; - } -} \ No newline at end of file diff --git a/src/Symfony/Component/Form/Renderer/Plugin/EnctypePlugin.php b/src/Symfony/Component/Form/Renderer/Plugin/EnctypePlugin.php new file mode 100644 index 0000000000..6249f72141 --- /dev/null +++ b/src/Symfony/Component/Form/Renderer/Plugin/EnctypePlugin.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license infieldation, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Renderer\Plugin; + +use Symfony\Component\Form\Renderer\RendererInterface; +use Symfony\Component\Form\FieldInterface; + +class EnctypePlugin implements PluginInterface +{ + private $field; + + public function __construct(FieldInterface $field) + { + $this->field = $field; + } + + /** + * Renders the HTML enctype in the field tag, if necessary + * + * Example usage in Twig templates: + * + * + * + * @param Form $field The field for which to render the encoding type + */ + public function setUp(RendererInterface $renderer) + { + $renderer->setParameter('enctype', $this->field->isMultipart() ? 'enctype="multipart/form-data"' : ''); + } +} \ No newline at end of file diff --git a/src/Symfony/Component/Form/Renderer/Plugin/MaxLengthPlugin.php b/src/Symfony/Component/Form/Renderer/Plugin/MaxLengthPlugin.php new file mode 100644 index 0000000000..3e8d5ebe18 --- /dev/null +++ b/src/Symfony/Component/Form/Renderer/Plugin/MaxLengthPlugin.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license infieldation, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Renderer\Plugin; + +use Symfony\Component\Form\Renderer\RendererInterface; +use Symfony\Component\Form\FieldInterface; + +class MaxLengthPlugin implements PluginInterface +{ + private $maxLength; + + public function __construct($maxLength) + { + $this->maxLength = $maxLength; + } + + /** + * Renders the HTML enctype in the field tag, if necessary + * + * Example usage in Twig templates: + * + * + * + * @param Form $field The field for which to render the encoding type + */ + public function setUp(RendererInterface $renderer) + { + $renderer->setParameter('max_length', $this->maxLength); + } +} \ No newline at end of file diff --git a/src/Symfony/Component/Form/Renderer/Plugin/MoneyPatternPlugin.php b/src/Symfony/Component/Form/Renderer/Plugin/MoneyPatternPlugin.php new file mode 100644 index 0000000000..a81c0d64a9 --- /dev/null +++ b/src/Symfony/Component/Form/Renderer/Plugin/MoneyPatternPlugin.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Renderer\Plugin; + +use Symfony\Component\Form\Renderer\RendererInterface; + +class MoneyPatternPlugin implements PluginInterface +{ + private static $patterns = array(); + + private $currency = 'EUR'; + + public function __construct($currency) + { + $this->currency = $currency; + } + + public function setUp(RendererInterface $renderer) + { + $renderer->setParameter('money_pattern', self::getPattern($this->currency)); + } + + /** + * Returns the pattern for this locale + * + * The pattern contains the placeholder "{{ widget }}" where the HTML tag should + * be inserted + */ + private static function getPattern($currency) + { + if (!$currency) { + return '{{ widget }}'; + } + + if (!isset(self::$patterns[\Locale::getDefault()])) { + self::$patterns[\Locale::getDefault()] = array(); + } + + if (!isset(self::$patterns[\Locale::getDefault()][$currency])) { + $format = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::CURRENCY); + $pattern = $format->formatCurrency('123', $currency); + + // the spacings between currency symbol and number are ignored, because + // a single space leads to better readability in combination with input + // fields + + // the regex also considers non-break spaces (0xC2 or 0xA0 in UTF-8) + + preg_match('/^([^\s\xc2\xa0]*)[\s\xc2\xa0]*123[,.]00[\s\xc2\xa0]*([^\s\xc2\xa0]*)$/', $pattern, $matches); + + if (!empty($matches[1])) { + self::$patterns[\Locale::getDefault()] = $matches[1].' {{ widget }}'; + } else if (!empty($matches[2])) { + self::$patterns[\Locale::getDefault()] = '{{ widget }} '.$matches[2]; + } else { + self::$patterns[\Locale::getDefault()] = '{{ widget }}'; + } + } + + return self::$patterns[\Locale::getDefault()]; + } +} \ No newline at end of file diff --git a/src/Symfony/Component/Form/Renderer/Plugin/PluginInterface.php b/src/Symfony/Component/Form/Renderer/Plugin/PluginInterface.php new file mode 100644 index 0000000000..40942628aa --- /dev/null +++ b/src/Symfony/Component/Form/Renderer/Plugin/PluginInterface.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Renderer\Plugin; + +use Symfony\Component\Form\Renderer\RendererInterface; + +interface PluginInterface +{ + function setUp(RendererInterface $renderer); +} \ No newline at end of file diff --git a/src/Symfony/Component/Form/Renderer/RendererInterface.php b/src/Symfony/Component/Form/Renderer/RendererInterface.php index b2308e9277..374962b2c4 100644 --- a/src/Symfony/Component/Form/Renderer/RendererInterface.php +++ b/src/Symfony/Component/Form/Renderer/RendererInterface.php @@ -13,4 +13,21 @@ namespace Symfony\Component\Form\Renderer; interface RendererInterface { + function setParameter($name, $value); + + function getWidget(array $attributes = array(), array $parameters = array()); + + function getErrors(array $attributes = array(), array $parameters = array()); + + function getRow(array $attributes = array(), array $parameters = array()); + + function getHidden(array $attributes = array(), array $parameters = array()); + + /** + * Renders the label of the given field + * + * @param FieldInterface $field The field to render the label for + * @param array $params Additional variables passed to the template + */ + function getLabel($label = null, array $attributes = array(), array $parameters = array()); } \ No newline at end of file diff --git a/src/Symfony/Component/Form/Renderer/Engine/EngineInterface.php b/src/Symfony/Component/Form/Renderer/Theme/ThemeInterface.php similarity index 66% rename from src/Symfony/Component/Form/Renderer/Engine/EngineInterface.php rename to src/Symfony/Component/Form/Renderer/Theme/ThemeInterface.php index 1f7e3d4609..81afa79df3 100644 --- a/src/Symfony/Component/Form/Renderer/Engine/EngineInterface.php +++ b/src/Symfony/Component/Form/Renderer/Theme/ThemeInterface.php @@ -9,8 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Renderer\Engine; +namespace Symfony\Component\Form\Renderer\Theme; -interface EngineInterface +interface ThemeInterface { + function render($template, $block, array $parameters); } diff --git a/src/Symfony/Component/Form/Renderer/Theme/TwigTheme.php b/src/Symfony/Component/Form/Renderer/Theme/TwigTheme.php new file mode 100644 index 0000000000..087438077a --- /dev/null +++ b/src/Symfony/Component/Form/Renderer/Theme/TwigTheme.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Renderer\Theme; + +use Symfony\Component\Form\Form; +use Symfony\Component\Form\FieldInterface; +use Symfony\Component\Form\Exception\FormException; + +class TwigTheme implements ThemeInterface +{ + private $environment; + private $template; + private $blocks; + + public function __construct(\Twig_Environment $environment, $template) + { + $this->environment = $environment; + $this->template = $template; + } + + private function initialize() + { + if (!$this->blocks) { + $this->blocks = array(); + + if (!$this->template instanceof \Twig_Template) { + $this->template = $this->environment->loadTemplate($this->template); + } + + foreach ($this->getBlockNames($this->template) as $blockName) { + $this->blocks[$blockName] = true; + } + } + } + + private function getBlockNames(\Twig_Template $template) + { + $names = $template->getBlockNames(); + $parent = $template; + + while (false !== $parent = $parent->getParent(array())) { + $names = array_merge($names, $parent->getBlockNames()); + } + + return array_unique($names); + } + + public function render($template, $block, array $parameters) + { + $this->initialize(); + + if (isset($this->blocks[$template.'__'.$block])) { + $blockName = $template.'__'.$block; + } else if (isset($this->blocks[$block])) { + $blockName = $block; + } else { + throw new FormException(sprintf('The form theme is missing the "%s" block', $block)); + } + + return $this->template->renderBlock($blockName, $parameters); + } +} \ No newline at end of file diff --git a/src/Symfony/Component/Form/TextField.php b/src/Symfony/Component/Form/TextField.php index 64b1ca3cfb..04362db59e 100644 --- a/src/Symfony/Component/Form/TextField.php +++ b/src/Symfony/Component/Form/TextField.php @@ -22,18 +22,4 @@ namespace Symfony\Component\Form; */ class TextField extends Field { - /** - * {@inheritDoc} - */ - protected function configure() - { - $this->addOption('max_length'); - - parent::configure(); - } - - public function getMaxLength() - { - return $this->getOption('max_length'); - } }