[Form] Improved the renderer implementation, added concepts of plugins and themes
This commit is contained in:
parent
6cc0a58edc
commit
ed68fd66a9
@ -1,23 +1,12 @@
|
||||
{% block field_row %}
|
||||
{% block row %}
|
||||
{% spaceless %}
|
||||
<div>
|
||||
{# 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 }}
|
||||
</div>
|
||||
{% 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" %}
|
||||
<input {{ block('field_attributes') }} value="{{ field.displayedData }}" />
|
||||
{% else %}
|
||||
{% set attr = attr|merge({ 'maxlength': attr.maxlength|default(field.maxlength) }) %}
|
||||
{% set attr = attr|merge({ 'maxlength': attr.maxlength|default(max_length) }) %}
|
||||
<input type="text" {{ block('field_attributes') }} value="{{ field.displayedData }}" />
|
||||
{% 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) }) %}
|
||||
<input type="password" {{ block('field_attributes') }} value="{{ field.displayedData }}" />
|
||||
{% endspaceless %}
|
||||
{% endblock password_field %}
|
||||
{% endblock password__widget %}
|
||||
|
||||
{% block hidden_field %}
|
||||
{% block hidden__widget %}
|
||||
{% spaceless %}
|
||||
<input type="hidden" id="{{ field.id }}" name="{{ field.name }}"{% if field.disabled %} disabled="disabled"{% endif %} value="{{ field.displayedData }}" />
|
||||
{% endspaceless %}
|
||||
{% endblock hidden_field %}
|
||||
{% endblock hidden__widget %}
|
||||
|
||||
{% block textarea_field %}
|
||||
{% block textarea__widget %}
|
||||
{% spaceless %}
|
||||
<textarea {{ block('field_attributes') }}>{{ field.displayedData }}</textarea>
|
||||
{% 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 }}
|
||||
<label for="{{ child.id }}">{{ field.label(choice) }}</label>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
@ -125,79 +128,79 @@
|
||||
</select>
|
||||
{% endif %}
|
||||
{% endspaceless %}
|
||||
{% endblock choice_field %}
|
||||
{% endblock choice__widget %}
|
||||
|
||||
{% block checkbox_field %}
|
||||
{% block checkbox__widget %}
|
||||
{% spaceless %}
|
||||
<input type="checkbox" {{ block('field_attributes') }}{% if field.hasValue %} value="{{ field.value }}"{% endif %}{% if field.ischecked %} checked="checked"{% endif %} />
|
||||
{% endspaceless %}
|
||||
{% endblock checkbox_field %}
|
||||
{% endblock checkbox__widget %}
|
||||
|
||||
{% block radio_field %}
|
||||
{% block radio__widget %}
|
||||
{% spaceless %}
|
||||
<input type="radio" {{ block('field_attributes') }}{% if field.hasValue %} value="{{ field.value }}"{% endif %}{% if field.ischecked %} checked="checked"{% endif %} />
|
||||
{% 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 %}
|
||||
<input type="file" {{ block('field_attributes') }} />
|
||||
{{ 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 %}
|
||||
|
||||
|
@ -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 <bernhard.schussek@symfony-project.com>
|
||||
*/
|
||||
@ -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()];
|
||||
}
|
||||
}
|
||||
|
115
src/Symfony/Component/Form/Renderer/DefaultRenderer.php
Normal file
115
src/Symfony/Component/Form/Renderer/DefaultRenderer.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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
|
||||
));
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* <form action="..." method="post" {{ form.render.enctype }}>
|
||||
*
|
||||
* @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()))),
|
||||
));
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* <form action="..." method="post" {{ form.render.enctype }}>
|
||||
*
|
||||
* @param Form $form The form for which to render the encoding type
|
||||
*/
|
||||
public function enctype()
|
||||
{
|
||||
return $this->getField()->isMultipart() ? 'enctype="multipart/form-data"' : '';
|
||||
}
|
||||
}
|
39
src/Symfony/Component/Form/Renderer/Plugin/EnctypePlugin.php
Normal file
39
src/Symfony/Component/Form/Renderer/Plugin/EnctypePlugin.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* <field action="..." method="post" {{ field.render.enctype }}>
|
||||
*
|
||||
* @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"' : '');
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* <field action="..." method="post" {{ field.render.enctype }}>
|
||||
*
|
||||
* @param Form $field The field for which to render the encoding type
|
||||
*/
|
||||
public function setUp(RendererInterface $renderer)
|
||||
{
|
||||
$renderer->setParameter('max_length', $this->maxLength);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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()];
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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);
|
||||
}
|
@ -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());
|
||||
}
|
@ -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);
|
||||
}
|
71
src/Symfony/Component/Form/Renderer/Theme/TwigTheme.php
Normal file
71
src/Symfony/Component/Form/Renderer/Theme/TwigTheme.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user