Skip to content

Commit

Permalink
[Form] Simplified Form::bind(), added convenience methods Form::bindR…
Browse files Browse the repository at this point in the history
…equest() and Form::bindGlobals()
  • Loading branch information
Bernhard Schussek committed Feb 1, 2011
1 parent 57cbd57 commit 4fcb985
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 46 deletions.
69 changes: 35 additions & 34 deletions src/Symfony/Component/Form/Form.php
Expand Up @@ -11,6 +11,8 @@

namespace Symfony\Component\Form;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\FileBag;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface;
Expand All @@ -20,11 +22,11 @@
*
* A form is composed of a validator schema and a widget form schema.
*
* Form also takes care of Csrf protection by default.
* Form also takes care of CSRF protection by default.
*
* A Csrf secret can be any random string. If set to false, it disables the
* Csrf protection, and if set to null, it forces the form to use the global
* Csrf secret. If the global Csrf secret is also null, then a random one
* A CSRF secret can be any random string. If set to false, it disables the
* CSRF protection, and if set to null, it forces the form to use the global
* CSRF secret. If the global CSRF secret is also null, then a random one
* is generated on the fly.
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
Expand Down Expand Up @@ -141,32 +143,42 @@ public function getCsrfProvider()
}

/**
* Binds the form with values and files.
* Binds the form with submitted data from a Request object
*
* This method is final because it is very easy to break a form when
* overriding this method and adding logic that depends on $taintedFiles.
* You should override doBind() instead where the uploaded files are
* already merged into the data array.
* @param Request $request The request object
* @see bind()
*/
public function bindRequest(Request $request)
{
$values = $request->request->get($this->getName());
$files = $request->files->get($this->getName());

$this->bind(self::deepArrayUnion($values, $files));
}

/**
* Binds the form with submitted data from the PHP globals $_POST and
* $_FILES
*
* @param array $taintedValues The form data of the $_POST array
* @param array $taintedFiles An array of uploaded files
* @return Boolean Whether the form is valid
* @see bind()
*/
final public function bind($taintedValues, array $taintedFiles = null)
public function bindGlobals()
{
if (null === $taintedFiles) {
if ($this->isMultipart() && $this->getParent() === null) {
throw new \InvalidArgumentException('You must provide a files array for multipart forms');
}
$values = $_POST[$this->getName()];

$taintedFiles = array();
}
// fix files array and convert to UploadedFile instances
$fileBag = new FileBag($_FILES);
$files = $fileBag->get($this->getName());

if (null === $taintedValues) {
$taintedValues = array();
}
$this->bind(self::deepArrayUnion($values, $files));
}

$this->doBind(self::deepArrayUnion($taintedValues, $taintedFiles));
/**
* {@inheritDoc}
*/
public function bind($values)
{
parent::bind($values);

if ($this->getParent() === null) {
if ($this->validator === null) {
Expand All @@ -192,17 +204,6 @@ final public function bind($taintedValues, array $taintedFiles = null)
}
}

/**
* Binds the form with the given data.
*
* @param array $taintedData The data to bind to the form
* @return Boolean Whether the form is valid
*/
protected function doBind(array $taintedData)
{
parent::bind($taintedData);
}

/**
* @return true if this form is CSRF protected
*/
Expand Down
75 changes: 63 additions & 12 deletions tests/Symfony/Tests/Component/Form/FormTest.php
Expand Up @@ -20,6 +20,8 @@
use Symfony\Component\Form\HiddenField;
use Symfony\Component\Form\FieldGroup;
use Symfony\Component\Form\PropertyPath;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Tests\Component\Form\Fixtures\Author;
Expand Down Expand Up @@ -222,26 +224,75 @@ public function testBindThrowsExceptionIfNoValidatorIsSet()
$form->bind(array()); // irrelevant
}

public function testMultipartFormsWithoutParentsRequireFiles()
public function testBindRequest()
{
$form = new Form('author', new Author(), $this->validator);
$form->add($this->createMultipartMockField('file'));
$values = array(
'author' => array(
'name' => 'Bernhard',
'image' => array('filename' => 'foobar.png'),
),
);
$files = array(
'author' => array(
'error' => array('image' => array('file' => UPLOAD_ERR_OK)),
'name' => array('image' => array('file' => 'upload.png')),
'size' => array('image' => array('file' => 123)),
'tmp_name' => array('image' => array('file' => 'abcdef.png')),
'type' => array('image' => array('file' => 'image/png')),
),
);

$request = new Request(array(), $values, array(), array(), $files);

$form = new Form('author', null, $this->createMockValidator());
$form->add(new TestField('name'));
$imageForm = new FieldGroup('image');
$imageForm->add(new TestField('file'));
$imageForm->add(new TestField('filename'));
$form->add($imageForm);

$form->bindRequest($request);

$this->setExpectedException('InvalidArgumentException');
$file = new UploadedFile('abcdef.png', 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);

// should be given in second argument
$form->bind(array('file' => 'test.txt'));
$this->assertEquals('Bernhard', $form['name']->getData());
$this->assertEquals('foobar.png', $form['image']['filename']->getData());
$this->assertEquals($file, $form['image']['file']->getData());
}

public function testMultipartFormsWithParentsRequireNoFiles()
public function testBindGlobals()
{
$form = new Form('author', new Author(), $this->validator);
$form->add($this->createMultipartMockField('file'));
$_POST = array(
'author' => array(
'name' => 'Bernhard',
'image' => array('filename' => 'foobar.png'),
),
);
$_FILES = array(
'author' => array(
'error' => array('image' => array('file' => UPLOAD_ERR_OK)),
'name' => array('image' => array('file' => 'upload.png')),
'size' => array('image' => array('file' => 123)),
'tmp_name' => array('image' => array('file' => 'abcdef.png')),
'type' => array('image' => array('file' => 'image/png')),
),
);


$form = new Form('author', null, $this->createMockValidator());
$form->add(new TestField('name'));
$imageForm = new FieldGroup('image');
$imageForm->add(new TestField('file'));
$imageForm->add(new TestField('filename'));
$form->add($imageForm);

$form->bindGlobals();

$form->setParent($this->createMockField('group'));
$file = new UploadedFile('abcdef.png', 'upload.png', 'image/png', 123, UPLOAD_ERR_OK);

// files are expected to be converted by the parent
$form->bind(array('file' => 'test.txt'));
$this->assertEquals('Bernhard', $form['name']->getData());
$this->assertEquals('foobar.png', $form['image']['filename']->getData());
$this->assertEquals($file, $form['image']['file']->getData());
}

public function testUpdateFromPropertyIsIgnoredIfFormHasObject()
Expand Down

0 comments on commit 4fcb985

Please sign in to comment.