[Form] Implemented form processors
This commit is contained in:
parent
0ea75dbf48
commit
81f8c67566
@ -1,6 +1,15 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
2.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* [BC BREAK] restricted the `render` tag to only accept URIs as reference (the signature changed)
|
||||||
|
* added a render function to render a request
|
||||||
|
* the `app` global variable is now injected even when using the twig service directly.
|
||||||
|
* added helpers form(), form_start() and form_end()
|
||||||
|
* deprecated form_enctype() in favor of form_start()
|
||||||
|
|
||||||
2.2.0
|
2.2.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -61,12 +61,14 @@ class FormExtension extends \Twig_Extension
|
|||||||
public function getFunctions()
|
public function getFunctions()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
'form_enctype' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
'form_enctype' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\FormEnctypeNode', array('is_safe' => array('html'))),
|
||||||
'form_widget' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
'form_widget' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
||||||
'form_errors' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
'form_errors' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
||||||
'form_label' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
'form_label' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
||||||
'form_row' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
'form_row' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
||||||
'form_rest' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
'form_rest' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode', array('is_safe' => array('html'))),
|
||||||
|
'form_start' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
|
||||||
|
'form_end' => new \Twig_Function_Node('Symfony\Bridge\Twig\Node\RenderBlockNode', array('is_safe' => array('html'))),
|
||||||
'csrf_token' => new \Twig_Function_Method($this, 'renderer->renderCsrfToken'),
|
'csrf_token' => new \Twig_Function_Method($this, 'renderer->renderCsrfToken'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
29
src/Symfony/Bridge/Twig/Node/FormEnctypeNode.php
Normal file
29
src/Symfony/Bridge/Twig/Node/FormEnctypeNode.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Twig\Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
|
||||||
|
* the helper "form_start()" instead.
|
||||||
|
*/
|
||||||
|
class FormEnctypeNode extends SearchAndRenderBlockNode
|
||||||
|
{
|
||||||
|
public function compile(\Twig_Compiler $compiler)
|
||||||
|
{
|
||||||
|
parent::compile($compiler);
|
||||||
|
|
||||||
|
$compiler->raw(";\n");
|
||||||
|
$compiler->write('trigger_error(\'The helper form_enctype(form) is deprecated since version 2.3 and will be removed in 3.0. Use form_start(form) instead.\', E_USER_DEPRECATED)');
|
||||||
|
}
|
||||||
|
}
|
42
src/Symfony/Bridge/Twig/Node/RenderBlockNode.php
Normal file
42
src/Symfony/Bridge/Twig/Node/RenderBlockNode.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\Twig\Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles a call to {@link FormRendererInterface::renderBlock()}.
|
||||||
|
*
|
||||||
|
* The function name is used as block name. For example, if the function name
|
||||||
|
* is "foo", the block "foo" will be rendered.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class RenderBlockNode extends \Twig_Node_Expression_Function
|
||||||
|
{
|
||||||
|
public function compile(\Twig_Compiler $compiler)
|
||||||
|
{
|
||||||
|
$compiler->addDebugInfo($this);
|
||||||
|
$arguments = iterator_to_array($this->getNode('arguments'));
|
||||||
|
$compiler->write('$this->env->getExtension(\'form\')->renderer->renderBlock(');
|
||||||
|
|
||||||
|
if (isset($arguments[0])) {
|
||||||
|
$compiler->subcompile($arguments[0]);
|
||||||
|
$compiler->raw(', \'' . $this->getAttribute('name') . '\'');
|
||||||
|
|
||||||
|
if (isset($arguments[1])) {
|
||||||
|
$compiler->raw(', ');
|
||||||
|
$compiler->subcompile($arguments[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$compiler->raw(')');
|
||||||
|
}
|
||||||
|
}
|
@ -298,6 +298,38 @@
|
|||||||
|
|
||||||
{# Misc #}
|
{# Misc #}
|
||||||
|
|
||||||
|
{% block form %}
|
||||||
|
{% spaceless %}
|
||||||
|
{{ form_start(form) }}
|
||||||
|
{{ form_widget(form) }}
|
||||||
|
{{ form_end(form) }}
|
||||||
|
{% endspaceless %}
|
||||||
|
{% endblock form %}
|
||||||
|
|
||||||
|
{% block form_start %}
|
||||||
|
{% spaceless %}
|
||||||
|
{% set method = method|upper %}
|
||||||
|
{% if method in ["GET", "POST"] %}
|
||||||
|
{% set form_method = method %}
|
||||||
|
{% else %}
|
||||||
|
{% set form_method = "POST" %}
|
||||||
|
{% endif %}
|
||||||
|
<form method="{{ form_method|lower }}" action="{{ action }}"{% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}{% if multipart %} enctype="multipart/form-data"{% endif %}>
|
||||||
|
{% if form_method != method %}
|
||||||
|
<input type="hidden" name="_method" value="{{ method }}" />
|
||||||
|
{% endif %}
|
||||||
|
{% endspaceless %}
|
||||||
|
{% endblock form_start %}
|
||||||
|
|
||||||
|
{% block form_end %}
|
||||||
|
{% spaceless %}
|
||||||
|
{% if not render_rest is defined or render_rest %}
|
||||||
|
{{ form_rest(form) }}
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
{% endspaceless %}
|
||||||
|
{% endblock form_end %}
|
||||||
|
|
||||||
{% block form_enctype %}
|
{% block form_enctype %}
|
||||||
{% spaceless %}
|
{% spaceless %}
|
||||||
{% if multipart %}enctype="multipart/form-data"{% endif %}
|
{% if multipart %}enctype="multipart/form-data"{% endif %}
|
||||||
|
@ -139,6 +139,11 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest
|
|||||||
$this->assertSame($expected, $this->extension->isSelectedChoice($choice, $value));
|
$this->assertSame($expected, $this->extension->isSelectedChoice($choice, $value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function renderForm(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->renderBlock($view, 'form', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
protected function renderEnctype(FormView $view)
|
protected function renderEnctype(FormView $view)
|
||||||
{
|
{
|
||||||
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
|
||||||
@ -173,6 +178,16 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest
|
|||||||
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function renderStart(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderEnd(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
protected function setTheme(FormView $view, array $themes)
|
protected function setTheme(FormView $view, array $themes)
|
||||||
{
|
{
|
||||||
$this->extension->renderer->setTheme($view, $themes);
|
$this->extension->renderer->setTheme($view, $themes);
|
||||||
|
@ -75,6 +75,11 @@ class FormExtensionTableLayoutTest extends AbstractTableLayoutTest
|
|||||||
$this->extension = null;
|
$this->extension = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function renderForm(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->renderBlock($view, 'form', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
protected function renderEnctype(FormView $view)
|
protected function renderEnctype(FormView $view)
|
||||||
{
|
{
|
||||||
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
|
||||||
@ -109,6 +114,16 @@ class FormExtensionTableLayoutTest extends AbstractTableLayoutTest
|
|||||||
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function renderStart(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderEnd(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
protected function setTheme(FormView $view, array $themes)
|
protected function setTheme(FormView $view, array $themes)
|
||||||
{
|
{
|
||||||
$this->extension->renderer->setTheme($view, $themes);
|
$this->extension->renderer->setTheme($view, $themes);
|
||||||
|
@ -10,6 +10,9 @@ CHANGELOG
|
|||||||
* added `TimedPhpEngine`
|
* added `TimedPhpEngine`
|
||||||
* added `--clean` option the the `translation:update` command
|
* added `--clean` option the the `translation:update` command
|
||||||
* added `http_method_override` option
|
* added `http_method_override` option
|
||||||
|
* added support for default templates per render tag
|
||||||
|
* added FormHelper::form(), FormHelper::start() and FormHelper::end()
|
||||||
|
* deprecated FormHelper::enctype() in favor of FormHelper::start()
|
||||||
|
|
||||||
2.2.0
|
2.2.0
|
||||||
-----
|
-----
|
||||||
@ -27,10 +30,10 @@ CHANGELOG
|
|||||||
* replaced Symfony\Bundle\FrameworkBundle\Controller\TraceableControllerResolver by Symfony\Component\HttpKernel\Controller\TraceableControllerResolver
|
* replaced Symfony\Bundle\FrameworkBundle\Controller\TraceableControllerResolver by Symfony\Component\HttpKernel\Controller\TraceableControllerResolver
|
||||||
* replaced Symfony\Component\HttpKernel\Debug\ContainerAwareTraceableEventDispatcher by Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher
|
* replaced Symfony\Component\HttpKernel\Debug\ContainerAwareTraceableEventDispatcher by Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher
|
||||||
* added Client::enableProfiler()
|
* added Client::enableProfiler()
|
||||||
* A new parameter has been added to the DIC: `router.request_context.base_url`
|
* a new parameter has been added to the DIC: `router.request_context.base_url`
|
||||||
You can customize it for your functional tests or for generating urls with
|
You can customize it for your functional tests or for generating urls with
|
||||||
the right base url when your are in the cli context.
|
the right base url when your are in the cli context.
|
||||||
* Added support for default templates per render tag
|
* added support for default templates per render tag
|
||||||
|
|
||||||
2.1.0
|
2.1.0
|
||||||
-----
|
-----
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
<?php echo $view['form']->start($form) ?>
|
||||||
|
<?php echo $view['form']->widget($form) ?>
|
||||||
|
<?php echo $view['form']->end($form) ?>
|
@ -0,0 +1,4 @@
|
|||||||
|
<?php if (!isset($render_rest) || $render_rest): ?>
|
||||||
|
<?php echo $view['form']->rest($form) ?>
|
||||||
|
<?php endif ?>
|
||||||
|
</form>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?php $method = strtoupper($method) ?>
|
||||||
|
<?php $form_method = $method === 'GET' || $method === 'POST' ? $method : 'POST' ?>
|
||||||
|
<form method="<?php echo strtolower($form_method) ?>" action="<?php echo $action ?>"<?php foreach ($attr as $k => $v) { printf(' %s="%s"', $view->escape($k), $view->escape($v)); } ?><?php if ($multipart): ?> enctype="multipart/form-data"<?php endif ?>>
|
||||||
|
<?php if ($form_method !== $method): ?>
|
||||||
|
<input type="hidden" name="_method" value="<?php echo $method ?>" />
|
||||||
|
<?php endif ?>
|
@ -57,19 +57,87 @@ class FormHelper extends Helper
|
|||||||
$this->renderer->setTheme($view, $themes);
|
$this->renderer->setTheme($view, $themes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the HTML for a form.
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* <?php echo view['form']->form($form) ?>
|
||||||
|
*
|
||||||
|
* You can pass options during the call:
|
||||||
|
*
|
||||||
|
* <?php echo view['form']->form($form, array('attr' => array('class' => 'foo'))) ?>
|
||||||
|
*
|
||||||
|
* <?php echo view['form']->form($form, array('separator' => '+++++')) ?>
|
||||||
|
*
|
||||||
|
* This method is mainly intended for prototyping purposes. If you want to
|
||||||
|
* control the layout of a form in a more fine-grained manner, you are
|
||||||
|
* advised to use the other helper methods for rendering the parts of the
|
||||||
|
* form individually. You can also create a custom form theme to adapt
|
||||||
|
* the look of the form.
|
||||||
|
*
|
||||||
|
* @param FormView $view The view for which to render the form
|
||||||
|
* @param array $variables Additional variables passed to the template
|
||||||
|
*
|
||||||
|
* @return string The HTML markup
|
||||||
|
*/
|
||||||
|
public function form(FormView $view, array $variables = array())
|
||||||
|
{
|
||||||
|
return $this->renderer->renderBlock($view, 'form', $variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the form start tag.
|
||||||
|
*
|
||||||
|
* Example usage templates:
|
||||||
|
*
|
||||||
|
* <?php echo $view['form']->start($form) ?>>
|
||||||
|
*
|
||||||
|
* @param FormView $view The view for which to render the start tag
|
||||||
|
* @param array $variables Additional variables passed to the template
|
||||||
|
*
|
||||||
|
* @return string The HTML markup
|
||||||
|
*/
|
||||||
|
public function start(FormView $view, array $variables = array())
|
||||||
|
{
|
||||||
|
return $this->renderer->renderBlock($view, 'form_start', $variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the form end tag.
|
||||||
|
*
|
||||||
|
* Example usage templates:
|
||||||
|
*
|
||||||
|
* <?php echo $view['form']->end($form) ?>>
|
||||||
|
*
|
||||||
|
* @param FormView $view The view for which to render the end tag
|
||||||
|
* @param array $variables Additional variables passed to the template
|
||||||
|
*
|
||||||
|
* @return string The HTML markup
|
||||||
|
*/
|
||||||
|
public function end(FormView $view, array $variables = array())
|
||||||
|
{
|
||||||
|
return $this->renderer->renderBlock($view, 'form_end', $variables);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the HTML enctype in the form tag, if necessary.
|
* Renders the HTML enctype in the form tag, if necessary.
|
||||||
*
|
*
|
||||||
* Example usage templates:
|
* Example usage templates:
|
||||||
*
|
*
|
||||||
* <form action="..." method="post" <?php echo $view['form']->enctype() ?>>
|
* <form action="..." method="post" <?php echo $view['form']->enctype($form) ?>>
|
||||||
*
|
*
|
||||||
* @param FormView $view The view for which to render the encoding type
|
* @param FormView $view The view for which to render the encoding type
|
||||||
*
|
*
|
||||||
* @return string The HTML markup
|
* @return string The HTML markup
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
|
||||||
|
* {@link start} instead.
|
||||||
*/
|
*/
|
||||||
public function enctype(FormView $view)
|
public function enctype(FormView $view)
|
||||||
{
|
{
|
||||||
|
trigger_error('The form helper $view[\'form\']->enctype() is deprecated since version 2.3 and will be removed in 3.0. Use $view[\'form\']->start() instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
return $this->renderer->searchAndRenderBlock($view, 'enctype');
|
return $this->renderer->searchAndRenderBlock($view, 'enctype');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,13 +146,13 @@ class FormHelper extends Helper
|
|||||||
*
|
*
|
||||||
* Example usage:
|
* Example usage:
|
||||||
*
|
*
|
||||||
* <?php echo view['form']->widget() ?>
|
* <?php echo view['form']->widget($form) ?>
|
||||||
*
|
*
|
||||||
* You can pass options during the call:
|
* You can pass options during the call:
|
||||||
*
|
*
|
||||||
* <?php echo view['form']->widget(array('attr' => array('class' => 'foo'))) ?>
|
* <?php echo view['form']->widget($form, array('attr' => array('class' => 'foo'))) ?>
|
||||||
*
|
*
|
||||||
* <?php echo view['form']->widget(array('separator' => '+++++')) ?>
|
* <?php echo view['form']->widget($form, array('separator' => '+++++')) ?>
|
||||||
*
|
*
|
||||||
* @param FormView $view The view for which to render the widget
|
* @param FormView $view The view for which to render the widget
|
||||||
* @param array $variables Additional variables passed to the template
|
* @param array $variables Additional variables passed to the template
|
||||||
|
@ -72,6 +72,11 @@ class FormHelperDivLayoutTest extends AbstractDivLayoutTest
|
|||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function renderForm(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->engine->get('form')->form($view, $vars);
|
||||||
|
}
|
||||||
|
|
||||||
protected function renderEnctype(FormView $view)
|
protected function renderEnctype(FormView $view)
|
||||||
{
|
{
|
||||||
return (string) $this->engine->get('form')->enctype($view);
|
return (string) $this->engine->get('form')->enctype($view);
|
||||||
@ -102,6 +107,16 @@ class FormHelperDivLayoutTest extends AbstractDivLayoutTest
|
|||||||
return (string) $this->engine->get('form')->rest($view, $vars);
|
return (string) $this->engine->get('form')->rest($view, $vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function renderStart(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->engine->get('form')->start($view, $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderEnd(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->engine->get('form')->end($view, $vars);
|
||||||
|
}
|
||||||
|
|
||||||
protected function setTheme(FormView $view, array $themes)
|
protected function setTheme(FormView $view, array $themes)
|
||||||
{
|
{
|
||||||
$this->engine->get('form')->setTheme($view, $themes);
|
$this->engine->get('form')->setTheme($view, $themes);
|
||||||
|
@ -73,6 +73,11 @@ class FormHelperTableLayoutTest extends AbstractTableLayoutTest
|
|||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function renderForm(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->engine->get('form')->form($view, $vars);
|
||||||
|
}
|
||||||
|
|
||||||
protected function renderEnctype(FormView $view)
|
protected function renderEnctype(FormView $view)
|
||||||
{
|
{
|
||||||
return (string) $this->engine->get('form')->enctype($view);
|
return (string) $this->engine->get('form')->enctype($view);
|
||||||
@ -103,6 +108,16 @@ class FormHelperTableLayoutTest extends AbstractTableLayoutTest
|
|||||||
return (string) $this->engine->get('form')->rest($view, $vars);
|
return (string) $this->engine->get('form')->rest($view, $vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function renderStart(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->engine->get('form')->start($view, $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderEnd(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->engine->get('form')->end($view, $vars);
|
||||||
|
}
|
||||||
|
|
||||||
protected function setTheme(FormView $view, array $themes)
|
protected function setTheme(FormView $view, array $themes)
|
||||||
{
|
{
|
||||||
$this->engine->get('form')->setTheme($view, $themes);
|
$this->engine->get('form')->setTheme($view, $themes);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
namespace Symfony\Component\Form;
|
namespace Symfony\Component\Form;
|
||||||
|
|
||||||
use Symfony\Component\Form\Exception\AlreadyBoundException;
|
use Symfony\Component\Form\Exception\AlreadyBoundException;
|
||||||
|
use Symfony\Component\Form\Exception\BadMethodCallException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A form button.
|
* A form button.
|
||||||
@ -342,6 +343,18 @@ class Button implements \IteratorAggregate, FormInterface
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported method.
|
||||||
|
*
|
||||||
|
* @param mixed $request
|
||||||
|
*
|
||||||
|
* @throws BadMethodCallException
|
||||||
|
*/
|
||||||
|
public function process($request = null)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException('Buttons cannot be processed. Call process() on the root form instead.');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds data to the button.
|
* Binds data to the button.
|
||||||
*
|
*
|
||||||
|
@ -456,6 +456,42 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
|
|||||||
throw new \BadMethodCallException('Buttons do not support form factories.');
|
throw new \BadMethodCallException('Buttons do not support form factories.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported method.
|
||||||
|
*
|
||||||
|
* @param string $action
|
||||||
|
*
|
||||||
|
* @throws \BadMethodCallException
|
||||||
|
*/
|
||||||
|
public function setAction($action)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Buttons do not support actions.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported method.
|
||||||
|
*
|
||||||
|
* @param string $method
|
||||||
|
*
|
||||||
|
* @throws \BadMethodCallException
|
||||||
|
*/
|
||||||
|
public function setMethod($method)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Buttons do not support methods.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported method.
|
||||||
|
*
|
||||||
|
* @param FormProcessorInterface $formProcessor
|
||||||
|
*
|
||||||
|
* @throws \BadMethodCallException
|
||||||
|
*/
|
||||||
|
public function setFormProcessor(FormProcessorInterface $formProcessor)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Buttons do not support form processors.');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and returns the button configuration.
|
* Builds and returns the button configuration.
|
||||||
*
|
*
|
||||||
@ -693,6 +729,36 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported method.
|
||||||
|
*
|
||||||
|
* @return null Always returns null.
|
||||||
|
*/
|
||||||
|
public function getAction()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported method.
|
||||||
|
*
|
||||||
|
* @return null Always returns null.
|
||||||
|
*/
|
||||||
|
public function getMethod()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsupported method.
|
||||||
|
*
|
||||||
|
* @return null Always returns null.
|
||||||
|
*/
|
||||||
|
public function getFormProcessor()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all options passed during the construction of the button.
|
* Returns all options passed during the construction of the button.
|
||||||
*
|
*
|
||||||
|
@ -6,6 +6,9 @@ CHANGELOG
|
|||||||
------
|
------
|
||||||
|
|
||||||
* changed FormRenderer::humanize() to humanize also camel cased field name
|
* changed FormRenderer::humanize() to humanize also camel cased field name
|
||||||
|
* added FormProcessorInterface and FormInterface::process()
|
||||||
|
* deprecated passing a Request instance to FormInterface::bind()
|
||||||
|
* added options "method" and "action" to FormType
|
||||||
|
|
||||||
2.2.0
|
2.2.0
|
||||||
-----
|
-----
|
||||||
|
@ -53,6 +53,8 @@ class FormType extends BaseType
|
|||||||
->setData(isset($options['data']) ? $options['data'] : null)
|
->setData(isset($options['data']) ? $options['data'] : null)
|
||||||
->setDataLocked(isset($options['data']))
|
->setDataLocked(isset($options['data']))
|
||||||
->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null)
|
->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null)
|
||||||
|
->setMethod($options['method'])
|
||||||
|
->setAction($options['action'])
|
||||||
;
|
;
|
||||||
|
|
||||||
if ($options['trim']) {
|
if ($options['trim']) {
|
||||||
@ -93,6 +95,8 @@ class FormType extends BaseType
|
|||||||
'size' => null,
|
'size' => null,
|
||||||
'label_attr' => $options['label_attr'],
|
'label_attr' => $options['label_attr'],
|
||||||
'compound' => $form->getConfig()->getCompound(),
|
'compound' => $form->getConfig()->getCompound(),
|
||||||
|
'method' => $form->getConfig()->getMethod(),
|
||||||
|
'action' => $form->getConfig()->getAction(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +171,10 @@ class FormType extends BaseType
|
|||||||
'label_attr' => array(),
|
'label_attr' => array(),
|
||||||
'virtual' => false,
|
'virtual' => false,
|
||||||
'compound' => true,
|
'compound' => true,
|
||||||
|
'method' => 'POST',
|
||||||
|
// According to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt)
|
||||||
|
// section 4.2., empty URIs are considered same-document references
|
||||||
|
'action' => '',
|
||||||
));
|
));
|
||||||
|
|
||||||
$resolver->setAllowedTypes(array(
|
$resolver->setAllowedTypes(array(
|
||||||
|
@ -19,6 +19,9 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Pass the
|
||||||
|
* Request instance to {@link Form::process()} instead.
|
||||||
*/
|
*/
|
||||||
class BindRequestListener implements EventSubscriberInterface
|
class BindRequestListener implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
@ -40,6 +43,8 @@ class BindRequestListener implements EventSubscriberInterface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trigger_error('Passing a Request instance to Form::bind() is deprecated since version 2.3 and will be disabled in 3.0. Call Form::process($request) instead.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
$name = $form->getConfig()->getName();
|
$name = $form->getConfig()->getName();
|
||||||
$default = $form->getConfig()->getCompound() ? array() : null;
|
$default = $form->getConfig()->getCompound() ? array() : null;
|
||||||
|
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Form\Extension\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Exception\InvalidArgumentException;
|
||||||
|
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormProcessorInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A form processor using the {@link Request} class of the HttpFoundation
|
||||||
|
* component.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class RequestFormProcessor implements FormProcessorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function processForm(FormInterface $form, $request = null)
|
||||||
|
{
|
||||||
|
if (!$request instanceof Request) {
|
||||||
|
throw new UnexpectedTypeException($request, 'Symfony\Component\HttpFoundation\Request');
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $form->getName();
|
||||||
|
$method = $form->getConfig()->getMethod();
|
||||||
|
|
||||||
|
if ($method !== $request->getMethod()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('GET' === $method) {
|
||||||
|
if ('' === $name) {
|
||||||
|
$data = $request->query->all();
|
||||||
|
} else {
|
||||||
|
// Don't bind GET requests if the form's name does not exist
|
||||||
|
// in the request
|
||||||
|
if (!$request->query->has($name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $request->query->get($name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ('' === $name) {
|
||||||
|
$params = $request->request->all();
|
||||||
|
$files = $request->files->all();
|
||||||
|
} else {
|
||||||
|
$default = $form->getConfig()->getCompound() ? array() : null;
|
||||||
|
$params = $request->request->get($name, $default);
|
||||||
|
$files = $request->files->get($name, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($params) && is_array($files)) {
|
||||||
|
$data = array_replace_recursive($params, $files);
|
||||||
|
} else {
|
||||||
|
$data = $params ?: $files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't auto-bind the form unless at least one field is submitted.
|
||||||
|
if ('' === $name && count(array_intersect_key($data, $form->all())) <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->bind($data);
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Extension\HttpFoundation\Type;
|
|||||||
|
|
||||||
use Symfony\Component\Form\AbstractTypeExtension;
|
use Symfony\Component\Form\AbstractTypeExtension;
|
||||||
use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
|
use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
|
||||||
|
use Symfony\Component\Form\Extension\HttpFoundation\RequestFormProcessor;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,9 +26,15 @@ class FormTypeHttpFoundationExtension extends AbstractTypeExtension
|
|||||||
*/
|
*/
|
||||||
private $listener;
|
private $listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var RequestFormProcessor
|
||||||
|
*/
|
||||||
|
private $processor;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->listener = new BindRequestListener();
|
$this->listener = new BindRequestListener();
|
||||||
|
$this->processor = new RequestFormProcessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,6 +43,7 @@ class FormTypeHttpFoundationExtension extends AbstractTypeExtension
|
|||||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
{
|
{
|
||||||
$builder->addEventSubscriber($this->listener);
|
$builder->addEventSubscriber($this->listener);
|
||||||
|
$builder->setFormProcessor($this->processor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -404,6 +404,16 @@ class Form implements \IteratorAggregate, FormInterface
|
|||||||
return $this->extraData;
|
return $this->extraData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function process($request = null)
|
||||||
|
{
|
||||||
|
$this->config->getFormProcessor()->processForm($this, $request);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -579,7 +589,7 @@ class Form implements \IteratorAggregate, FormInterface
|
|||||||
public function isValid()
|
public function isValid()
|
||||||
{
|
{
|
||||||
if (!$this->bound) {
|
if (!$this->bound) {
|
||||||
throw new \LogicException('You cannot call isValid() on a form that is not bound.');
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($this->errors) > 0) {
|
if (count($this->errors) > 0) {
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
namespace Symfony\Component\Form;
|
namespace Symfony\Component\Form;
|
||||||
|
|
||||||
use Symfony\Component\Form\Exception\BadMethodCallException;
|
use Symfony\Component\Form\Exception\BadMethodCallException;
|
||||||
use Symfony\Component\Form\Exception\Exception;
|
use Symfony\Component\Form\Exception\InvalidArgumentException;
|
||||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||||
use Symfony\Component\PropertyAccess\PropertyPath;
|
use Symfony\Component\PropertyAccess\PropertyPath;
|
||||||
use Symfony\Component\PropertyAccess\PropertyPathInterface;
|
use Symfony\Component\PropertyAccess\PropertyPathInterface;
|
||||||
@ -27,6 +27,26 @@ use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
|
|||||||
*/
|
*/
|
||||||
class FormConfigBuilder implements FormConfigBuilderInterface
|
class FormConfigBuilder implements FormConfigBuilderInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Caches a globally unique {@link NativeFormProcessor} instance.
|
||||||
|
*
|
||||||
|
* @var NativeFormProcessor
|
||||||
|
*/
|
||||||
|
private static $nativeFormProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The accepted request methods.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $allowedMethods = array(
|
||||||
|
'GET',
|
||||||
|
'PUT',
|
||||||
|
'POST',
|
||||||
|
'DELETE',
|
||||||
|
'PATCH'
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Boolean
|
* @var Boolean
|
||||||
*/
|
*/
|
||||||
@ -137,6 +157,21 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||||||
*/
|
*/
|
||||||
private $formFactory;
|
private $formFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $method = 'POST';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FormProcessorInterface
|
||||||
|
*/
|
||||||
|
private $formProcessor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@ -264,6 +299,10 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||||||
*/
|
*/
|
||||||
public function getEventDispatcher()
|
public function getEventDispatcher()
|
||||||
{
|
{
|
||||||
|
if ($this->locked && !$this->dispatcher instanceof ImmutableEventDispatcher) {
|
||||||
|
$this->dispatcher = new ImmutableEventDispatcher($this->dispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
return $this->dispatcher;
|
return $this->dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,6 +474,37 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||||||
return $this->formFactory;
|
return $this->formFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getAction()
|
||||||
|
{
|
||||||
|
return $this->action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getMethod()
|
||||||
|
{
|
||||||
|
return $this->method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getFormProcessor()
|
||||||
|
{
|
||||||
|
if (null === $this->formProcessor) {
|
||||||
|
if (null === self::$nativeFormProcessor) {
|
||||||
|
self::$nativeFormProcessor = new NativeFormProcessor();
|
||||||
|
}
|
||||||
|
$this->formProcessor = self::$nativeFormProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->formProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -687,6 +757,58 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setAction($action)
|
||||||
|
{
|
||||||
|
if ($this->locked) {
|
||||||
|
throw new BadMethodCallException('The config builder cannot be modified anymore.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->action = $action;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setMethod($method)
|
||||||
|
{
|
||||||
|
if ($this->locked) {
|
||||||
|
throw new BadMethodCallException('The config builder cannot be modified anymore.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$upperCaseMethod = strtoupper($method);
|
||||||
|
|
||||||
|
if (!in_array($upperCaseMethod, self::$allowedMethods)) {
|
||||||
|
throw new InvalidArgumentException(sprintf(
|
||||||
|
'The form method is "%s", but should be one of "%s".',
|
||||||
|
$method,
|
||||||
|
implode('", "', self::$allowedMethods)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->method = $upperCaseMethod;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setFormProcessor(FormProcessorInterface $formProcessor)
|
||||||
|
{
|
||||||
|
if ($this->locked) {
|
||||||
|
throw new BadMethodCallException('The config builder cannot be modified anymore.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->formProcessor = $formProcessor;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
@ -700,10 +822,6 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||||||
$config = clone $this;
|
$config = clone $this;
|
||||||
$config->locked = true;
|
$config->locked = true;
|
||||||
|
|
||||||
if (!$config->dispatcher instanceof ImmutableEventDispatcher) {
|
|
||||||
$config->dispatcher = new ImmutableEventDispatcher($config->dispatcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $config;
|
return $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,6 +237,31 @@ interface FormConfigBuilderInterface extends FormConfigInterface
|
|||||||
*/
|
*/
|
||||||
public function setFormFactory(FormFactoryInterface $formFactory);
|
public function setFormFactory(FormFactoryInterface $formFactory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the target URL of the form.
|
||||||
|
*
|
||||||
|
* @param string $action The target URL of the form.
|
||||||
|
*
|
||||||
|
* @return self The configuration object.
|
||||||
|
*/
|
||||||
|
public function setAction($action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the HTTP method used by the form.
|
||||||
|
*
|
||||||
|
* @param string $method The HTTP method of the form.
|
||||||
|
*
|
||||||
|
* @return self The configuration object.
|
||||||
|
*/
|
||||||
|
public function setMethod($method);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param FormProcessorInterface $formProcessor
|
||||||
|
*
|
||||||
|
* @return self The configuration object.
|
||||||
|
*/
|
||||||
|
public function setFormProcessor(FormProcessorInterface $formProcessor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and returns the form configuration.
|
* Builds and returns the form configuration.
|
||||||
*
|
*
|
||||||
|
@ -190,6 +190,25 @@ interface FormConfigInterface
|
|||||||
*/
|
*/
|
||||||
public function getFormFactory();
|
public function getFormFactory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the target URL of the form.
|
||||||
|
*
|
||||||
|
* @return string The target URL of the form.
|
||||||
|
*/
|
||||||
|
public function getAction();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the HTTP method used by the form.
|
||||||
|
*
|
||||||
|
* @return string The HTTP method of the form.
|
||||||
|
*/
|
||||||
|
public function getMethod();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FormProcessorInterface The form processor.
|
||||||
|
*/
|
||||||
|
public function getFormProcessor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all options passed during the construction of the form.
|
* Returns all options passed during the construction of the form.
|
||||||
*
|
*
|
||||||
|
@ -182,6 +182,8 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
|
|||||||
/**
|
/**
|
||||||
* Returns whether the form and all children are valid.
|
* Returns whether the form and all children are valid.
|
||||||
*
|
*
|
||||||
|
* If the form is not bound, this method always returns false.
|
||||||
|
*
|
||||||
* @return Boolean
|
* @return Boolean
|
||||||
*/
|
*/
|
||||||
public function isValid();
|
public function isValid();
|
||||||
@ -224,6 +226,19 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
|
|||||||
*/
|
*/
|
||||||
public function isSynchronized();
|
public function isSynchronized();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the given request and binds the form if it was submitted.
|
||||||
|
*
|
||||||
|
* Internally, the request is forwarded to a {@link FormProcessorInterface}
|
||||||
|
* instance. This instance determines the allowed value of the
|
||||||
|
* $request parameter.
|
||||||
|
*
|
||||||
|
* @param mixed $request The request to check.
|
||||||
|
*
|
||||||
|
* @return FormInterface The form instance.
|
||||||
|
*/
|
||||||
|
public function process($request = null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds data to the form, transforms and validates it.
|
* Binds data to the form, transforms and validates it.
|
||||||
*
|
*
|
||||||
|
28
src/Symfony/Component/Form/FormProcessorInterface.php
Normal file
28
src/Symfony/Component/Form/FormProcessorInterface.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Form;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds forms from requests if they were submitted.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
interface FormProcessorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Binds a form from a request if it was submitted.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form The form to bind.
|
||||||
|
* @param mixed $request The current request.
|
||||||
|
*/
|
||||||
|
public function processForm(FormInterface $form, $request = null);
|
||||||
|
}
|
194
src/Symfony/Component/Form/NativeFormProcessor.php
Normal file
194
src/Symfony/Component/Form/NativeFormProcessor.php
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Form;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormProcessorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A form processor using PHP's super globals $_GET, $_POST and $_SERVER.
|
||||||
|
*
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class NativeFormProcessor implements FormProcessorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The allowed keys of the $_FILES array.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $fileKeys = array(
|
||||||
|
'error',
|
||||||
|
'name',
|
||||||
|
'size',
|
||||||
|
'tmp_name',
|
||||||
|
'type',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function processForm(FormInterface $form, $request = null)
|
||||||
|
{
|
||||||
|
if (null !== $request) {
|
||||||
|
throw new UnexpectedTypeException($request, 'null');
|
||||||
|
}
|
||||||
|
|
||||||
|
$name = $form->getName();
|
||||||
|
$method = $form->getConfig()->getMethod();
|
||||||
|
|
||||||
|
if ($method !== self::getRequestMethod()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('GET' === $method) {
|
||||||
|
if ('' === $name) {
|
||||||
|
$data = $_GET;
|
||||||
|
} else {
|
||||||
|
// Don't bind GET requests if the form's name does not exist
|
||||||
|
// in the request
|
||||||
|
if (!isset($_GET[$name])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $_GET[$name];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$fixedFiles = array();
|
||||||
|
foreach ($_FILES as $name => $file) {
|
||||||
|
$fixedFiles[$name] = self::stripEmptyFiles(self::fixPhpFilesArray($file));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('' === $name) {
|
||||||
|
$params = $_POST;
|
||||||
|
$files = $fixedFiles;
|
||||||
|
} else {
|
||||||
|
$default = $form->getConfig()->getCompound() ? array() : null;
|
||||||
|
$params = isset($_POST[$name]) ? $_POST[$name] : $default;
|
||||||
|
$files = isset($fixedFiles[$name]) ? $fixedFiles[$name] : $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($params) && is_array($files)) {
|
||||||
|
$data = array_replace_recursive($params, $files);
|
||||||
|
} else {
|
||||||
|
$data = $params ?: $files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't auto-bind the form unless at least one field is submitted.
|
||||||
|
if ('' === $name && count(array_intersect_key($data, $form->all())) <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->bind($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the method used to submit the request to the server.
|
||||||
|
*
|
||||||
|
* @return string The request method.
|
||||||
|
*/
|
||||||
|
private static function getRequestMethod()
|
||||||
|
{
|
||||||
|
$method = isset($_SERVER['REQUEST_METHOD'])
|
||||||
|
? strtoupper($_SERVER['REQUEST_METHOD'])
|
||||||
|
: 'GET';
|
||||||
|
|
||||||
|
if ('POST' === $method && isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
|
||||||
|
$method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixes a malformed PHP $_FILES array.
|
||||||
|
*
|
||||||
|
* PHP has a bug that the format of the $_FILES array differs, depending on
|
||||||
|
* whether the uploaded file fields had normal field names or array-like
|
||||||
|
* field names ("normal" vs. "parent[child]").
|
||||||
|
*
|
||||||
|
* This method fixes the array to look like the "normal" $_FILES array.
|
||||||
|
*
|
||||||
|
* It's safe to pass an already converted array, in which case this method
|
||||||
|
* just returns the original array unmodified.
|
||||||
|
*
|
||||||
|
* This method is identical to {@link Symfony\Component\HttpFoundation\FileBag::fixPhpFilesArray}
|
||||||
|
* and should be kept as such in order to port fixes quickly and easily.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private static function fixPhpFilesArray($data)
|
||||||
|
{
|
||||||
|
if (!is_array($data)) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$keys = array_keys($data);
|
||||||
|
sort($keys);
|
||||||
|
|
||||||
|
if (self::$fileKeys !== $keys || !isset($data['name']) || !is_array($data['name'])) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = $data;
|
||||||
|
foreach (self::$fileKeys as $k) {
|
||||||
|
unset($files[$k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (array_keys($data['name']) as $key) {
|
||||||
|
$files[$key] = self::fixPhpFilesArray(array(
|
||||||
|
'error' => $data['error'][$key],
|
||||||
|
'name' => $data['name'][$key],
|
||||||
|
'type' => $data['type'][$key],
|
||||||
|
'tmp_name' => $data['tmp_name'][$key],
|
||||||
|
'size' => $data['size'][$key]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets empty uploaded files to NULL in the given uploaded files array.
|
||||||
|
*
|
||||||
|
* @param mixed $data The file upload data.
|
||||||
|
*
|
||||||
|
* @return array|null Returns the stripped upload data.
|
||||||
|
*/
|
||||||
|
private static function stripEmptyFiles($data)
|
||||||
|
{
|
||||||
|
if (!is_array($data)) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$keys = array_keys($data);
|
||||||
|
sort($keys);
|
||||||
|
|
||||||
|
if (self::$fileKeys === $keys) {
|
||||||
|
if (UPLOAD_ERR_NO_FILE === $data['error']) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
$data[$key] = self::stripEmptyFiles($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Form\Test;
|
namespace Symfony\Component\Form\Test;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
|
||||||
class DeprecationErrorHandler
|
class DeprecationErrorHandler
|
||||||
{
|
{
|
||||||
public static function handle($errorNumber, $message, $file, $line, $context)
|
public static function handle($errorNumber, $message, $file, $line, $context)
|
||||||
@ -21,4 +23,11 @@ class DeprecationErrorHandler
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function preBind($listener, FormEvent $event)
|
||||||
|
{
|
||||||
|
set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handle'));
|
||||||
|
$listener->preBind($event);
|
||||||
|
restore_error_handler();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,6 +378,50 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testForm()
|
public function testForm()
|
||||||
|
{
|
||||||
|
$form = $this->factory->createNamedBuilder('name', 'form')
|
||||||
|
->setMethod('PUT')
|
||||||
|
->setAction('http://example.com')
|
||||||
|
->add('firstName', 'text')
|
||||||
|
->add('lastName', 'text')
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
// include ampersands everywhere to validate escaping
|
||||||
|
$html = $this->renderForm($form->createView(), array(
|
||||||
|
'id' => 'my&id',
|
||||||
|
'attr' => array('class' => 'my&class'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->assertMatchesXpath($html,
|
||||||
|
'/form
|
||||||
|
[
|
||||||
|
./input[@type="hidden"][@name="_method"][@value="PUT"]
|
||||||
|
/following-sibling::div
|
||||||
|
[
|
||||||
|
./div
|
||||||
|
[
|
||||||
|
./label[@for="name_firstName"]
|
||||||
|
/following-sibling::input[@type="text"][@id="name_firstName"]
|
||||||
|
]
|
||||||
|
/following-sibling::div
|
||||||
|
[
|
||||||
|
./label[@for="name_lastName"]
|
||||||
|
/following-sibling::input[@type="text"][@id="name_lastName"]
|
||||||
|
]
|
||||||
|
/following-sibling::input[@type="hidden"][@id="name__token"]
|
||||||
|
]
|
||||||
|
[count(.//input)=3]
|
||||||
|
[@id="my&id"]
|
||||||
|
[@class="my&class"]
|
||||||
|
]
|
||||||
|
[@method="post"]
|
||||||
|
[@action="http://example.com"]
|
||||||
|
[@class="my&class"]
|
||||||
|
'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFormWidget()
|
||||||
{
|
{
|
||||||
$form = $this->factory->createNamedBuilder('name', 'form')
|
$form = $this->factory->createNamedBuilder('name', 'form')
|
||||||
->add('firstName', 'text')
|
->add('firstName', 'text')
|
||||||
@ -642,4 +686,50 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
|
|||||||
'
|
'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFormEndWithRest()
|
||||||
|
{
|
||||||
|
$view = $this->factory->createNamedBuilder('name', 'form')
|
||||||
|
->add('field1', 'text')
|
||||||
|
->add('field2', 'text')
|
||||||
|
->getForm()
|
||||||
|
->createView();
|
||||||
|
|
||||||
|
$this->renderWidget($view['field1']);
|
||||||
|
|
||||||
|
// Rest should only contain field2
|
||||||
|
$html = $this->renderEnd($view);
|
||||||
|
|
||||||
|
// Insert the start tag, the end tag should be rendered by the helper
|
||||||
|
$this->assertMatchesXpath('<form>' . $html,
|
||||||
|
'/form
|
||||||
|
[
|
||||||
|
./div
|
||||||
|
[
|
||||||
|
./label[@for="name_field2"]
|
||||||
|
/following-sibling::input[@type="text"][@id="name_field2"]
|
||||||
|
]
|
||||||
|
/following-sibling::input
|
||||||
|
[@type="hidden"]
|
||||||
|
[@id="name__token"]
|
||||||
|
]
|
||||||
|
'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFormEndWithoutRest()
|
||||||
|
{
|
||||||
|
$view = $this->factory->createNamedBuilder('name', 'form')
|
||||||
|
->add('field1', 'text')
|
||||||
|
->add('field2', 'text')
|
||||||
|
->getForm()
|
||||||
|
->createView();
|
||||||
|
|
||||||
|
$this->renderWidget($view['field1']);
|
||||||
|
|
||||||
|
// Rest should only contain field2, but isn't rendered
|
||||||
|
$html = $this->renderEnd($view, array('render_rest' => false));
|
||||||
|
|
||||||
|
$this->assertEquals('</form>', $html);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
280
src/Symfony/Component/Form/Tests/AbstractFormProcessorTest.php
Normal file
280
src/Symfony/Component/Form/Tests/AbstractFormProcessorTest.php
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Form\Tests;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
abstract class AbstractFormProcessorTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Symfony\Component\Form\FormProcessorInterface
|
||||||
|
*/
|
||||||
|
protected $processor;
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->processor = $this->getFormProcessor();
|
||||||
|
$this->request = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function methodExceptGetProvider()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('POST'),
|
||||||
|
array('PUT'),
|
||||||
|
array('DELETE'),
|
||||||
|
array('PATCH'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function methodProvider()
|
||||||
|
{
|
||||||
|
return array_merge(array(
|
||||||
|
array('GET'),
|
||||||
|
), $this->methodExceptGetProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodProvider
|
||||||
|
*/
|
||||||
|
public function testBindIfNameInRequest($method)
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', $method);
|
||||||
|
|
||||||
|
$this->setRequestData($method, array(
|
||||||
|
'param1' => 'DATA',
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with('DATA');
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodProvider
|
||||||
|
*/
|
||||||
|
public function testDoNotBindIfWrongRequestMethod($method)
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', $method);
|
||||||
|
|
||||||
|
$otherMethod = 'POST' === $method ? 'PUT' : 'POST';
|
||||||
|
|
||||||
|
$this->setRequestData($otherMethod, array(
|
||||||
|
'param1' => 'DATA',
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->never())
|
||||||
|
->method('bind');
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodExceptGetProvider
|
||||||
|
*/
|
||||||
|
public function testBindSimpleFormWithNullIfNameNotInRequestAndNotGetRequest($method)
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', $method, false);
|
||||||
|
|
||||||
|
$this->setRequestData($method, array(
|
||||||
|
'paramx' => array(),
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with($this->identicalTo(null));
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodExceptGetProvider
|
||||||
|
*/
|
||||||
|
public function testBindCompoundFormWithArrayIfNameNotInRequestAndNotGetRequest($method)
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', $method, true);
|
||||||
|
|
||||||
|
$this->setRequestData($method, array(
|
||||||
|
'paramx' => array(),
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with($this->identicalTo(array()));
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoNotBindIfNameNotInRequestAndGetRequest()
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', 'GET');
|
||||||
|
|
||||||
|
$this->setRequestData('GET', array(
|
||||||
|
'paramx' => array(),
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->never())
|
||||||
|
->method('bind');
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodProvider
|
||||||
|
*/
|
||||||
|
public function testBindFormWithEmptyNameIfAtLeastOneFieldInRequest($method)
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('', $method);
|
||||||
|
$form->expects($this->any())
|
||||||
|
->method('all')
|
||||||
|
->will($this->returnValue(array(
|
||||||
|
'param1' => $this->getMockForm('param1'),
|
||||||
|
'param2' => $this->getMockForm('param2'),
|
||||||
|
)));
|
||||||
|
|
||||||
|
$this->setRequestData($method, $requestData = array(
|
||||||
|
'param1' => 'submitted value',
|
||||||
|
'paramx' => 'submitted value',
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with($requestData);
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodProvider
|
||||||
|
*/
|
||||||
|
public function testDoNotBindFormWithEmptyNameIfNoFieldInRequest($method)
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('', $method);
|
||||||
|
$form->expects($this->any())
|
||||||
|
->method('all')
|
||||||
|
->will($this->returnValue(array(
|
||||||
|
'param1' => $this->getMockForm('param1'),
|
||||||
|
'param2' => $this->getMockForm('param2'),
|
||||||
|
)));
|
||||||
|
|
||||||
|
$this->setRequestData($method, array(
|
||||||
|
'paramx' => 'submitted value',
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->never())
|
||||||
|
->method('bind');
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodExceptGetProvider
|
||||||
|
*/
|
||||||
|
public function testMergeParamsAndFiles($method)
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', $method);
|
||||||
|
$file = $this->getMockFile();
|
||||||
|
|
||||||
|
$this->setRequestData($method, array(
|
||||||
|
'param1' => array(
|
||||||
|
'field1' => 'DATA',
|
||||||
|
),
|
||||||
|
), array(
|
||||||
|
'param1' => array(
|
||||||
|
'field2' => $file,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with(array(
|
||||||
|
'field1' => 'DATA',
|
||||||
|
'field2' => $file,
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodExceptGetProvider
|
||||||
|
*/
|
||||||
|
public function testParamTakesPrecedenceOverFile($method)
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', $method);
|
||||||
|
$file = $this->getMockFile();
|
||||||
|
|
||||||
|
$this->setRequestData($method, array(
|
||||||
|
'param1' => 'DATA',
|
||||||
|
), array(
|
||||||
|
'param1' => $file,
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with('DATA');
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider methodExceptGetProvider
|
||||||
|
*/
|
||||||
|
public function testBindFileIfNoParam($method)
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', $method);
|
||||||
|
$file = $this->getMockFile();
|
||||||
|
|
||||||
|
$this->setRequestData($method, array(
|
||||||
|
'param1' => null,
|
||||||
|
), array(
|
||||||
|
'param1' => $file,
|
||||||
|
));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with($file);
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function setRequestData($method, $data, $files = array());
|
||||||
|
|
||||||
|
abstract protected function getFormProcessor();
|
||||||
|
|
||||||
|
abstract protected function getMockFile();
|
||||||
|
|
||||||
|
protected function getMockForm($name, $method = null, $compound = true)
|
||||||
|
{
|
||||||
|
$config = $this->getMock('Symfony\Component\Form\FormConfigInterface');
|
||||||
|
$config->expects($this->any())
|
||||||
|
->method('getMethod')
|
||||||
|
->will($this->returnValue($method));
|
||||||
|
$config->expects($this->any())
|
||||||
|
->method('getCompound')
|
||||||
|
->will($this->returnValue($compound));
|
||||||
|
|
||||||
|
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||||
|
$form->expects($this->any())
|
||||||
|
->method('getName')
|
||||||
|
->will($this->returnValue($name));
|
||||||
|
$form->expects($this->any())
|
||||||
|
->method('getConfig')
|
||||||
|
->will($this->returnValue($config));
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
}
|
@ -19,8 +19,6 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
|
|||||||
{
|
{
|
||||||
protected $csrfProvider;
|
protected $csrfProvider;
|
||||||
|
|
||||||
protected $factory;
|
|
||||||
|
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
if (!extension_loaded('intl')) {
|
if (!extension_loaded('intl')) {
|
||||||
@ -44,7 +42,6 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
|
|||||||
protected function tearDown()
|
protected function tearDown()
|
||||||
{
|
{
|
||||||
$this->csrfProvider = null;
|
$this->csrfProvider = null;
|
||||||
$this->factory = null;
|
|
||||||
|
|
||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
@ -102,6 +99,8 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
|
|||||||
$this->assertMatchesXpath($html, $xpath);
|
$this->assertMatchesXpath($html, $xpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract protected function renderForm(FormView $view, array $vars = array());
|
||||||
|
|
||||||
abstract protected function renderEnctype(FormView $view);
|
abstract protected function renderEnctype(FormView $view);
|
||||||
|
|
||||||
abstract protected function renderLabel(FormView $view, $label = null, array $vars = array());
|
abstract protected function renderLabel(FormView $view, $label = null, array $vars = array());
|
||||||
@ -114,6 +113,10 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
|
|||||||
|
|
||||||
abstract protected function renderRest(FormView $view, array $vars = array());
|
abstract protected function renderRest(FormView $view, array $vars = array());
|
||||||
|
|
||||||
|
abstract protected function renderStart(FormView $view, array $vars = array());
|
||||||
|
|
||||||
|
abstract protected function renderEnd(FormView $view, array $vars = array());
|
||||||
|
|
||||||
abstract protected function setTheme(FormView $view, array $themes);
|
abstract protected function setTheme(FormView $view, array $themes);
|
||||||
|
|
||||||
public function testEnctype()
|
public function testEnctype()
|
||||||
@ -1744,9 +1747,7 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
|
|||||||
$this->assertMatchesXpath($html,
|
$this->assertMatchesXpath($html,
|
||||||
'//div[@id="name_items"][@data-prototype]
|
'//div[@id="name_items"][@data-prototype]
|
||||||
|
|
|
|
||||||
//table[@id="name_items"][@data-prototype]
|
//table[@id="name_items"][@data-prototype]'
|
||||||
|
|
||||||
'
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1796,4 +1797,76 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
|
|||||||
'/button[@type="reset"][@name="name"]'
|
'/button[@type="reset"][@name="name"]'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testStartTag()
|
||||||
|
{
|
||||||
|
$form = $this->factory->create('form', null, array(
|
||||||
|
'method' => 'get',
|
||||||
|
'action' => 'http://example.com/directory'
|
||||||
|
));
|
||||||
|
|
||||||
|
$html = $this->renderStart($form->createView());
|
||||||
|
|
||||||
|
$this->assertSame('<form method="get" action="http://example.com/directory">', $html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStartTagForPutRequest()
|
||||||
|
{
|
||||||
|
$form = $this->factory->create('form', null, array(
|
||||||
|
'method' => 'put',
|
||||||
|
'action' => 'http://example.com/directory'
|
||||||
|
));
|
||||||
|
|
||||||
|
$html = $this->renderStart($form->createView());
|
||||||
|
|
||||||
|
$this->assertMatchesXpath($html . '</form>',
|
||||||
|
'/form
|
||||||
|
[./input[@type="hidden"][@name="_method"][@value="PUT"]]
|
||||||
|
[@method="post"]
|
||||||
|
[@action="http://example.com/directory"]'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStartTagWithOverriddenVars()
|
||||||
|
{
|
||||||
|
$form = $this->factory->create('form', null, array(
|
||||||
|
'method' => 'put',
|
||||||
|
'action' => 'http://example.com/directory',
|
||||||
|
));
|
||||||
|
|
||||||
|
$html = $this->renderStart($form->createView(), array(
|
||||||
|
'method' => 'post',
|
||||||
|
'action' => 'http://foo.com/directory'
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->assertSame('<form method="post" action="http://foo.com/directory">', $html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStartTagForMultipartForm()
|
||||||
|
{
|
||||||
|
$form = $this->factory->createBuilder('form', null, array(
|
||||||
|
'method' => 'get',
|
||||||
|
'action' => 'http://example.com/directory'
|
||||||
|
))
|
||||||
|
->add('file', 'file')
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$html = $this->renderStart($form->createView());
|
||||||
|
|
||||||
|
$this->assertSame('<form method="get" action="http://example.com/directory" enctype="multipart/form-data">', $html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testStartTagWithExtraAttributes()
|
||||||
|
{
|
||||||
|
$form = $this->factory->create('form', null, array(
|
||||||
|
'method' => 'get',
|
||||||
|
'action' => 'http://example.com/directory'
|
||||||
|
));
|
||||||
|
|
||||||
|
$html = $this->renderStart($form->createView(), array(
|
||||||
|
'attr' => array('class' => 'foobar'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->assertSame('<form method="get" action="http://example.com/directory" class="foobar">', $html);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,6 +224,58 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testForm()
|
public function testForm()
|
||||||
|
{
|
||||||
|
$view = $this->factory->createNamedBuilder('name', 'form')
|
||||||
|
->setMethod('PUT')
|
||||||
|
->setAction('http://example.com')
|
||||||
|
->add('firstName', 'text')
|
||||||
|
->add('lastName', 'text')
|
||||||
|
->getForm()
|
||||||
|
->createView();
|
||||||
|
|
||||||
|
$html = $this->renderForm($view, array(
|
||||||
|
'id' => 'my&id',
|
||||||
|
'attr' => array('class' => 'my&class'),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->assertMatchesXpath($html,
|
||||||
|
'/form
|
||||||
|
[
|
||||||
|
./input[@type="hidden"][@name="_method"][@value="PUT"]
|
||||||
|
/following-sibling::table
|
||||||
|
[
|
||||||
|
./tr
|
||||||
|
[
|
||||||
|
./td
|
||||||
|
[./label[@for="name_firstName"]]
|
||||||
|
/following-sibling::td
|
||||||
|
[./input[@id="name_firstName"]]
|
||||||
|
]
|
||||||
|
/following-sibling::tr
|
||||||
|
[
|
||||||
|
./td
|
||||||
|
[./label[@for="name_lastName"]]
|
||||||
|
/following-sibling::td
|
||||||
|
[./input[@id="name_lastName"]]
|
||||||
|
]
|
||||||
|
/following-sibling::tr[@style="display: none"]
|
||||||
|
[./td[@colspan="2"]/input
|
||||||
|
[@type="hidden"]
|
||||||
|
[@id="name__token"]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[count(.//input)=3]
|
||||||
|
[@id="my&id"]
|
||||||
|
[@class="my&class"]
|
||||||
|
]
|
||||||
|
[@method="post"]
|
||||||
|
[@action="http://example.com"]
|
||||||
|
[@class="my&class"]
|
||||||
|
'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFormWidget()
|
||||||
{
|
{
|
||||||
$view = $this->factory->createNamedBuilder('name', 'form')
|
$view = $this->factory->createNamedBuilder('name', 'form')
|
||||||
->add('firstName', 'text')
|
->add('firstName', 'text')
|
||||||
@ -400,4 +452,58 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
|
|||||||
'
|
'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFormEndWithRest()
|
||||||
|
{
|
||||||
|
$view = $this->factory->createNamedBuilder('name', 'form')
|
||||||
|
->add('field1', 'text')
|
||||||
|
->add('field2', 'text')
|
||||||
|
->getForm()
|
||||||
|
->createView();
|
||||||
|
|
||||||
|
$this->renderWidget($view['field1']);
|
||||||
|
|
||||||
|
// Rest should only contain field2
|
||||||
|
$html = $this->renderEnd($view);
|
||||||
|
|
||||||
|
// Insert the start tag, the end tag should be rendered by the helper
|
||||||
|
// Unfortunately this is not valid HTML, because the surrounding table
|
||||||
|
// tag is missing. If someone renders a form with table layout
|
||||||
|
// manually, she should call form_rest() explicitly within the <table>
|
||||||
|
// tag.
|
||||||
|
$this->assertMatchesXpath('<form>' . $html,
|
||||||
|
'/form
|
||||||
|
[
|
||||||
|
./tr
|
||||||
|
[
|
||||||
|
./td
|
||||||
|
[./label[@for="name_field2"]]
|
||||||
|
/following-sibling::td
|
||||||
|
[./input[@id="name_field2"]]
|
||||||
|
]
|
||||||
|
/following-sibling::tr[@style="display: none"]
|
||||||
|
[./td[@colspan="2"]/input
|
||||||
|
[@type="hidden"]
|
||||||
|
[@id="name__token"]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFormEndWithoutRest()
|
||||||
|
{
|
||||||
|
$view = $this->factory->createNamedBuilder('name', 'form')
|
||||||
|
->add('field1', 'text')
|
||||||
|
->add('field2', 'text')
|
||||||
|
->getForm()
|
||||||
|
->createView();
|
||||||
|
|
||||||
|
$this->renderWidget($view['field1']);
|
||||||
|
|
||||||
|
// Rest should only contain field2, but isn't rendered
|
||||||
|
$html = $this->renderEnd($view, array('render_rest' => false));
|
||||||
|
|
||||||
|
$this->assertEquals('</form>', $html);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,8 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Form\Tests;
|
namespace Symfony\Component\Form\Tests;
|
||||||
|
|
||||||
use Symfony\Component\Form\Form;
|
use Symfony\Component\Form\Extension\HttpFoundation\RequestFormProcessor;
|
||||||
use Symfony\Component\Form\FormError;
|
use Symfony\Component\Form\FormError;
|
||||||
use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
|
use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
|
||||||
@ -421,14 +420,15 @@ class CompoundFormTest extends AbstractFormTest
|
|||||||
));
|
));
|
||||||
|
|
||||||
$form = $this->getBuilder('author')
|
$form = $this->getBuilder('author')
|
||||||
|
->setMethod($method)
|
||||||
->setCompound(true)
|
->setCompound(true)
|
||||||
->setDataMapper($this->getDataMapper())
|
->setDataMapper($this->getDataMapper())
|
||||||
->addEventSubscriber(new BindRequestListener())
|
->setFormProcessor(new RequestFormProcessor())
|
||||||
->getForm();
|
->getForm();
|
||||||
$form->add($this->getBuilder('name')->getForm());
|
$form->add($this->getBuilder('name')->getForm());
|
||||||
$form->add($this->getBuilder('image')->getForm());
|
$form->add($this->getBuilder('image')->getForm());
|
||||||
|
|
||||||
$form->bind($request);
|
$form->process($request);
|
||||||
|
|
||||||
$file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
|
$file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
|
||||||
|
|
||||||
@ -470,14 +470,15 @@ class CompoundFormTest extends AbstractFormTest
|
|||||||
));
|
));
|
||||||
|
|
||||||
$form = $this->getBuilder('')
|
$form = $this->getBuilder('')
|
||||||
|
->setMethod($method)
|
||||||
->setCompound(true)
|
->setCompound(true)
|
||||||
->setDataMapper($this->getDataMapper())
|
->setDataMapper($this->getDataMapper())
|
||||||
->addEventSubscriber(new BindRequestListener())
|
->setFormProcessor(new RequestFormProcessor())
|
||||||
->getForm();
|
->getForm();
|
||||||
$form->add($this->getBuilder('name')->getForm());
|
$form->add($this->getBuilder('name')->getForm());
|
||||||
$form->add($this->getBuilder('image')->getForm());
|
$form->add($this->getBuilder('image')->getForm());
|
||||||
|
|
||||||
$form->bind($request);
|
$form->process($request);
|
||||||
|
|
||||||
$file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
|
$file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
|
||||||
|
|
||||||
@ -515,10 +516,11 @@ class CompoundFormTest extends AbstractFormTest
|
|||||||
));
|
));
|
||||||
|
|
||||||
$form = $this->getBuilder('image')
|
$form = $this->getBuilder('image')
|
||||||
->addEventSubscriber(new BindRequestListener())
|
->setMethod($method)
|
||||||
|
->setFormProcessor(new RequestFormProcessor())
|
||||||
->getForm();
|
->getForm();
|
||||||
|
|
||||||
$form->bind($request);
|
$form->process($request);
|
||||||
|
|
||||||
$file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
|
$file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
|
||||||
|
|
||||||
@ -548,10 +550,11 @@ class CompoundFormTest extends AbstractFormTest
|
|||||||
));
|
));
|
||||||
|
|
||||||
$form = $this->getBuilder('name')
|
$form = $this->getBuilder('name')
|
||||||
->addEventSubscriber(new BindRequestListener())
|
->setMethod($method)
|
||||||
|
->setFormProcessor(new RequestFormProcessor())
|
||||||
->getForm();
|
->getForm();
|
||||||
|
|
||||||
$form->bind($request);
|
$form->process($request);
|
||||||
|
|
||||||
$this->assertEquals('Bernhard', $form->getData());
|
$this->assertEquals('Bernhard', $form->getData());
|
||||||
|
|
||||||
@ -576,14 +579,15 @@ class CompoundFormTest extends AbstractFormTest
|
|||||||
));
|
));
|
||||||
|
|
||||||
$form = $this->getBuilder('author')
|
$form = $this->getBuilder('author')
|
||||||
|
->setMethod('GET')
|
||||||
->setCompound(true)
|
->setCompound(true)
|
||||||
->setDataMapper($this->getDataMapper())
|
->setDataMapper($this->getDataMapper())
|
||||||
->addEventSubscriber(new BindRequestListener())
|
->setFormProcessor(new RequestFormProcessor())
|
||||||
->getForm();
|
->getForm();
|
||||||
$form->add($this->getBuilder('firstName')->getForm());
|
$form->add($this->getBuilder('firstName')->getForm());
|
||||||
$form->add($this->getBuilder('lastName')->getForm());
|
$form->add($this->getBuilder('lastName')->getForm());
|
||||||
|
|
||||||
$form->bind($request);
|
$form->process($request);
|
||||||
|
|
||||||
$this->assertEquals('Bernhard', $form['firstName']->getData());
|
$this->assertEquals('Bernhard', $form['firstName']->getData());
|
||||||
$this->assertEquals('Schussek', $form['lastName']->getData());
|
$this->assertEquals('Schussek', $form['lastName']->getData());
|
||||||
@ -606,14 +610,15 @@ class CompoundFormTest extends AbstractFormTest
|
|||||||
));
|
));
|
||||||
|
|
||||||
$form = $this->getBuilder('')
|
$form = $this->getBuilder('')
|
||||||
|
->setMethod('GET')
|
||||||
->setCompound(true)
|
->setCompound(true)
|
||||||
->setDataMapper($this->getDataMapper())
|
->setDataMapper($this->getDataMapper())
|
||||||
->addEventSubscriber(new BindRequestListener())
|
->setFormProcessor(new RequestFormProcessor())
|
||||||
->getForm();
|
->getForm();
|
||||||
$form->add($this->getBuilder('firstName')->getForm());
|
$form->add($this->getBuilder('firstName')->getForm());
|
||||||
$form->add($this->getBuilder('lastName')->getForm());
|
$form->add($this->getBuilder('lastName')->getForm());
|
||||||
|
|
||||||
$form->bind($request);
|
$form->process($request);
|
||||||
|
|
||||||
$this->assertEquals('Bernhard', $form['firstName']->getData());
|
$this->assertEquals('Bernhard', $form['firstName']->getData());
|
||||||
$this->assertEquals('Schussek', $form['lastName']->getData());
|
$this->assertEquals('Schussek', $form['lastName']->getData());
|
||||||
|
@ -15,6 +15,7 @@ use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestLis
|
|||||||
use Symfony\Component\Form\Form;
|
use Symfony\Component\Form\Form;
|
||||||
use Symfony\Component\Form\FormConfigBuilder;
|
use Symfony\Component\Form\FormConfigBuilder;
|
||||||
use Symfony\Component\Form\FormEvent;
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\Test\DeprecationErrorHandler;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
|
|
||||||
@ -101,7 +102,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$event = new FormEvent($form, $request);
|
$event = new FormEvent($form, $request);
|
||||||
|
|
||||||
$listener = new BindRequestListener();
|
$listener = new BindRequestListener();
|
||||||
$listener->preBind($event);
|
DeprecationErrorHandler::preBind($listener, $event);
|
||||||
|
|
||||||
$this->assertEquals(array(
|
$this->assertEquals(array(
|
||||||
'name' => 'Bernhard',
|
'name' => 'Bernhard',
|
||||||
@ -128,7 +129,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$event = new FormEvent($form, $request);
|
$event = new FormEvent($form, $request);
|
||||||
|
|
||||||
$listener = new BindRequestListener();
|
$listener = new BindRequestListener();
|
||||||
$listener->preBind($event);
|
DeprecationErrorHandler::preBind($listener, $event);
|
||||||
|
|
||||||
$this->assertEquals(array(
|
$this->assertEquals(array(
|
||||||
'name' => 'Bernhard',
|
'name' => 'Bernhard',
|
||||||
@ -157,7 +158,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$event = new FormEvent($form, $request);
|
$event = new FormEvent($form, $request);
|
||||||
|
|
||||||
$listener = new BindRequestListener();
|
$listener = new BindRequestListener();
|
||||||
$listener->preBind($event);
|
DeprecationErrorHandler::preBind($listener, $event);
|
||||||
|
|
||||||
// Default to empty array
|
// Default to empty array
|
||||||
$this->assertEquals(array(), $event->getData());
|
$this->assertEquals(array(), $event->getData());
|
||||||
@ -183,7 +184,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$event = new FormEvent($form, $request);
|
$event = new FormEvent($form, $request);
|
||||||
|
|
||||||
$listener = new BindRequestListener();
|
$listener = new BindRequestListener();
|
||||||
$listener->preBind($event);
|
DeprecationErrorHandler::preBind($listener, $event);
|
||||||
|
|
||||||
// Default to null
|
// Default to null
|
||||||
$this->assertNull($event->getData());
|
$this->assertNull($event->getData());
|
||||||
@ -206,7 +207,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$event = new FormEvent($form, $request);
|
$event = new FormEvent($form, $request);
|
||||||
|
|
||||||
$listener = new BindRequestListener();
|
$listener = new BindRequestListener();
|
||||||
$listener->preBind($event);
|
DeprecationErrorHandler::preBind($listener, $event);
|
||||||
|
|
||||||
$this->assertEquals(array(
|
$this->assertEquals(array(
|
||||||
'name' => 'Bernhard',
|
'name' => 'Bernhard',
|
||||||
@ -230,7 +231,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$event = new FormEvent($form, $request);
|
$event = new FormEvent($form, $request);
|
||||||
|
|
||||||
$listener = new BindRequestListener();
|
$listener = new BindRequestListener();
|
||||||
$listener->preBind($event);
|
DeprecationErrorHandler::preBind($listener, $event);
|
||||||
|
|
||||||
$this->assertEquals(array(
|
$this->assertEquals(array(
|
||||||
'name' => 'Bernhard',
|
'name' => 'Bernhard',
|
||||||
@ -256,7 +257,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$event = new FormEvent($form, $request);
|
$event = new FormEvent($form, $request);
|
||||||
|
|
||||||
$listener = new BindRequestListener();
|
$listener = new BindRequestListener();
|
||||||
$listener->preBind($event);
|
DeprecationErrorHandler::preBind($listener, $event);
|
||||||
|
|
||||||
$this->assertEquals(array(), $event->getData());
|
$this->assertEquals(array(), $event->getData());
|
||||||
}
|
}
|
||||||
@ -278,7 +279,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$event = new FormEvent($form, $request);
|
$event = new FormEvent($form, $request);
|
||||||
|
|
||||||
$listener = new BindRequestListener();
|
$listener = new BindRequestListener();
|
||||||
$listener->preBind($event);
|
DeprecationErrorHandler::preBind($listener, $event);
|
||||||
|
|
||||||
$this->assertNull($event->getData());
|
$this->assertNull($event->getData());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Form\Tests\Extension\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Extension\HttpFoundation\RequestFormProcessor;
|
||||||
|
use Symfony\Component\Form\Tests\AbstractFormProcessorTest;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class RequestFormProcessorTest extends AbstractFormProcessorTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
|
||||||
|
*/
|
||||||
|
public function testRequestShouldNotBeNull()
|
||||||
|
{
|
||||||
|
$this->processor->processForm($this->getMockForm('name', 'GET'));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
|
||||||
|
*/
|
||||||
|
public function testRequestShouldBeInstanceOfRequest()
|
||||||
|
{
|
||||||
|
$this->processor->processForm($this->getMockForm('name', 'GET'), new \stdClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setRequestData($method, $data, $files = array())
|
||||||
|
{
|
||||||
|
$this->request = Request::create('http://localhost', $method, $data, array(), $files);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFormProcessor()
|
||||||
|
{
|
||||||
|
return new RequestFormProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getMockFile()
|
||||||
|
{
|
||||||
|
return $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
}
|
||||||
|
}
|
@ -12,12 +12,11 @@
|
|||||||
namespace Symfony\Component\Form\Tests;
|
namespace Symfony\Component\Form\Tests;
|
||||||
|
|
||||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Form\FormConfigBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
*/
|
*/
|
||||||
use Symfony\Component\Form\FormConfigBuilder;
|
|
||||||
|
|
||||||
class FormConfigTest extends \PHPUnit_Framework_TestCase
|
class FormConfigTest extends \PHPUnit_Framework_TestCase
|
||||||
{
|
{
|
||||||
public function getHtml4Ids()
|
public function getHtml4Ids()
|
||||||
@ -90,4 +89,59 @@ class FormConfigTest extends \PHPUnit_Framework_TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGetFormProcessorCreatesNativeFormProcessorIfNotSet()
|
||||||
|
{
|
||||||
|
$config = $this->getConfigBuilder()->getFormConfig();
|
||||||
|
|
||||||
|
$this->assertInstanceOf('Symfony\Component\Form\NativeFormProcessor', $config->getFormProcessor());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetFormProcessorReusesNativeFormProcessorInstance()
|
||||||
|
{
|
||||||
|
$config1 = $this->getConfigBuilder()->getFormConfig();
|
||||||
|
$config2 = $this->getConfigBuilder()->getFormConfig();
|
||||||
|
|
||||||
|
$this->assertSame($config1->getFormProcessor(), $config2->getFormProcessor());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetMethodAllowsGet()
|
||||||
|
{
|
||||||
|
$this->getConfigBuilder()->setMethod('GET');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetMethodAllowsPost()
|
||||||
|
{
|
||||||
|
$this->getConfigBuilder()->setMethod('POST');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetMethodAllowsPut()
|
||||||
|
{
|
||||||
|
$this->getConfigBuilder()->setMethod('PUT');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetMethodAllowsDelete()
|
||||||
|
{
|
||||||
|
$this->getConfigBuilder()->setMethod('DELETE');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetMethodAllowsPatch()
|
||||||
|
{
|
||||||
|
$this->getConfigBuilder()->setMethod('PATCH');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Form\Exception\FormException
|
||||||
|
*/
|
||||||
|
public function testSetMethodDoesNotAllowOtherValues()
|
||||||
|
{
|
||||||
|
$this->getConfigBuilder()->setMethod('foo');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getConfigBuilder($name = 'name')
|
||||||
|
{
|
||||||
|
$dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||||
|
|
||||||
|
return new FormConfigBuilder($name, null, $dispatcher);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,15 @@ abstract class FormIntegrationTestCase extends \PHPUnit_Framework_TestCase
|
|||||||
$this->factory = Forms::createFormFactoryBuilder()
|
$this->factory = Forms::createFormFactoryBuilder()
|
||||||
->addExtensions($this->getExtensions())
|
->addExtensions($this->getExtensions())
|
||||||
->getFormFactory();
|
->getFormFactory();
|
||||||
|
|
||||||
|
set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handle'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
$this->factory = null;
|
||||||
|
|
||||||
|
restore_error_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getExtensions()
|
protected function getExtensions()
|
||||||
|
219
src/Symfony/Component/Form/Tests/NativeFormProcessorTest.php
Normal file
219
src/Symfony/Component/Form/Tests/NativeFormProcessorTest.php
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Form\Tests;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\NativeFormProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class NativeFormProcessorTest extends AbstractFormProcessorTest
|
||||||
|
{
|
||||||
|
private static $serverBackup;
|
||||||
|
|
||||||
|
public static function setUpBeforeClass()
|
||||||
|
{
|
||||||
|
self::$serverBackup = $_SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$_GET = array();
|
||||||
|
$_POST = array();
|
||||||
|
$_FILES = array();
|
||||||
|
$_SERVER = array(
|
||||||
|
// PHPUnit needs this entry
|
||||||
|
'SCRIPT_NAME' => self::$serverBackup['SCRIPT_NAME'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
parent::tearDown();
|
||||||
|
|
||||||
|
$_GET = array();
|
||||||
|
$_POST = array();
|
||||||
|
$_FILES = array();
|
||||||
|
$_SERVER = self::$serverBackup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
|
||||||
|
*/
|
||||||
|
public function testRequestShouldBeNull()
|
||||||
|
{
|
||||||
|
$this->processor->processForm($this->getMockForm('name', 'GET'), 'request');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMethodOverrideHeaderTakesPrecedenceIfPost()
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', 'PUT');
|
||||||
|
|
||||||
|
$this->setRequestData('POST', array(
|
||||||
|
'param1' => 'DATA',
|
||||||
|
));
|
||||||
|
|
||||||
|
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT';
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with('DATA');
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testConvertEmptyUploadedFilesToNull()
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', 'POST', false);
|
||||||
|
|
||||||
|
$this->setRequestData('POST', array(), array('param1' => array(
|
||||||
|
'name' => '',
|
||||||
|
'type' => '',
|
||||||
|
'tmp_name' => '',
|
||||||
|
'error' => UPLOAD_ERR_NO_FILE,
|
||||||
|
'size' => 0
|
||||||
|
)));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with($this->identicalTo(null));
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFixBuggyFilesArray()
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', 'POST', false);
|
||||||
|
|
||||||
|
$this->setRequestData('POST', array(), array('param1' => array(
|
||||||
|
'name' => array(
|
||||||
|
'field' => 'upload.txt',
|
||||||
|
),
|
||||||
|
'type' => array(
|
||||||
|
'field' => 'text/plain',
|
||||||
|
),
|
||||||
|
'tmp_name' => array(
|
||||||
|
'field' => 'owfdskjasdfsa',
|
||||||
|
),
|
||||||
|
'error' => array(
|
||||||
|
'field' => UPLOAD_ERR_OK,
|
||||||
|
),
|
||||||
|
'size' => array(
|
||||||
|
'field' => 100,
|
||||||
|
),
|
||||||
|
)));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with(array(
|
||||||
|
'field' => array(
|
||||||
|
'name' => 'upload.txt',
|
||||||
|
'type' => 'text/plain',
|
||||||
|
'tmp_name' => 'owfdskjasdfsa',
|
||||||
|
'error' => UPLOAD_ERR_OK,
|
||||||
|
'size' => 100,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFixBuggyNestedFilesArray()
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', 'POST');
|
||||||
|
|
||||||
|
$this->setRequestData('POST', array(), array('param1' => array(
|
||||||
|
'name' => array(
|
||||||
|
'field' => array('subfield' => 'upload.txt'),
|
||||||
|
),
|
||||||
|
'type' => array(
|
||||||
|
'field' => array('subfield' => 'text/plain'),
|
||||||
|
),
|
||||||
|
'tmp_name' => array(
|
||||||
|
'field' => array('subfield' => 'owfdskjasdfsa'),
|
||||||
|
),
|
||||||
|
'error' => array(
|
||||||
|
'field' => array('subfield' => UPLOAD_ERR_OK),
|
||||||
|
),
|
||||||
|
'size' => array(
|
||||||
|
'field' => array('subfield' => 100),
|
||||||
|
),
|
||||||
|
)));
|
||||||
|
|
||||||
|
$form->expects($this->once())
|
||||||
|
->method('bind')
|
||||||
|
->with(array(
|
||||||
|
'field' => array(
|
||||||
|
'subfield' => array(
|
||||||
|
'name' => 'upload.txt',
|
||||||
|
'type' => 'text/plain',
|
||||||
|
'tmp_name' => 'owfdskjasdfsa',
|
||||||
|
'error' => UPLOAD_ERR_OK,
|
||||||
|
'size' => 100,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMethodOverrideHeaderIgnoredIfNotPost()
|
||||||
|
{
|
||||||
|
$form = $this->getMockForm('param1', 'POST');
|
||||||
|
|
||||||
|
$this->setRequestData('GET', array(
|
||||||
|
'param1' => 'DATA',
|
||||||
|
));
|
||||||
|
|
||||||
|
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT';
|
||||||
|
|
||||||
|
$form->expects($this->never())
|
||||||
|
->method('bind');
|
||||||
|
|
||||||
|
$this->processor->processForm($form, $this->request);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setRequestData($method, $data, $files = array())
|
||||||
|
{
|
||||||
|
if ('GET' === $method) {
|
||||||
|
$_GET = $data;
|
||||||
|
$_FILES = array();
|
||||||
|
} else {
|
||||||
|
$_POST = $data;
|
||||||
|
$_FILES = $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SERVER = array(
|
||||||
|
'REQUEST_METHOD' => $method,
|
||||||
|
// PHPUnit needs this entry
|
||||||
|
'SCRIPT_NAME' => self::$serverBackup['SCRIPT_NAME'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFormProcessor()
|
||||||
|
{
|
||||||
|
return new NativeFormProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getMockFile()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'name' => 'upload.txt',
|
||||||
|
'type' => 'text/plain',
|
||||||
|
'tmp_name' => 'owfdskjasdfsa',
|
||||||
|
'error' => UPLOAD_ERR_OK,
|
||||||
|
'size' => 100,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -275,12 +275,9 @@ class SimpleFormTest extends AbstractFormTest
|
|||||||
$this->assertTrue($form->isValid());
|
$this->assertTrue($form->isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException \LogicException
|
|
||||||
*/
|
|
||||||
public function testNotValidIfNotBound()
|
public function testNotValidIfNotBound()
|
||||||
{
|
{
|
||||||
$this->form->isValid();
|
$this->assertFalse($this->form->isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNotValidIfErrors()
|
public function testNotValidIfErrors()
|
||||||
@ -845,6 +842,21 @@ class SimpleFormTest extends AbstractFormTest
|
|||||||
$parent->bind('not-an-array');
|
$parent->bind('not-an-array');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testProcessForwardsToFormProcessor()
|
||||||
|
{
|
||||||
|
$processor = $this->getMock('Symfony\Component\Form\FormProcessorInterface');
|
||||||
|
|
||||||
|
$form = $this->getBuilder()
|
||||||
|
->setFormProcessor($processor)
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$processor->expects($this->once())
|
||||||
|
->method('processForm')
|
||||||
|
->with($this->identicalTo($form), 'REQUEST');
|
||||||
|
|
||||||
|
$this->assertSame($form, $form->process('REQUEST'));
|
||||||
|
}
|
||||||
|
|
||||||
protected function createForm()
|
protected function createForm()
|
||||||
{
|
{
|
||||||
return $this->getBuilder()->getForm();
|
return $this->getBuilder()->getForm();
|
||||||
|
Reference in New Issue
Block a user