diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml index 375e02fd00..c6edded851 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml @@ -20,8 +20,7 @@ Symfony\Bundle\FrameworkBundle\Templating\Helper\CodeHelper Symfony\Bundle\FrameworkBundle\Templating\Helper\TranslatorHelper Symfony\Bundle\FrameworkBundle\Templating\Helper\SecurityHelper - Symfony\Bundle\FrameworkBundle\Templating\Form\Form - Symfony\Bundle\FrameworkBundle\Templating\HtmlGenerator + Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper false null @@ -29,8 +28,6 @@ - - @@ -111,9 +108,9 @@ - + + - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/checkbox_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/checkbox_field.php new file mode 100644 index 0000000000..bc5f3a0b28 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/checkbox_field.php @@ -0,0 +1,7 @@ +isDisabled()): ?>disabled="disabled" + isChecked()): ?>checked="checked" +/> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_field.php new file mode 100644 index 0000000000..13e23906b9 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/choice_field.php @@ -0,0 +1,47 @@ +isExpanded()): ?> + $child): ?> + render($child) ?> + + + + + \ No newline at end of file diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/date_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/date_field.php new file mode 100644 index 0000000000..6a927b3efa --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/date_field.php @@ -0,0 +1,14 @@ +isField()): ?> + isDisabled()): ?>disabled="disabled" + /> + + render($field['year']), + $view['form']->render($field['month']), + $view['form']->render($field['day']), + ), $field->getPattern()) ?> + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/date_time_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/date_time_field.php new file mode 100644 index 0000000000..9c3d39f44f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/date_time_field.php @@ -0,0 +1,3 @@ +render($field['date']) ?> + +render($field['time']) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/errors.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/errors.php index 9ade44ed9f..1a4308330f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/errors.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/errors.php @@ -1,7 +1,7 @@ - +hasErrors()): ?>
    - + getErrors() as $error): ?>
  • trans($error[0], $error[1], 'validators') ?>
- + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_group.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_group.php new file mode 100644 index 0000000000..9eb28bcc4f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/field_group.php @@ -0,0 +1,13 @@ +errors($field) ?> + +
+ getVisibleFields() as $child): ?> +
+ label($child) ?> + errors($child) ?> + render($child) ?> +
+ +
+ +hidden($field) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/file_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/file_field.php new file mode 100644 index 0000000000..09f3e1fda7 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/file_field.php @@ -0,0 +1,5 @@ +isDisabled()): ?>disabled="disabled" +/> \ No newline at end of file diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/div/field_group.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/div/field_group.php deleted file mode 100644 index fce7c0c260..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/div/field_group.php +++ /dev/null @@ -1,9 +0,0 @@ -errors() ?> - -
- - render() ?> - -
- -hidden() ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/div/row.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/div/row.php deleted file mode 100644 index 2960ecec7f..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/div/row.php +++ /dev/null @@ -1,5 +0,0 @@ -
- label() ?> - errors() ?> - field() ?> -
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/table/field_group.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/table/field_group.php deleted file mode 100644 index f4eeba6ce8..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/table/field_group.php +++ /dev/null @@ -1,9 +0,0 @@ -errors() ?> - - - - render() ?> - -
- -hidden() ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/table/row.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/table/row.php deleted file mode 100644 index 8d42093f86..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/group/table/row.php +++ /dev/null @@ -1,9 +0,0 @@ - - - label() ?> - - - errors() ?> - widget() ?> - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden.php index 8d53c09b7b..6e0aedc783 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden.php @@ -1,3 +1,3 @@ - - widget() ?> +getAllHiddenFields() as $child): ?> + render($child) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden_field.php new file mode 100644 index 0000000000..fe0a512723 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/hidden_field.php @@ -0,0 +1,6 @@ +isDisabled()): ?>disabled="disabled" +/> \ No newline at end of file diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/label.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/label.php index d975823806..842e4b0777 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/label.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/label.php @@ -1 +1 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/money_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/money_field.php new file mode 100644 index 0000000000..1e546a8de4 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/money_field.php @@ -0,0 +1,4 @@ +render($field, array(), array(), 'FrameworkBundle:Form:number_field.php'), + $field->getPattern() +) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_field.php new file mode 100644 index 0000000000..cb23986487 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_field.php @@ -0,0 +1,6 @@ +isDisabled()): ?>disabled="disabled" +/> \ No newline at end of file diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_field.php new file mode 100644 index 0000000000..7a65a9470b --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_field.php @@ -0,0 +1 @@ +render($field, array(), array(), 'FrameworkBundle:Form:number_field.php') ?> % diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/radio_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/radio_field.php new file mode 100644 index 0000000000..236e7edab6 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/radio_field.php @@ -0,0 +1,7 @@ +isDisabled()): ?>disabled="disabled" + isChecked()): ?>checked="checked" +/> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/text_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/text_field.php new file mode 100644 index 0000000000..d485f4912b --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/text_field.php @@ -0,0 +1,8 @@ +isDisabled()): ?>disabled="disabled" + getMaxLength() > 0) $attr['maxlength'] = $field->getMaxLength() ?> + attributes($attr) ?> +/> \ No newline at end of file diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/textarea_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/textarea_field.php new file mode 100644 index 0000000000..c30b8545eb --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/textarea_field.php @@ -0,0 +1,3 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/time_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/time_field.php new file mode 100644 index 0000000000..707fa6021b --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/time_field.php @@ -0,0 +1,12 @@ +render($field['hour'], array('size' => 1)); + echo ':'; + echo $view['form']->render($field['minute'], array('size' => 1)); + + if ($field->isWithSeconds()) { + echo ':'; + echo $view['form']->render($field['second'], array('size' => 1)); + } +?> \ No newline at end of file diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/choice_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/choice_field.php deleted file mode 100644 index dd7cb72c56..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/choice_field.php +++ /dev/null @@ -1,9 +0,0 @@ -getOption('expanded')): ?> - - widget() ?> - - - contentTag('select', - $generator->choices($origin->getPreferredChoices(), $origin->getOtherChoices(), $origin->getEmptyValue(), $origin->getSelected()), - $attributes) ?> - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/date_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/date_field.php deleted file mode 100644 index 4787cc8af7..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/date_field.php +++ /dev/null @@ -1,9 +0,0 @@ -isField()): ?> - tag('input', $attributes) ?> - - widget($attributes), - $field['month']->widget($attributes), - $field['day']->widget($attributes), - ), $origin->getPattern()) ?> - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/date_time_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/date_time_field.php deleted file mode 100644 index bc349b78fa..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/date_time_field.php +++ /dev/null @@ -1,2 +0,0 @@ -widget($attributes) ?> -widget($attributes) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/input_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/input_field.php deleted file mode 100644 index c425fcfa9f..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/input_field.php +++ /dev/null @@ -1 +0,0 @@ -tag('input', $attributes) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/money_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/money_field.php deleted file mode 100644 index 9e55562f38..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/money_field.php +++ /dev/null @@ -1,6 +0,0 @@ -render('FrameworkBundle:Form:widget/input_field.php', array( - 'field' => $field, - 'origin' => $origin, - 'attributes' => $attributes, - 'generator' => $generator, -)), $origin->getPattern()) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/percent_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/percent_field.php deleted file mode 100644 index ecef83aa61..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/percent_field.php +++ /dev/null @@ -1,6 +0,0 @@ -render('FrameworkBundle:Form:widget/input_field.php', array( - 'field' => $field, - 'origin' => $origin, - 'attributes' => $attributes, - 'generator' => $generator, -)) ?> % diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/textarea_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/textarea_field.php deleted file mode 100644 index b2d00dcb1b..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/textarea_field.php +++ /dev/null @@ -1 +0,0 @@ -contentTag('textarea', $view->escape($origin->getDisplayedData()), $attributes) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/time_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/time_field.php deleted file mode 100644 index 76cb2c2bb1..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/time_field.php +++ /dev/null @@ -1,9 +0,0 @@ -isField()): ?> - tag('input', $attributes) ?> - - widget($attributes).':'.$field['minute']->widget($attributes) ?> - - getOption('with_seconds')): ?> - widget($attributes) ?> - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/toggle_field.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/toggle_field.php deleted file mode 100644 index 373cd28cf4..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/widget/toggle_field.php +++ /dev/null @@ -1,11 +0,0 @@ -render('FrameworkBundle:Form:widget/input_field.php', array( - 'field' => $field, - 'origin' => $origin, - 'attributes' => $attributes, - 'generator' => $generator, - )) -?> - -getOption('label')): ?> - contentTag('label', $view['translator']->trans($label), array('for' => $origin->getId())) ?> - diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/BaseField.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Form/BaseField.php deleted file mode 100644 index f7863d273b..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/BaseField.php +++ /dev/null @@ -1,132 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -/** - * - * - * @author Fabien Potencier - */ -abstract class BaseField implements FieldInterface, SafeDecoratorInterface -{ - protected $engine; - protected $field; - protected $generator; - protected $theme; - protected $doctype; - - public function __construct(FormFieldInterface $field, Engine $engine, HtmlGeneratorInterface $generator, $theme, $doctype) - { - $this->field = $field; - $this->engine = $engine; - $this->generator = $generator; - $this->theme = $theme; - } - - public function getIterator() - { - if (!$this->field instanceof FieldGroupInterface) { - throw new \LogicException(sprintf('Cannot iterate a non group field (%s)', $this->field->getKey())); - } - - $fields = array(); - foreach ($this->field->getFields() as $field) { - if (!$field->isHidden()) { - $fields[] = $field; - } - } - - return new \ArrayIterator($this->wrapFields($fields)); - } - - /** - * Returns true if the bound field exists (implements the \ArrayAccess interface). - * - * @param string $key The key of the bound field - * - * @return Boolean true if the widget exists, false otherwise - */ - public function offsetExists($key) - { - if (!$this->field instanceof FieldGroupInterface) { - throw new \LogicException(sprintf('Cannot access a non group field as an array (%s)', $this->field->getKey())); - } - - return $this->field->has($key); - } - - /** - * Returns the form field associated with the name (implements the \ArrayAccess interface). - * - * @param string $key The offset of the value to get - * - * @return Field A form field instance - */ - public function offsetGet($key) - { - if (!$this->field instanceof FieldGroupInterface) { - throw new \LogicException(sprintf('Cannot access a non group field as an array (%s)', $this->field->getKey())); - } - - return $this->createField($this->field->get($key)); - } - - /** - * Throws an exception saying that values cannot be set (implements the \ArrayAccess interface). - * - * @param string $offset (ignored) - * @param string $value (ignored) - * - * @throws \LogicException - */ - public function offsetSet($key, $field) - { - throw new \LogicException('This helper is read-only'); - } - - /** - * Throws an exception saying that values cannot be unset (implements the \ArrayAccess interface). - * - * @param string $key - * - * @throws \LogicException - */ - public function offsetUnset($key) - { - throw new \LogicException('This helper is read-only'); - } - - protected function wrapFields($fields) - { - foreach ($fields as $id => $field) { - $fields[$id] = $this->createField($field); - } - - return $fields; - } - - protected function createField(FormFieldInterface $field) - { - if ($field instanceof FieldGroupInterface && !$field instanceof HybridField) { - return new FieldGroup($field, $this->engine, $this->generator, $this->theme, $this->doctype); - } - - return new Field($field, $this->engine, $this->generator, $this->theme, $this->doctype); - } -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/Field.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Form/Field.php deleted file mode 100644 index 8f01c47fc1..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/Field.php +++ /dev/null @@ -1,107 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -/** - * Field wraps a Form\FieldInterface instance. - * - * @author Fabien Potencier - */ -class Field extends BaseField -{ - static protected $cache = array(); - - public function render($template = null) - { - if ($this->field instanceof FieldGroupInterface && !$this->field instanceof HybridField) { - throw new \LogicException(sprintf('Cannot render a group field as a row (%s)', $this->field->getKey())); - } - - if (null === $template) { - $template = sprintf('FrameworkBundle:Form:group/%s/row.php', $this->theme); - } - - return $this->engine->render($template, array('field' => $this)); - } - - public function data() - { - return $this->field->getData(); - } - - public function widget(array $attributes = array(), $template = null) - { - if ($this->field instanceof FieldGroupInterface && !$this->field instanceof HybridField) { - throw new \LogicException(sprintf('Cannot render a group field (%s)', $this->field->getKey())); - } - - if (null === $template) { - $template = $this->getTemplate(); - } - - return $this->engine->render($template, array( - 'field' => $this, - 'origin' => $this->field, - 'attributes' => array_merge($this->field->getAttributes(), $attributes), - 'generator' => $this->generator, - )); - } - - public function label($label = false, $template = null) - { - if (null === $template) { - $template = 'FrameworkBundle:Form:label.php'; - } - - return $this->engine->render($template, array( - 'field' => $this, - 'id' => $this->field->getId(), - 'key' => $this->field->getKey(), - 'label' => $label ? $label : ucfirst(strtolower(str_replace('_', ' ', $this->field->getKey()))) - )); - } - - public function errors($template = null) - { - if (null === $template) { - $template = 'FrameworkBundle:Form:errors.php'; - } - - return $this->engine->render($template, array('field' => $this, 'errors' => $this->field->getErrors())); - } - - protected function getTemplate() - { - $class = get_class($this->field); - - if (isset(self::$cache[$class])) { - return self::$cache[$class]; - } - - // find a template for the given class or one of its parents - do { - $parts = explode('\\', $class); - $c = array_pop($parts); - - $underscore = strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($c, '_', '.'))); - - if ($this->engine->exists($template = 'FrameworkBundle:Form:widget/'.$underscore.'.php')) { - return self::$cache[$class] = $template; - } - } while (false !== $class = get_parent_class($class)); - - throw new \RuntimeException(sprintf('Unable to find a template to render the "%s" widget.', $this->field->getKey())); - } -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/FieldGroup.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Form/FieldGroup.php deleted file mode 100644 index 791270416c..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/FieldGroup.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -/** - * FieldGroup wraps a Form\FieldGroupInterface instance. - * - * @author Fabien Potencier - */ -class FieldGroup extends BaseField -{ - /** - * Renders the form tag. - * - * This method only renders the opening form tag. - * You need to close it after the form rendering. - * - * This method takes into account the multipart widgets. - * - * @param string $url The URL for the action - * @param array $attributes An array of HTML attributes - * - * @return string An HTML representation of the opening form tag - */ - public function form($url, array $attributes = array()) - { - return sprintf('', $this->generator->attributes(array_merge(array( - 'action' => $url, - 'method' => isset($attributes['method']) ? strtolower($attributes['method']) : 'post', - 'enctype' => $this->field->isMultipart() ? 'multipart/form-data' : null, - ), $attributes))); - } - - public function render($template = null) - { - if (null === $template) { - $template = sprintf('FrameworkBundle:Form:group/%s/field_group.php', $this->theme); - } - - return $this->engine->render($template, array('group' => $this)); - } - - public function hidden($template = null) - { - if (null === $template) { - $template = 'FrameworkBundle:Form:hidden.php'; - } - - return $this->engine->render($template, array( - 'group' => $this, - 'hidden' => $this->wrapFields($this->field->getHiddenFields(true)) - )); - } - - public function errors($template = null) - { - if (null === $template) { - $template = 'FrameworkBundle:Form:errors.php'; - } - - return $this->engine->render($template, array( - 'group' => $this, - 'errors' => $this->field->getErrors() - )); - } -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/FieldInterface.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Form/FieldInterface.php deleted file mode 100644 index bafcd4d444..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/FieldInterface.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -/** - * - * - * @author Fabien Potencier - */ -interface FieldInterface extends \IteratorAggregate, \ArrayAccess -{ - function render($template = null); -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/Form.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Form/Form.php deleted file mode 100644 index 89d3a64db3..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Form/Form.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -/** - * Form is a factory that wraps Form instances. - * - * @author Fabien Potencier - */ -class Form -{ - public $generator; - - protected $engine; - protected $theme; - protected $doctype; - - public function __construct(Engine $engine, HtmlGeneratorInterface $generator, $theme = 'table', $doctype = 'xhtml') - { - $this->engine = $engine; - $this->generator = $generator; - $this->theme = $theme; - $this->doctype = $doctype; - } - - public function get(FieldGroupInterface $group, $theme = null, $doctype = null) - { - return new FieldGroup($group, $this->engine, $this->generator, null === $theme ? $this->theme : $theme, null === $doctype ? $this->doctype : $doctype); - } -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php new file mode 100644 index 0000000000..c002fe49de --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php @@ -0,0 +1,183 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Form is a factory that wraps Form instances. + * + * @author Fabien Potencier + * @author Bernhard Schussek + */ +class FormHelper extends Helper +{ + static protected $cache = array(); + + protected $engine; + + public function __construct(Engine $engine) + { + $this->engine = $engine; + } + + public function getName() + { + return 'form'; + } + + public function attributes($attributes) + { + if ($attributes instanceof \Traversable) { + $attributes = iterator_to_array($attributes); + } + + return implode('', array_map(array($this, 'attributesCallback'), array_keys($attributes), array_values($attributes))); + } + + private function attribute($name, $value) + { + return sprintf('%s="%s"', $name, true === $value ? $name : $value); + } + + /** + * Prepares an attribute key and value for HTML representation. + * + * It removes empty attributes, except for the value one. + * + * @param string $name The attribute name + * @param string $value The attribute value + * + * @return string The HTML representation of the HTML key attribute pair. + */ + private function attributesCallback($name, $value) + { + if (false === $value || null === $value || ('' === $value && 'value' != $name)) { + return ''; + } else { + return ' '.$this->attribute($name, $value); + } + } + + /** + * Renders the form tag. + * + * This method only renders the opening form tag. + * You need to close it after the form rendering. + * + * This method takes into account the multipart widgets. + * + * @param string $url The URL for the action + * @param array $attributes An array of HTML attributes + * + * @return string An HTML representation of the opening form tag + */ + public function enctype(/*Form */$form) + { + return $form->isMultipart() ? ' enctype="multipart/form-data"' : ''; + } + + public function render(/*FieldInterface */$field, array $attributes = array(), array $parameters = array(), $template = null) + { + if (null === $template) { + $template = $this->lookupTemplate($field); + + if (null === $template) { + throw new \RuntimeException(sprintf('Unable to find a template to render the "%s" widget.', $field->getKey())); + } + } + + return trim($this->engine->render($template, array( + 'field' => $field, + 'attr' => $attributes, + 'params' => $parameters, + ))); + } + + public function label(/*FieldInterface */$field, $label = false, array $parameters = array(), $template = null) + { + if (null === $template) { + $template = 'FrameworkBundle:Form:label.php'; + } + + return $this->engine->render($template, array( + 'field' => $field, + 'params' => $parameters, + 'label' => $label ? $label : ucfirst(strtolower(str_replace('_', ' ', $field->getKey()))) + )); + } + + public function errors(/*FieldInterface */$field, array $parameters = array(), $template = null) + { + if (null === $template) { + $template = 'FrameworkBundle:Form:errors.php'; + } + + return $this->engine->render($template, array( + 'field' => $field, + 'params' => $parameters, + )); + } + + public function hidden(/*FieldGroupInterface */$group, array $parameters = array(), $template = null) + { + if (null === $template) { + $template = 'FrameworkBundle:Form:hidden.php'; + } + + return $this->engine->render($template, array( + 'field' => $group, + 'params' => $parameters, + )); + } + + protected function lookupTemplate(/*FieldInterface */$field) + { + if ($field instanceof \Symfony\Component\OutputEscaper\ObjectDecorator) { + $field = $field->getRawValue(); + } + + $fqClassName = get_class($field); + $template = null; + + if (isset(self::$cache[$fqClassName])) { + return self::$cache[$fqClassName]; + } + + // find a template for the given class or one of its parents + $currentFqClassName = $fqClassName; + + do { + $parts = explode('\\', $currentFqClassName); + $className = array_pop($parts); + + $underscoredName = strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($className, '_', '.'))); + + if ($this->engine->exists($guess = 'FrameworkBundle:Form:'.$underscoredName.'.php')) { + $template = $guess; + } + + $currentFqClassName = get_parent_class($currentFqClassName); + } while (null === $template && false !== $currentFqClassName); + + if (null === $template && $field instanceof FieldGroupInterface) { + $template = 'FrameworkBundle:Form:field_group.php'; + } + + self::$cache[$fqClassName] = $template; + + return $template; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/HtmlGenerator.php b/src/Symfony/Bundle/FrameworkBundle/Templating/HtmlGenerator.php deleted file mode 100644 index f9483e42ba..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/HtmlGenerator.php +++ /dev/null @@ -1,171 +0,0 @@ - - * @author Fabien Potencier - */ -class HtmlGenerator implements HtmlGeneratorInterface -{ - /** - * Whether to produce XHTML compliant code - * @var boolean - */ - protected static $xhtml = true; - - /** - * The charset used during generating - * @var string - */ - protected $charset; - - /** - * Sets the charset used for rendering - * - * @param string $charset - */ - public function __construct($charset = 'UTF-8') - { - $this->charset = $charset; - } - - /** - * Sets the XHTML generation flag. - * - * @param bool $boolean true if renderers must be generated as XHTML, false otherwise - */ - static public function setXhtml($boolean) - { - self::$xhtml = (boolean) $boolean; - } - - /** - * Returns whether to generate XHTML tags or not. - * - * @return bool true if renderers must be generated as XHTML, false otherwise - */ - static public function isXhtml() - { - return self::$xhtml; - } - - /** - * {@inheritDoc} - */ - public function tag($tag, $attributes = array()) - { - if (empty($tag)) { - return ''; - } - - return sprintf('<%s%s%s', $tag, $this->attributes($attributes), self::$xhtml ? ' />' : (strtolower($tag) == 'input' ? '>' : sprintf('>', $tag))); - } - - /** - * {@inheritDoc} - */ - public function contentTag($tag, $content = null, $attributes = array()) - { - if (empty($tag)) { - return ''; - } - - return sprintf('<%s%s>%s', $tag, $this->attributes($attributes), $content, $tag); - } - - /** - * {@inheritDoc} - */ - public function attribute($name, $value) - { - if (true === $value) { - return self::$xhtml ? sprintf('%s="%s"', $name, $this->escape($name)) : $this->escape($name); - } else { - return sprintf('%s="%s"', $name, $this->escape($value)); - } - } - - /** - * {@inheritDoc} - */ - public function attributes(array $attributes) - { - return implode('', array_map(array($this, 'attributesCallback'), array_keys($attributes), array_values($attributes))); - } - - public function choices(array $preferredChoices, array $choices, $empty, array $selected) - { - $html = ''; - - if (false !== $empty) { - $html .= $this->doChoices(array('' => $empty), $selected)."\n"; - } - - if (count($preferredChoices) > 0) { - $html .= $this->doChoices($preferredChoices, $selected)."\n"; - $html .= $this->contentTag('option', $origin->getOption('separator'), array('disabled' => true))."\n"; - } - - $html .= $this->doChoices($choices, $selected)."\n"; - - return $html; - } - - protected function doChoices(array $choices, array $selected) - { - $options = array(); - foreach ($choices as $key => $option) { - if (is_array($option)) { - $options[] = $this->contentTag( - 'optgroup', - "\n".$this->doChoices($option, $selected)."\n", - array('label' => $this->escape($key)) - ); - } else { - $attributes = array('value' => $this->escape($key)); - - if (isset($selected[strval($key)])) { - $attributes['selected'] = true; - } - - $options[] = $this->contentTag( - 'option', - $this->escape($option), - $attributes - ); - } - } - - return implode("\n", $options); - } - - /** - * Prepares an attribute key and value for HTML representation. - * - * It removes empty attributes, except for the value one. - * - * @param string $name The attribute name - * @param string $value The attribute value - * - * @return string The HTML representation of the HTML key attribute pair. - */ - private function attributesCallback($name, $value) - { - if (false === $value || null === $value || ('' === $value && 'value' != $name)) { - return ''; - } else { - return ' '.$this->attribute($name, $value); - } - } - - /** - * {@inheritDoc} - */ - public function escape($value) - { - return htmlspecialchars((string) $value, ENT_QUOTES, $this->charset, false); - } -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/HtmlGeneratorInterface.php b/src/Symfony/Bundle/FrameworkBundle/Templating/HtmlGeneratorInterface.php deleted file mode 100644 index 201b77feca..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/HtmlGeneratorInterface.php +++ /dev/null @@ -1,63 +0,0 @@ - - */ -interface HtmlGeneratorInterface -{ - /** - * Escapes a value for safe output in HTML - * - * Double escaping of already-escaped sequences is avoided by this method. - * - * @param string $value The unescaped or partially escaped value - * - * @return string The fully escaped value - */ - function escape($value); - - /** - * Generates the HTML code for a tag attribute - * - * @param string $name The attribute name - * @param string $value The attribute value - * - * @return string The HTML code of the attribute - */ - function attribute($name, $value); - - /** - * Generates the HTML code for multiple tag attributes - * - * @param array $attributes An array with attribute names as keys and - * attribute values as elements - * - * @return string The HTML code of the attribute list - */ - function attributes(array $attributes); - - /** - * Generates the HTML code for a tag without content - * - * @param string $tag The name of the tag - * @param array $attributes The attributes for the tag - * - * @return string The HTML code for the tag - */ - function tag($tag, $attributes = array()); - - /** - * Generates the HTML code for a tag with content - * - * @param string $tag The name of the tag - * @param string $content The content of the tag - * @param array $attributes The attributes for the tag - * - * @return string The HTML code for the tag - */ - function contentTag($tag, $content, $attributes = array()); -} diff --git a/src/Symfony/Bundle/TwigBundle/Extension/FormExtension.php b/src/Symfony/Bundle/TwigBundle/Extension/FormExtension.php index a426d8a3cc..07cb86b8c3 100644 --- a/src/Symfony/Bundle/TwigBundle/Extension/FormExtension.php +++ b/src/Symfony/Bundle/TwigBundle/Extension/FormExtension.php @@ -22,6 +22,7 @@ use Symfony\Bundle\FrameworkBundle\Templating\HtmlGeneratorInterface; /** * * @author Fabien Potencier + * @author Bernhard Schussek */ class FormExtension extends \Twig_Extension { @@ -31,15 +32,12 @@ class FormExtension extends \Twig_Extension protected $templates; protected $environment; protected $themes; - protected $generator; - public function __construct(HtmlGeneratorInterface $generator, array $resources = array()) + public function __construct(array $resources = array()) { - $this->generator = $generator; $this->themes = new \SplObjectStorage(); $this->resources = array_merge(array( 'TwigBundle::form.twig', - 'TwigBundle::widgets.twig', ), $resources); } @@ -79,89 +77,51 @@ class FormExtension extends \Twig_Extension 'render' => new \Twig_Filter_Method($this, 'render', array('is_safe' => array('html'))), 'render_hidden' => new \Twig_Filter_Method($this, 'renderHidden', array('is_safe' => array('html'))), 'render_errors' => new \Twig_Filter_Method($this, 'renderErrors', array('is_safe' => array('html'))), - 'render_widget' => new \Twig_Filter_Method($this, 'renderWidget', array('is_safe' => array('html'))), 'render_label' => new \Twig_Filter_Method($this, 'renderLabel', array('is_safe' => array('html'))), 'render_data' => new \Twig_Filter_Method($this, 'renderData', array('is_safe' => array('html'))), - 'render_choices' => new \Twig_Filter_Method($this, 'renderChoices', array('is_safe' => array('html'))), ); } + /** + * 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 renderEnctype(Form $form) { return $form->isMultipart() ? 'enctype="multipart/form-data"' : ''; } - public function render(FieldInterface $field, array $attributes = array()) + /** + * Renders the HTML for an individual form field + * + * Example usage in Twig: + * + * {{ field|render }} + * + * You can pass additional variables during the call: + * + * {{ field|render(['param': 'value']) }} + * + * @param FieldInterface $field The field to render + * @param array $params Additional variables passed to the template + * @param string $resources + */ + public function render(FieldInterface $field, array $attributes = array(), array $parameters = array(), $resources = null) { if (null === $this->templates) { $this->templates = $this->resolveResources($this->resources); } - if ($field instanceof CollectionField) { - return $this->templates['group']->getBlock('collection', array( - 'collection' => $field, - 'attributes' => $attributes, - )); - } - - // FieldGroupInterface instances that need to be rendered as - // a field instead of group should return false in isGroup() - if ($field instanceof FieldGroupInterface && true === $field->isGroup()) { - return $this->templates['group']->getBlock('group', array( - 'group' => $field, - 'attributes' => $attributes, - )); - } - - return $this->templates['field']->getBlock('field', array( - 'field' => $field, - 'attributes' => $attributes, - )); - } - - public function renderHidden(FieldGroupInterface $form) - { - if (null === $this->templates) { - $this->templates = $this->resolveResources($this->resources); - } - - return $this->templates['hidden']->getBlock('hidden', array( - 'fields' => $form->getHiddenFields() - )); - } - - public function renderErrors($formOrField) - { - if (null === $this->templates) { - $this->templates = $this->resolveResources($this->resources); - } - - return $this->templates['errors']->getBlock('errors', array( - 'errors' => $formOrField->getErrors() - )); - } - - public function renderLabel(FieldInterface $field, $label = null, array $attributes = array()) - { - if (null === $this->templates) { - $this->templates = $this->resolveResources($this->resources); - } - - return $this->templates['label']->getBlock('label', array( - 'id' => $field->getId(), - 'key' => $field->getKey(), - 'label' => null !== $label ? $label : ucfirst(strtolower(str_replace('_', ' ', $field->getKey()))), - 'attributes' => $attributes, - )); - } - - public function renderWidget(FieldInterface $field, array $attributes = array(), $resources = null) - { - if (null === $this->templates) { - $this->templates = $this->resolveResources($this->resources); - } - - if (null === $resources) { + if (null !== $resources) { + // The developer provided a custom theme in the filter call + $resources = array($resources); + } else { + // The default theme is used $parent = $field; $resources = array(); while ($parent = $parent->getParent()) { @@ -169,31 +129,71 @@ class FormExtension extends \Twig_Extension $resources = $this->themes[$parent]; } } - } else { - $resources = array($resources); } list($widget, $template) = $this->getWidget($field, $resources); return $template->getBlock($widget, array( - 'field' => $field, - 'attributes' => array_merge($field->getAttributes(), $attributes), + 'field' => $field, + 'attr' => $attributes, + 'params' => $parameters, )); } - public function renderData(FieldInterface $field) + /** + * Renders all hidden fields of the given field group + * + * @param FieldGroupInterface $group The field group + * @param array $params Additional variables passed to the + * template + */ + public function renderHidden(FieldGroupInterface $group, array $parameters = array()) { - return $field->getData(); + if (null === $this->templates) { + $this->templates = $this->resolveResources($this->resources); + } + + return $this->templates['hidden']->getBlock('hidden', array( + 'field' => $group, + 'params' => $parameters, + )); } - public function renderChoices(FieldInterface $field) + /** + * 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 renderErrors(FieldInterface $field, array $parameters = array()) { - return $this->generator->choices( - $field->getPreferredChoices(), - $field->getOtherChoices(), - $field->getEmptyValue(), - $field->getSelected() - ); + if (null === $this->templates) { + $this->templates = $this->resolveResources($this->resources); + } + + return $this->templates['errors']->getBlock('errors', array( + 'field' => $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 renderLabel(FieldInterface $field, $label = null, array $parameters = array()) + { + if (null === $this->templates) { + $this->templates = $this->resolveResources($this->resources); + } + + return $this->templates['label']->getBlock('label', array( + 'field' => $field, + 'params' => $parameters, + 'label' => null !== $label ? $label : ucfirst(strtolower(str_replace('_', ' ', $field->getKey()))), + )); } protected function getWidget(FieldInterface $field, array $resources = array()) diff --git a/src/Symfony/Bundle/TwigBundle/Extension/HtmlExtension.php b/src/Symfony/Bundle/TwigBundle/Extension/HtmlExtension.php deleted file mode 100644 index 32633aa7c5..0000000000 --- a/src/Symfony/Bundle/TwigBundle/Extension/HtmlExtension.php +++ /dev/null @@ -1,62 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -/** - * - * @author Fabien Potencier - */ -class HtmlExtension extends \Twig_Extension -{ - protected $generator; - - public function __construct(HtmlGeneratorInterface $generator) - { - $this->generator = $generator; - } - - public function getGenerator() - { - return $this->generator; - } - - /** - * Returns the token parser instance to add to the existing list. - * - * @return array An array of Twig_TokenParser instances - */ - public function getTokenParsers() - { - return array( - // {% tag "input" with attributes %} - new TagTokenParser(), - - // {% contenttag "textarea" with attributes %}content{% endcontenttag %} - new ContentTagTokenParser(), - ); - } - - /** - * Returns the name of the extension. - * - * @return string The extension name - */ - public function getName() - { - return 'html'; - } -} diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 94053b1a14..c1d4af9d9b 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -43,11 +43,6 @@ - - - - - @@ -55,7 +50,6 @@ - %twig.form.resources% diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/form.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/form.twig index 93f7c1b053..ecee601dcf 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/form.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/form.twig @@ -1,28 +1,16 @@ -{% block group %} - {{ group|render_errors }} - {% for field in group %} - {% if not field.ishidden %} - {{ field|render }} +{% block field_group %} + {{ field|render_errors }} + {% for child in field %} + {% if not child.ishidden %} +
+ {{ child|render_label }} + {{ child|render_errors }} + {{ child|render }} +
{% endif %} {% endfor %} - {{ group|render_hidden }} -{% endblock group %} - -{% block field %} -
- {{ field|render_label }} - {{ field|render_errors }} - {{ field|render_widget }} -
-{% endblock field %} - -{% block collection %} -
- {% for field in collection %} - {{ field|render }} - {% endfor %} -
-{% endblock collection %} + {{ field|render_hidden }} +{% endblock field_group %} {% block errors %} {% if errors %} @@ -35,11 +23,117 @@ {% endblock errors %} {% block hidden %} - {% for field in fields %} - {{ field|render_widget }} + {% for child in field.allHiddenFields %} + {{ child|render }} {% endfor %} {% endblock hidden %} {% block label %} - + {% endblock label %} + +{% block attributes %} + {% for key, value in attr %} + {{ key }}="{{ value}}" + {% endfor %} +{% endblock attributes %} + +{% block field_attributes %} + id="{{ field.id }}" name="{{ field.name }}"{% if field.disabled %} disabled="disabled"{% endif %} + {% display attributes %} +{% endblock field_attributes %} + +{% block text_field %} + {#{% set attr.maxlength = attr.maxlength|default(field.maxlength) %}#} + +{% endblock text_field %} + +{% block password_field %} + {#{% set attr.maxlength = attr.maxlength|default(field.maxlength) %}#} + +{% endblock password_field %} + +{% block hidden_field %} + +{% endblock hidden_field %} + +{% block textarea_field %} + +{% endblock textarea_field %} + +{% block options %} + {% for choice, label in options %} + {% if field.isChoiceGroup(label) %} + + {% for nestedChoice, nestedLabel in label %} + + {% endfor %} + + {% else %} + + {% endif %} + {% endfor %} +{% endblock options %} + +{% block choice_field %} + {% if field.isExpanded %} + {% for choice, child in field %} + {{ child|render }} + + {% endfor %} + {% else %} + + {% endif %} +{% endblock choice_field %} + +{% block checkbox_field %} + +{% endblock checkbox_field %} + +{% block radio_field %} + +{% endblock radio_field %} + +{% block date_time_field %} + {{ field.date|render }} + {{ field.time|render }} +{% endblock date_time_field %} + +{% block date_field %} + {% if field.isfield %} + {% display text_field %} + {% else %} + {{ field.pattern|replace(['{{ year }}': field.year|render, '{{ month }}': field.month|render, '{{ day }}': field.day|render]) }} + {% endif %} +{% endblock date_field %} + +{% block time_field %} + {# TODO the next line should be set attr.size = 1, but that's not supported yet by Twig #} + {% if field.isfield %}{% set attr = ['size': 1] %}{% endif %} + {{ field.hour|render(attr) }}:{{ field.minute|render(attr) }}{% if field.isWithSeconds %}:{{ field.second|render(attr) }}{% endif %} +{% endblock time_field %} + +{% block number_field %} + +{% endblock number_field %} + +{% block money_field %} + {% set widget %}{% display number_field %}{% endset %} + {{ field.pattern|replace(['{{ widget }}': widget])|raw }} +{% endblock money_field %} + +{% block percent_field %} + {% display text_field %} % +{% endblock percent_field %} + +{% block file_field %} + +{% endblock file_field %} \ No newline at end of file diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/widgets.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/widgets.twig deleted file mode 100644 index f7d104f2bc..0000000000 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/widgets.twig +++ /dev/null @@ -1,57 +0,0 @@ -{% block input_field %} - {% tag "input" with attributes %} -{% endblock input_field %} - -{% block textarea_field %} - {% contenttag "textarea" with attributes %}{{ field.displayedData }}{% endcontenttag %} -{% endblock textarea_field %} - -{% block choice_field %} - {% if field.options.expanded %} - {% for child in field %} - {{ child|render_widget }} - {% endfor %} - {% else %} - {% contenttag "select" with attributes %} - {{ field|render_choices }} - {% endcontenttag %} - {% endif %} -{% endblock choice_field %} - -{% block toggle_field %} - {% display input_field %} - {% if field.options.label %} - {% contenttag "label" with ['for': field.id] %}{% trans field.options.label %}{% endcontenttag %} - {% endif %} -{% endblock toggle_field %} - -{% block date_time_field %} - {{ field.date|render_widget }} - {{ field.time|render_widget }} -{% endblock date_time_field %} - -{% block date_field %} - {% if field.field %} - {% display input_field %} - {% else %} - {{ field.pattern|replace(['{{ year }}': field.year|render_widget, '{{ month }}': field.month|render_widget, '{{ day }}': field.day|render_widget,]) }} - {% endif %} -{% endblock date_field %} - -{% block time_field %} - {% if field.isfield %} - {% display input_field %} - {% else %} - {{ field.hour|render_widget }}:{{ field.minute|render_widget }} - {% if field.options.with_seconds %}:{{ field.second|render_widget }}{% endif %} - {% endif %} -{% endblock time_field %} - -{% block money_field %} - {% set widget %}{% display input_field %}{% endset %} - {{ field.pattern|replace(['{{ widget }}': widget]) }} -{% endblock money_field %} - -{% block percent_field %} - {% display input_field %} % -{% endblock percent_field %} diff --git a/src/Symfony/Component/Form/CheckboxField.php b/src/Symfony/Component/Form/CheckboxField.php index 0e71d3f36a..f8193a8159 100644 --- a/src/Symfony/Component/Form/CheckboxField.php +++ b/src/Symfony/Component/Form/CheckboxField.php @@ -18,13 +18,4 @@ namespace Symfony\Component\Form; */ class CheckboxField extends ToggleField { - /** - * {@inheritDoc} - */ - public function __construct($key, array $options = array()) - { - $options['type'] = 'checkbox'; - - parent::__construct($key, $options); - } } \ No newline at end of file diff --git a/src/Symfony/Component/Form/ChoiceField.php b/src/Symfony/Component/Form/ChoiceField.php index 013222e65e..b829235674 100644 --- a/src/Symfony/Component/Form/ChoiceField.php +++ b/src/Symfony/Component/Form/ChoiceField.php @@ -50,7 +50,7 @@ class ChoiceField extends HybridField $this->preferredChoices = array_flip($this->getOption('preferred_choices')); } - if ($this->getOption('expanded')) { + if ($this->isExpanded()) { $this->setFieldMode(self::GROUP); $choices = $this->getOption('choices'); @@ -71,34 +71,19 @@ class ChoiceField extends HybridField parent::configure(); } - /** - * {@inheritDoc} - */ - public function getAttributes() + public function getName() { - $attributes = array( - 'id' => $this->getId(), - 'name' => $this->getName(), - 'disabled' => $this->isDisabled(), - ); + // TESTME + $name = parent::getName(); // Add "[]" to the name in case a select tag with multiple options is // displayed. Otherwise only one of the selected options is sent in the // POST request. - if ($this->getOption('multiple') && !$this->getOption('expanded')) { - $attributes['name'] .= '[]'; + if ($this->isMultipleChoice() && !$this->isExpanded()) { + $name .= '[]'; } - if ($this->getOption('multiple')) { - $attributes['multiple'] = 'multiple'; - } - - return array_merge(parent::getAttributes(), $attributes); - } - - public function getSelected() - { - return array_flip(array_map('strval', (array) $this->getDisplayedData())); + return $name; } public function getPreferredChoices() @@ -116,6 +101,33 @@ class ChoiceField extends HybridField return $this->isRequired() ? false : $this->getOption('empty_value'); } + public function getLabel($choice) + { + $choices = $this->getOption('choices'); + + return isset($choices[$choice]) ? $choices[$choice] : null; + } + + public function isChoiceGroup($choice) + { + return is_array($choice) || $choice instanceof \Traversable; + } + + public function isChoiceSelected($choice) + { + return in_array($choice, (array) $this->getDisplayedData()); + } + + public function isMultipleChoice() + { + return $this->getOption('multiple'); + } + + public function isExpanded() + { + return $this->getOption('expanded'); + } + /** * Returns a new field of type radio button or checkbox. * @@ -124,16 +136,15 @@ class ChoiceField extends HybridField */ protected function newChoiceField($choice, $label) { - if ($this->getOption('multiple')) { + if ($this->isMultipleChoice()) { return new CheckboxField($choice, array( 'value' => $choice, - 'label' => $label, + )); + } else { + return new RadioField($choice, array( + 'value' => $choice, )); } - return new RadioField($choice, array( - 'value' => $choice, - 'label' => $label, - )); } /** @@ -144,7 +155,7 @@ class ChoiceField extends HybridField */ public function bind($value) { - if (!$this->getOption('multiple') && $this->getOption('expanded')) { + if (!$this->isMultipleChoice() && $this->isExpanded()) { $value = $value === null ? array() : array($value => true); } @@ -166,12 +177,12 @@ class ChoiceField extends HybridField */ protected function transform($value) { - if ($this->getOption('expanded')) { + if ($this->isExpanded()) { $value = parent::transform($value); $choices = $this->getOption('choices'); foreach ($choices as $choice => $_) { - $choices[$choice] = $this->getOption('multiple') + $choices[$choice] = $this->isMultipleChoice() ? in_array($choice, (array)$value, true) : ($choice === $value); } @@ -196,7 +207,7 @@ class ChoiceField extends HybridField */ protected function reverseTransform($value) { - if ($this->getOption('expanded')) { + if ($this->isExpanded()) { $choices = array(); foreach ($value as $choice => $selected) { @@ -205,7 +216,7 @@ class ChoiceField extends HybridField } } - if ($this->getOption('multiple')) { + if ($this->isMultipleChoice()) { $value = $choices; } else { $value = count($choices) > 0 ? current($choices) : null; diff --git a/src/Symfony/Component/Form/CollectionField.php b/src/Symfony/Component/Form/CollectionField.php index a70a8e681f..124fe7dbb6 100644 --- a/src/Symfony/Component/Form/CollectionField.php +++ b/src/Symfony/Component/Form/CollectionField.php @@ -54,7 +54,7 @@ class CollectionField extends FieldGroup public function setData($collection) { if (!is_array($collection) && !$collection instanceof \Traversable) { - throw new UnexpectedTypeException('The data must be an array'); + throw new UnexpectedTypeException('The data passed to the CollectionField must be an array or a Traversable'); } foreach ($this as $name => $field) { diff --git a/src/Symfony/Component/Form/DateField.php b/src/Symfony/Component/Form/DateField.php index 860db62eea..7217fad13a 100644 --- a/src/Symfony/Component/Form/DateField.php +++ b/src/Symfony/Component/Form/DateField.php @@ -145,23 +145,6 @@ class DateField extends HybridField } } - /** - * {@inheritDoc} - */ - public function getAttributes() - { - if ($this->isField()) { - return array_merge(parent::getAttributes(), array( - 'id' => $this->getId(), - 'name' => $this->getName(), - 'value' => $this->getDisplayedData(), - 'type' => 'text', - )); - } - - return parent::getAttributes(); - } - /** * Generates an array of choices for the given values * diff --git a/src/Symfony/Component/Form/Field.php b/src/Symfony/Component/Form/Field.php index 7548956b84..18e7008e3d 100644 --- a/src/Symfony/Component/Form/Field.php +++ b/src/Symfony/Component/Form/Field.php @@ -103,11 +103,6 @@ abstract class Field extends Configurable implements FieldInterface // TODO } - public function getAttributes() - { - return array(); - } - /** * Returns the data of the field as it is displayed to the user. * diff --git a/src/Symfony/Component/Form/FieldGroup.php b/src/Symfony/Component/Form/FieldGroup.php index c282d87129..be5cf8e5d6 100644 --- a/src/Symfony/Component/Form/FieldGroup.php +++ b/src/Symfony/Component/Form/FieldGroup.php @@ -216,7 +216,7 @@ class FieldGroup extends Field implements \IteratorAggregate, FieldGroupInterfac * * @return array */ - public function getVisibleFieldsRecursively() + public function getAllVisibleFields() { return $this->getFieldsByVisibility(false, true); } @@ -239,7 +239,7 @@ class FieldGroup extends Field implements \IteratorAggregate, FieldGroupInterfac * * @return array */ - public function getHiddenFieldsRecursively() + public function getAllHiddenFields() { return $this->getFieldsByVisibility(true, true); } @@ -255,13 +255,12 @@ class FieldGroup extends Field implements \IteratorAggregate, FieldGroupInterfac protected function getFieldsByVisibility($hidden, $recursive) { $fields = array(); + $hidden = (bool)$hidden; foreach ($this->fields as $field) { - if ($field instanceof FieldGroup) { - if ($recursive) { - $fields = array_merge($fields, $field->getFieldsByVisibility($hidden, $recursive)); - } - } else if ((bool)$hidden === $field->isHidden()) { + if ($field instanceof FieldGroup && $recursive) { + $fields = array_merge($fields, $field->getFieldsByVisibility($hidden, $recursive)); + } else if ($hidden === $field->isHidden()) { $fields[] = $field; } } @@ -447,11 +446,6 @@ class FieldGroup extends Field implements \IteratorAggregate, FieldGroupInterfac return false; } - public function isGroup() - { - return true; - } - /** * Returns true if the bound field exists (implements the \ArrayAccess interface). * diff --git a/src/Symfony/Component/Form/FieldGroupInterface.php b/src/Symfony/Component/Form/FieldGroupInterface.php index c800263c03..16d332905a 100644 --- a/src/Symfony/Component/Form/FieldGroupInterface.php +++ b/src/Symfony/Component/Form/FieldGroupInterface.php @@ -18,9 +18,4 @@ namespace Symfony\Component\Form; */ interface FieldGroupInterface extends FieldInterface, \ArrayAccess, \Traversable, \Countable { - /** - * Returns whether the Field instance really is a group - * @return bool - */ - public function isGroup(); } \ No newline at end of file diff --git a/src/Symfony/Component/Form/FileField.php b/src/Symfony/Component/Form/FileField.php index e905d5e4d3..d507ed379b 100644 --- a/src/Symfony/Component/Form/FileField.php +++ b/src/Symfony/Component/Form/FileField.php @@ -14,28 +14,8 @@ namespace Symfony\Component\Form; /** * A file field to upload files. */ -class FileField extends InputField +class FileField extends Field { - /** - * {@inheritDoc} - */ - public function __construct($key, array $options = array()) - { - $options['type'] = 'file'; - - parent::__construct($key, $options); - } - - /** - * {@inheritDoc} - */ - public function getAttributes() - { - return array_merge(parent::getAttributes(), array( - 'type' => 'file', - )); - } - /** * {@inheritDoc} */ diff --git a/src/Symfony/Component/Form/HiddenField.php b/src/Symfony/Component/Form/HiddenField.php index 56aa2c10db..90949a3507 100644 --- a/src/Symfony/Component/Form/HiddenField.php +++ b/src/Symfony/Component/Form/HiddenField.php @@ -16,18 +16,8 @@ namespace Symfony\Component\Form; * * @author Bernhard Schussek */ -class HiddenField extends InputField +class HiddenField extends Field { - /** - * {@inheritDoc} - */ - public function __construct($key, array $options = array()) - { - $options['type'] = 'hidden'; - - parent::__construct($key, $options); - } - /** * {@inheritDoc} */ diff --git a/src/Symfony/Component/Form/InputField.php b/src/Symfony/Component/Form/InputField.php deleted file mode 100644 index 22ff100997..0000000000 --- a/src/Symfony/Component/Form/InputField.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * This source file is subject to the MIT license that is bundled - * with this source code in the file LICENSE. - */ - -/** - * Base class for all low-level fields represented by input tags - * - * @author Bernhard Schussek - */ -class InputField extends Field -{ - /** - * {@inheritDoc} - */ - protected function configure() - { - $this->addRequiredOption('type'); - - parent::configure(); - } - - /** - * {@inheritDoc} - */ - public function getAttributes() - { - return array_merge(parent::getAttributes(), array( - 'id' => $this->getId(), - 'name' => $this->getName(), - 'value' => $this->getDisplayedData(), - 'disabled' => $this->isDisabled(), - 'type' => $this->getOption('type'), - )); - } -} diff --git a/src/Symfony/Component/Form/MoneyField.php b/src/Symfony/Component/Form/MoneyField.php index f603bf143a..4326f20256 100644 --- a/src/Symfony/Component/Form/MoneyField.php +++ b/src/Symfony/Component/Form/MoneyField.php @@ -53,7 +53,7 @@ class MoneyField extends NumberField * The pattern contains the placeholder "{{ widget }}" where the HTML tag should * be inserted */ - protected function getPattern() + public function getPattern() { if (!$this->getOption('currency')) { return '{{ widget }}'; diff --git a/src/Symfony/Component/Form/NumberField.php b/src/Symfony/Component/Form/NumberField.php index 891ebd50ae..c0b1dc1085 100644 --- a/src/Symfony/Component/Form/NumberField.php +++ b/src/Symfony/Component/Form/NumberField.php @@ -18,18 +18,8 @@ use Symfony\Component\Form\ValueTransformer\NumberToLocalizedStringTransformer; * * @author Bernhard Schussek */ -class NumberField extends InputField +class NumberField extends Field { - /** - * {@inheritDoc} - */ - public function __construct($key, array $options = array()) - { - $options['type'] = 'text'; - - parent::__construct($key, $options); - } - /** * {@inheritDoc} */ diff --git a/src/Symfony/Component/Form/PasswordField.php b/src/Symfony/Component/Form/PasswordField.php index 9db9e14ad6..8fbbd5e46e 100644 --- a/src/Symfony/Component/Form/PasswordField.php +++ b/src/Symfony/Component/Form/PasswordField.php @@ -28,15 +28,11 @@ class PasswordField extends TextField parent::configure(); } - /** - * {@inheritDoc} - */ - public function getAttributes() + public function getDisplayedData() { - return array_merge(parent::getAttributes(), array( - // override getDisplayedData() instead? - 'value' => $this->getOption('always_empty') && !$this->isBound() ? '' : $this->getDisplayedData(), - 'type' => 'password', - )); + // TESTME + return $this->getOption('always_empty') && !$this->isBound() + ? '' + : parent::getDisplayedData(); } } \ No newline at end of file diff --git a/src/Symfony/Component/Form/RadioField.php b/src/Symfony/Component/Form/RadioField.php index adb5ed3d01..77c552b97c 100644 --- a/src/Symfony/Component/Form/RadioField.php +++ b/src/Symfony/Component/Form/RadioField.php @@ -21,21 +21,9 @@ class RadioField extends ToggleField /** * {@inheritDoc} */ - public function __construct($key, array $options = array()) + public function getName() { - $options['type'] = 'radio'; - - parent::__construct($key, $options); - } - - /** - * {@inheritDoc} - */ - public function getAttributes() - { - return array_merge(parent::getAttributes(), array( - // TODO: should getName() be overridden instead? - 'name' => $this->getParent() ? $this->getParent()->getName() : $this->getName(), - )); + // TESTME + return $this->getParent() ? $this->getParent()->getName() : $this->getName(); } } diff --git a/src/Symfony/Component/Form/TextField.php b/src/Symfony/Component/Form/TextField.php index 08b1762bdf..d8273f8104 100644 --- a/src/Symfony/Component/Form/TextField.php +++ b/src/Symfony/Component/Form/TextField.php @@ -16,18 +16,8 @@ namespace Symfony\Component\Form; * * @author Bernhard Schussek */ -class TextField extends InputField +class TextField extends Field { - /** - * {@inheritDoc} - */ - public function __construct($key, array $options = array()) - { - $options['type'] = 'text'; - - parent::__construct($key, $options); - } - /** * {@inheritDoc} */ @@ -38,13 +28,8 @@ class TextField extends InputField parent::configure(); } - /** - * {@inheritDoc} - */ - public function getAttributes() + public function getMaxLength() { - return array_merge(parent::getAttributes(), array( - 'maxlength' => $this->getOption('max_length'), - )); + return $this->getOption('max_length'); } } diff --git a/src/Symfony/Component/Form/TextareaField.php b/src/Symfony/Component/Form/TextareaField.php index 369b7cfc7d..62e0cafccf 100644 --- a/src/Symfony/Component/Form/TextareaField.php +++ b/src/Symfony/Component/Form/TextareaField.php @@ -18,16 +18,4 @@ namespace Symfony\Component\Form; */ class TextareaField extends Field { - /** - * {@inheritDoc} - */ - public function getAttributes() - { - return array_merge(parent::getAttributes(), array( - 'id' => $this->getId(), - 'name' => $this->getName(), - 'rows' => 4, - 'cols' => 30, - )); - } } diff --git a/src/Symfony/Component/Form/TimeField.php b/src/Symfony/Component/Form/TimeField.php index b0f131448c..52b484d558 100644 --- a/src/Symfony/Component/Form/TimeField.php +++ b/src/Symfony/Component/Form/TimeField.php @@ -121,18 +121,9 @@ class TimeField extends FieldGroup return self::INPUT === $this->getOption('widget'); } - /** - * {@inheritDoc} - */ - public function getAttributes() + public function isWithSeconds() { - if ($this->isField()) { - return array_merge(parent::getAttributes(), array( - 'size' => '1', - )); - } - - return parent::getAttributes(); + return $this->getOption('with_seconds'); } /** diff --git a/src/Symfony/Component/Form/ToggleField.php b/src/Symfony/Component/Form/ToggleField.php index feca74b3e2..df00130743 100644 --- a/src/Symfony/Component/Form/ToggleField.php +++ b/src/Symfony/Component/Form/ToggleField.php @@ -18,7 +18,7 @@ use Symfony\Component\Form\ValueTransformer\BooleanToStringTransformer; * * @author Bernhard Schussek */ -abstract class ToggleField extends InputField +abstract class ToggleField extends Field { /** * {@inheritDoc} @@ -26,21 +26,24 @@ abstract class ToggleField extends InputField protected function configure() { $this->addOption('value'); - $this->addOption('label'); parent::configure(); $this->setValueTransformer(new BooleanToStringTransformer()); } - /** - * {@inheritDoc} - */ - public function getAttributes() + public function isChecked() { - return array_merge(parent::getAttributes(), array( - 'value' => $this->getOption('value'), - 'checked' => (string) $this->getDisplayedData() !== '' && $this->getDisplayedData() !== 0, - )); + return $this->getData(); + } + + public function getValue() + { + return $this->getOption('value'); + } + + public function hasValue() + { + return $this->getValue() !== null; } }