merged branch bschussek/issue5493 (PR #6522)
This PR was merged into the master branch. Discussion ---------- [2.3] [Form] Implemented form processors Bug fix: no Feature addition: yes Backwards compatibility break: no Symfony2 tests pass: yes Fixes the following tickets: partially #5493 Todo: - License of the code: MIT Documentation PR: symfony/symfony-docs#2092 Commits -------11fee06
[TwigBridge] Removed duplicate entries from the CHANGELOG68f360c
[Form] Moved upgrade nodes to UPGRADE-3.001b71a4
[Form] Removed trigger_error() for deprecations as of 3.081f8c67
[Form] Implemented form processors0ea75db
[Form] Improved FormRenderer::renderBlock() to be usable outside of form blocks
This commit is contained in:
commit
fcd941c033
|
@ -1,4 +1,4 @@
|
|||
UPGRADE FROM 2.2 to 2.3
|
||||
UPGRADE FROM 2.2 to 2.3
|
||||
=======================
|
||||
|
||||
### Form
|
||||
|
|
141
UPGRADE-3.0.md
141
UPGRADE-3.0.md
|
@ -18,6 +18,97 @@ UPGRADE FROM 2.x to 3.0
|
|||
`DebugClassLoader`. The difference is that the constructor now takes a
|
||||
loader to wrap.
|
||||
|
||||
### Form
|
||||
|
||||
* Passing a `Symfony\Component\HttpFoundation\Request` instance to
|
||||
`FormInterface::bind()` was disabled. You should use
|
||||
`FormInterface::process()` instead.
|
||||
|
||||
Before:
|
||||
|
||||
```
|
||||
if ('POST' === $request->getMethod()) {
|
||||
$form->bind($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
if ($form->process($request)->isValid()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
If you want to test whether the form was submitted separately, you can use
|
||||
the method `isBound()`:
|
||||
|
||||
```
|
||||
if ($form->process($request)->isBound()) {
|
||||
// ...
|
||||
|
||||
if ($form->isValid()) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### FrameworkBundle
|
||||
|
||||
* The `enctype` method of the `form` helper was removed. You should use the
|
||||
new method `start` instead.
|
||||
|
||||
Before:
|
||||
|
||||
```
|
||||
<form method="post" action="http://example.com" <?php echo $view['form']->enctype($form) ?>>
|
||||
...
|
||||
</form>
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
<?php echo $view['form']->start($form) ?>
|
||||
...
|
||||
<?php echo $view['form']->end($form) ?>
|
||||
```
|
||||
|
||||
The method and action of the form default to "POST" and the current
|
||||
document. If you want to change these values, you can set them explicitly in
|
||||
the controller.
|
||||
|
||||
Alternative 1:
|
||||
|
||||
```
|
||||
$form = $this->createForm('my_form', $formData, array(
|
||||
'method' => 'PUT',
|
||||
'action' => $this->generateUrl('target_route'),
|
||||
));
|
||||
```
|
||||
|
||||
Alternative 2:
|
||||
|
||||
```
|
||||
$form = $this->createFormBuilder($formData)
|
||||
// ...
|
||||
->setMethod('PUT')
|
||||
->setAction($this->generateUrl('target_route'))
|
||||
->getForm();
|
||||
```
|
||||
|
||||
It is also possible to override the method and the action in the template:
|
||||
|
||||
```
|
||||
<?php echo $view['form']->start($form, array('method' => 'GET', 'action' => 'http://example.com')) ?>
|
||||
...
|
||||
<?php echo $view['form']->end($form) ?>
|
||||
```
|
||||
|
||||
### HttpKernel
|
||||
|
||||
* The `Symfony\Component\HttpKernel\Log\LoggerInterface` has been removed in
|
||||
|
@ -98,6 +189,56 @@ UPGRADE FROM 2.x to 3.0
|
|||
|
||||
* The `render` tag is deprecated in favor of the `render` function.
|
||||
|
||||
* The `form_enctype` helper was removed. You should use the new `form_start`
|
||||
function instead.
|
||||
|
||||
Before:
|
||||
|
||||
```
|
||||
<form method="post" action="http://example.com" {{ form_enctype(form) }}>
|
||||
...
|
||||
</form>
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
{{ form_start(form) }}
|
||||
...
|
||||
{{ form_end(form) }}
|
||||
```
|
||||
|
||||
The method and action of the form default to "POST" and the current
|
||||
document. If you want to change these values, you can set them explicitly in
|
||||
the controller.
|
||||
|
||||
Alternative 1:
|
||||
|
||||
```
|
||||
$form = $this->createForm('my_form', $formData, array(
|
||||
'method' => 'PUT',
|
||||
'action' => $this->generateUrl('target_route'),
|
||||
));
|
||||
```
|
||||
|
||||
Alternative 2:
|
||||
|
||||
```
|
||||
$form = $this->createFormBuilder($formData)
|
||||
// ...
|
||||
->setMethod('PUT')
|
||||
->setAction($this->generateUrl('target_route'))
|
||||
->getForm();
|
||||
```
|
||||
|
||||
It is also possible to override the method and the action in the template:
|
||||
|
||||
```
|
||||
{{ form_start(form, {'method': 'GET', 'action': 'http://example.com'}) }}
|
||||
...
|
||||
{{ form_end(form) }}
|
||||
```
|
||||
|
||||
### Yaml
|
||||
|
||||
* The ability to pass file names to `Yaml::parse()` has been removed.
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
CHANGELOG
|
||||
=========
|
||||
|
||||
2.3.0
|
||||
-----
|
||||
|
||||
* added helpers form(), form_start() and form_end()
|
||||
* deprecated form_enctype() in favor of form_start()
|
||||
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
|
|
|
@ -61,12 +61,14 @@ class FormExtension extends \Twig_Extension
|
|||
public function getFunctions()
|
||||
{
|
||||
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_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_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_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'),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?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");
|
||||
|
||||
// Uncomment this as soon as the deprecation note should be shown
|
||||
// $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)');
|
||||
}
|
||||
}
|
|
@ -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 #}
|
||||
|
||||
{% 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 %}
|
||||
{% spaceless %}
|
||||
{% if multipart %}enctype="multipart/form-data"{% endif %}
|
||||
|
|
|
@ -139,6 +139,11 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest
|
|||
$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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
$this->extension->renderer->setTheme($view, $themes);
|
||||
|
|
|
@ -75,6 +75,11 @@ class FormExtensionTableLayoutTest extends AbstractTableLayoutTest
|
|||
$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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
$this->extension->renderer->setTheme($view, $themes);
|
||||
|
|
|
@ -10,6 +10,9 @@ CHANGELOG
|
|||
* added `TimedPhpEngine`
|
||||
* added `--clean` option the the `translation:update` command
|
||||
* 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
|
||||
-----
|
||||
|
@ -27,10 +30,10 @@ CHANGELOG
|
|||
* replaced Symfony\Bundle\FrameworkBundle\Controller\TraceableControllerResolver by Symfony\Component\HttpKernel\Controller\TraceableControllerResolver
|
||||
* replaced Symfony\Component\HttpKernel\Debug\ContainerAwareTraceableEventDispatcher by Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher
|
||||
* 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
|
||||
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
|
||||
-----
|
||||
|
|
|
@ -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,88 @@ class FormHelper extends Helper
|
|||
$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.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
// Uncomment this as soon as the deprecation note should be shown
|
||||
// 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');
|
||||
}
|
||||
|
||||
|
@ -78,13 +147,13 @@ class FormHelper extends Helper
|
|||
*
|
||||
* Example usage:
|
||||
*
|
||||
* <?php echo view['form']->widget() ?>
|
||||
* <?php echo view['form']->widget($form) ?>
|
||||
*
|
||||
* 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 array $variables Additional variables passed to the template
|
||||
|
|
|
@ -72,6 +72,11 @@ class FormHelperDivLayoutTest extends AbstractDivLayoutTest
|
|||
parent::tearDown();
|
||||
}
|
||||
|
||||
protected function renderForm(FormView $view, array $vars = array())
|
||||
{
|
||||
return (string) $this->engine->get('form')->form($view, $vars);
|
||||
}
|
||||
|
||||
protected function renderEnctype(FormView $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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
$this->engine->get('form')->setTheme($view, $themes);
|
||||
|
|
|
@ -73,6 +73,11 @@ class FormHelperTableLayoutTest extends AbstractTableLayoutTest
|
|||
parent::tearDown();
|
||||
}
|
||||
|
||||
protected function renderForm(FormView $view, array $vars = array())
|
||||
{
|
||||
return (string) $this->engine->get('form')->form($view, $vars);
|
||||
}
|
||||
|
||||
protected function renderEnctype(FormView $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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
$this->engine->get('form')->setTheme($view, $themes);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
namespace Symfony\Component\Form;
|
||||
|
||||
use Symfony\Component\Form\Exception\AlreadyBoundException;
|
||||
use Symfony\Component\Form\Exception\BadMethodCallException;
|
||||
|
||||
/**
|
||||
* A form button.
|
||||
|
@ -342,6 +343,18 @@ class Button implements \IteratorAggregate, FormInterface
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -456,6 +456,42 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
|
|||
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.
|
||||
*
|
||||
|
@ -693,6 +729,36 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -6,6 +6,9 @@ CHANGELOG
|
|||
------
|
||||
|
||||
* 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
|
||||
-----
|
||||
|
|
|
@ -53,6 +53,8 @@ class FormType extends BaseType
|
|||
->setData(isset($options['data']) ? $options['data'] : null)
|
||||
->setDataLocked(isset($options['data']))
|
||||
->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null)
|
||||
->setMethod($options['method'])
|
||||
->setAction($options['action'])
|
||||
;
|
||||
|
||||
if ($options['trim']) {
|
||||
|
@ -93,6 +95,8 @@ class FormType extends BaseType
|
|||
'size' => null,
|
||||
'label_attr' => $options['label_attr'],
|
||||
'compound' => $form->getConfig()->getCompound(),
|
||||
'method' => $form->getConfig()->getMethod(),
|
||||
'action' => $form->getConfig()->getAction(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -167,6 +171,10 @@ class FormType extends BaseType
|
|||
'label_attr' => array(),
|
||||
'virtual' => false,
|
||||
'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(
|
||||
|
|
|
@ -19,6 +19,9 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
|
||||
/**
|
||||
* @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
|
||||
{
|
||||
|
@ -40,6 +43,9 @@ class BindRequestListener implements EventSubscriberInterface
|
|||
return;
|
||||
}
|
||||
|
||||
// Uncomment this as soon as the deprecation note should be shown
|
||||
// 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();
|
||||
$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\Extension\HttpFoundation\EventListener\BindRequestListener;
|
||||
use Symfony\Component\Form\Extension\HttpFoundation\RequestFormProcessor;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
/**
|
||||
|
@ -25,9 +26,15 @@ class FormTypeHttpFoundationExtension extends AbstractTypeExtension
|
|||
*/
|
||||
private $listener;
|
||||
|
||||
/**
|
||||
* @var RequestFormProcessor
|
||||
*/
|
||||
private $processor;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->listener = new BindRequestListener();
|
||||
$this->processor = new RequestFormProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,6 +43,7 @@ class FormTypeHttpFoundationExtension extends AbstractTypeExtension
|
|||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->addEventSubscriber($this->listener);
|
||||
$builder->setFormProcessor($this->processor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -404,6 +404,16 @@ class Form implements \IteratorAggregate, FormInterface
|
|||
return $this->extraData;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function process($request = null)
|
||||
{
|
||||
$this->config->getFormProcessor()->processForm($this, $request);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -579,7 +589,7 @@ class Form implements \IteratorAggregate, FormInterface
|
|||
public function isValid()
|
||||
{
|
||||
if (!$this->bound) {
|
||||
throw new \LogicException('You cannot call isValid() on a form that is not bound.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($this->errors) > 0) {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
namespace Symfony\Component\Form;
|
||||
|
||||
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\PropertyAccess\PropertyPath;
|
||||
use Symfony\Component\PropertyAccess\PropertyPathInterface;
|
||||
|
@ -27,6 +27,26 @@ use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
@ -137,6 +157,21 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||
*/
|
||||
private $formFactory;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $action;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $method = 'POST';
|
||||
|
||||
/**
|
||||
* @var FormProcessorInterface
|
||||
*/
|
||||
private $formProcessor;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
|
@ -264,6 +299,10 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||
*/
|
||||
public function getEventDispatcher()
|
||||
{
|
||||
if ($this->locked && !$this->dispatcher instanceof ImmutableEventDispatcher) {
|
||||
$this->dispatcher = new ImmutableEventDispatcher($this->dispatcher);
|
||||
}
|
||||
|
||||
return $this->dispatcher;
|
||||
}
|
||||
|
||||
|
@ -435,6 +474,37 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||
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}
|
||||
*/
|
||||
|
@ -687,6 +757,58 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||
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}
|
||||
*/
|
||||
|
@ -700,10 +822,6 @@ class FormConfigBuilder implements FormConfigBuilderInterface
|
|||
$config = clone $this;
|
||||
$config->locked = true;
|
||||
|
||||
if (!$config->dispatcher instanceof ImmutableEventDispatcher) {
|
||||
$config->dispatcher = new ImmutableEventDispatcher($config->dispatcher);
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
|
|
@ -237,6 +237,31 @@ interface FormConfigBuilderInterface extends FormConfigInterface
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -190,6 +190,25 @@ interface FormConfigInterface
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -182,6 +182,8 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
|
|||
/**
|
||||
* Returns whether the form and all children are valid.
|
||||
*
|
||||
* If the form is not bound, this method always returns false.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isValid();
|
||||
|
@ -224,6 +226,19 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -87,19 +87,31 @@ class FormRenderer implements FormRendererInterface
|
|||
*/
|
||||
public function renderBlock(FormView $view, $blockName, array $variables = array())
|
||||
{
|
||||
if (0 == count($this->variableStack)) {
|
||||
throw new Exception('This method should only be called while rendering a form element.');
|
||||
}
|
||||
|
||||
$viewCacheKey = $view->vars[self::CACHE_KEY_VAR];
|
||||
$scopeVariables = end($this->variableStack[$viewCacheKey]);
|
||||
|
||||
$resource = $this->engine->getResourceForBlockName($view, $blockName);
|
||||
|
||||
if (!$resource) {
|
||||
throw new Exception(sprintf('No block "%s" found while rendering the form.', $blockName));
|
||||
}
|
||||
|
||||
$viewCacheKey = $view->vars[self::CACHE_KEY_VAR];
|
||||
|
||||
// The variables are cached globally for a view (instead of for the
|
||||
// current suffix)
|
||||
if (!isset($this->variableStack[$viewCacheKey])) {
|
||||
$this->variableStack[$viewCacheKey] = array();
|
||||
|
||||
// The default variable scope contains all view variables, merged with
|
||||
// the variables passed explicitly to the helper
|
||||
$scopeVariables = $view->vars;
|
||||
|
||||
$varInit = true;
|
||||
} else {
|
||||
// Reuse the current scope and merge it with the explicitly passed variables
|
||||
$scopeVariables = end($this->variableStack[$viewCacheKey]);
|
||||
|
||||
$varInit = false;
|
||||
}
|
||||
|
||||
// Merge the passed with the existing attributes
|
||||
if (isset($variables['attr']) && isset($scopeVariables['attr'])) {
|
||||
$variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']);
|
||||
|
@ -122,6 +134,10 @@ class FormRenderer implements FormRendererInterface
|
|||
// Clear the stack
|
||||
array_pop($this->variableStack[$viewCacheKey]);
|
||||
|
||||
if ($varInit) {
|
||||
unset($this->variableStack[$viewCacheKey]);
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
@ -191,6 +207,8 @@ class FormRenderer implements FormRendererInterface
|
|||
// The variables are cached globally for a view (instead of for the
|
||||
// current suffix)
|
||||
if (!isset($this->variableStack[$viewCacheKey])) {
|
||||
$this->variableStack[$viewCacheKey] = array();
|
||||
|
||||
// The default variable scope contains all view variables, merged with
|
||||
// the variables passed explicitly to the helper
|
||||
$scopeVariables = $view->vars;
|
||||
|
|
|
@ -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;
|
||||
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
|
||||
class DeprecationErrorHandler
|
||||
{
|
||||
public static function handle($errorNumber, $message, $file, $line, $context)
|
||||
|
@ -21,4 +23,11 @@ class DeprecationErrorHandler
|
|||
|
||||
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()
|
||||
{
|
||||
$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')
|
||||
->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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 $factory;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
if (!extension_loaded('intl')) {
|
||||
|
@ -44,7 +42,6 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
|
|||
protected function tearDown()
|
||||
{
|
||||
$this->csrfProvider = null;
|
||||
$this->factory = null;
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
@ -102,6 +99,8 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
|
|||
$this->assertMatchesXpath($html, $xpath);
|
||||
}
|
||||
|
||||
abstract protected function renderForm(FormView $view, array $vars = array());
|
||||
|
||||
abstract protected function renderEnctype(FormView $view);
|
||||
|
||||
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 renderStart(FormView $view, array $vars = array());
|
||||
|
||||
abstract protected function renderEnd(FormView $view, array $vars = array());
|
||||
|
||||
abstract protected function setTheme(FormView $view, array $themes);
|
||||
|
||||
public function testEnctype()
|
||||
|
@ -1744,9 +1747,7 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase
|
|||
$this->assertMatchesXpath($html,
|
||||
'//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"]'
|
||||
);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
$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')
|
||||
->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;
|
||||
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\Extension\HttpFoundation\RequestFormProcessor;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
|
||||
|
@ -421,14 +420,15 @@ class CompoundFormTest extends AbstractFormTest
|
|||
));
|
||||
|
||||
$form = $this->getBuilder('author')
|
||||
->setMethod($method)
|
||||
->setCompound(true)
|
||||
->setDataMapper($this->getDataMapper())
|
||||
->addEventSubscriber(new BindRequestListener())
|
||||
->setFormProcessor(new RequestFormProcessor())
|
||||
->getForm();
|
||||
$form->add($this->getBuilder('name')->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);
|
||||
|
||||
|
@ -470,14 +470,15 @@ class CompoundFormTest extends AbstractFormTest
|
|||
));
|
||||
|
||||
$form = $this->getBuilder('')
|
||||
->setMethod($method)
|
||||
->setCompound(true)
|
||||
->setDataMapper($this->getDataMapper())
|
||||
->addEventSubscriber(new BindRequestListener())
|
||||
->setFormProcessor(new RequestFormProcessor())
|
||||
->getForm();
|
||||
$form->add($this->getBuilder('name')->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);
|
||||
|
||||
|
@ -515,10 +516,11 @@ class CompoundFormTest extends AbstractFormTest
|
|||
));
|
||||
|
||||
$form = $this->getBuilder('image')
|
||||
->addEventSubscriber(new BindRequestListener())
|
||||
->setMethod($method)
|
||||
->setFormProcessor(new RequestFormProcessor())
|
||||
->getForm();
|
||||
|
||||
$form->bind($request);
|
||||
$form->process($request);
|
||||
|
||||
$file = new UploadedFile($path, 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);
|
||||
|
||||
|
@ -548,10 +550,11 @@ class CompoundFormTest extends AbstractFormTest
|
|||
));
|
||||
|
||||
$form = $this->getBuilder('name')
|
||||
->addEventSubscriber(new BindRequestListener())
|
||||
->setMethod($method)
|
||||
->setFormProcessor(new RequestFormProcessor())
|
||||
->getForm();
|
||||
|
||||
$form->bind($request);
|
||||
$form->process($request);
|
||||
|
||||
$this->assertEquals('Bernhard', $form->getData());
|
||||
|
||||
|
@ -576,14 +579,15 @@ class CompoundFormTest extends AbstractFormTest
|
|||
));
|
||||
|
||||
$form = $this->getBuilder('author')
|
||||
->setMethod('GET')
|
||||
->setCompound(true)
|
||||
->setDataMapper($this->getDataMapper())
|
||||
->addEventSubscriber(new BindRequestListener())
|
||||
->setFormProcessor(new RequestFormProcessor())
|
||||
->getForm();
|
||||
$form->add($this->getBuilder('firstName')->getForm());
|
||||
$form->add($this->getBuilder('lastName')->getForm());
|
||||
|
||||
$form->bind($request);
|
||||
$form->process($request);
|
||||
|
||||
$this->assertEquals('Bernhard', $form['firstName']->getData());
|
||||
$this->assertEquals('Schussek', $form['lastName']->getData());
|
||||
|
@ -606,14 +610,15 @@ class CompoundFormTest extends AbstractFormTest
|
|||
));
|
||||
|
||||
$form = $this->getBuilder('')
|
||||
->setMethod('GET')
|
||||
->setCompound(true)
|
||||
->setDataMapper($this->getDataMapper())
|
||||
->addEventSubscriber(new BindRequestListener())
|
||||
->setFormProcessor(new RequestFormProcessor())
|
||||
->getForm();
|
||||
$form->add($this->getBuilder('firstName')->getForm());
|
||||
$form->add($this->getBuilder('lastName')->getForm());
|
||||
|
||||
$form->bind($request);
|
||||
$form->process($request);
|
||||
|
||||
$this->assertEquals('Bernhard', $form['firstName']->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\FormConfigBuilder;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\Test\DeprecationErrorHandler;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
|
@ -101,7 +102,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$event = new FormEvent($form, $request);
|
||||
|
||||
$listener = new BindRequestListener();
|
||||
$listener->preBind($event);
|
||||
DeprecationErrorHandler::preBind($listener, $event);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'name' => 'Bernhard',
|
||||
|
@ -128,7 +129,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$event = new FormEvent($form, $request);
|
||||
|
||||
$listener = new BindRequestListener();
|
||||
$listener->preBind($event);
|
||||
DeprecationErrorHandler::preBind($listener, $event);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'name' => 'Bernhard',
|
||||
|
@ -157,7 +158,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$event = new FormEvent($form, $request);
|
||||
|
||||
$listener = new BindRequestListener();
|
||||
$listener->preBind($event);
|
||||
DeprecationErrorHandler::preBind($listener, $event);
|
||||
|
||||
// Default to empty array
|
||||
$this->assertEquals(array(), $event->getData());
|
||||
|
@ -183,7 +184,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$event = new FormEvent($form, $request);
|
||||
|
||||
$listener = new BindRequestListener();
|
||||
$listener->preBind($event);
|
||||
DeprecationErrorHandler::preBind($listener, $event);
|
||||
|
||||
// Default to null
|
||||
$this->assertNull($event->getData());
|
||||
|
@ -206,7 +207,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$event = new FormEvent($form, $request);
|
||||
|
||||
$listener = new BindRequestListener();
|
||||
$listener->preBind($event);
|
||||
DeprecationErrorHandler::preBind($listener, $event);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'name' => 'Bernhard',
|
||||
|
@ -230,7 +231,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$event = new FormEvent($form, $request);
|
||||
|
||||
$listener = new BindRequestListener();
|
||||
$listener->preBind($event);
|
||||
DeprecationErrorHandler::preBind($listener, $event);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'name' => 'Bernhard',
|
||||
|
@ -256,7 +257,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$event = new FormEvent($form, $request);
|
||||
|
||||
$listener = new BindRequestListener();
|
||||
$listener->preBind($event);
|
||||
DeprecationErrorHandler::preBind($listener, $event);
|
||||
|
||||
$this->assertEquals(array(), $event->getData());
|
||||
}
|
||||
|
@ -278,7 +279,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$event = new FormEvent($form, $request);
|
||||
|
||||
$listener = new BindRequestListener();
|
||||
$listener->preBind($event);
|
||||
DeprecationErrorHandler::preBind($listener, $event);
|
||||
|
||||
$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;
|
||||
|
||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||
use Symfony\Component\Form\FormConfigBuilder;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
use Symfony\Component\Form\FormConfigBuilder;
|
||||
|
||||
class FormConfigTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testNotValidIfNotBound()
|
||||
{
|
||||
$this->form->isValid();
|
||||
$this->assertFalse($this->form->isValid());
|
||||
}
|
||||
|
||||
public function testNotValidIfErrors()
|
||||
|
@ -845,6 +842,21 @@ class SimpleFormTest extends AbstractFormTest
|
|||
$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()
|
||||
{
|
||||
return $this->getBuilder()->getForm();
|
||||
|
|
Reference in New Issue