Skip to content

Commit 4fcb985

Browse files
author
Bernhard Schussek
committed
[Form] Simplified Form::bind(), added convenience methods Form::bindRequest() and Form::bindGlobals()
1 parent 57cbd57 commit 4fcb985

File tree

2 files changed

+98
-46
lines changed

2 files changed

+98
-46
lines changed

src/Symfony/Component/Form/Form.php

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Form;
1313

14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\FileBag;
1416
use Symfony\Component\Validator\ValidatorInterface;
1517
use Symfony\Component\Form\Exception\FormException;
1618
use Symfony\Component\Form\CsrfProvider\CsrfProviderInterface;
@@ -20,11 +22,11 @@
2022
*
2123
* A form is composed of a validator schema and a widget form schema.
2224
*
23-
* Form also takes care of Csrf protection by default.
25+
* Form also takes care of CSRF protection by default.
2426
*
25-
* A Csrf secret can be any random string. If set to false, it disables the
26-
* Csrf protection, and if set to null, it forces the form to use the global
27-
* Csrf secret. If the global Csrf secret is also null, then a random one
27+
* A CSRF secret can be any random string. If set to false, it disables the
28+
* CSRF protection, and if set to null, it forces the form to use the global
29+
* CSRF secret. If the global CSRF secret is also null, then a random one
2830
* is generated on the fly.
2931
*
3032
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
@@ -141,32 +143,42 @@ public function getCsrfProvider()
141143
}
142144

143145
/**
144-
* Binds the form with values and files.
146+
* Binds the form with submitted data from a Request object
145147
*
146-
* This method is final because it is very easy to break a form when
147-
* overriding this method and adding logic that depends on $taintedFiles.
148-
* You should override doBind() instead where the uploaded files are
149-
* already merged into the data array.
148+
* @param Request $request The request object
149+
* @see bind()
150+
*/
151+
public function bindRequest(Request $request)
152+
{
153+
$values = $request->request->get($this->getName());
154+
$files = $request->files->get($this->getName());
155+
156+
$this->bind(self::deepArrayUnion($values, $files));
157+
}
158+
159+
/**
160+
* Binds the form with submitted data from the PHP globals $_POST and
161+
* $_FILES
150162
*
151-
* @param array $taintedValues The form data of the $_POST array
152-
* @param array $taintedFiles An array of uploaded files
153-
* @return Boolean Whether the form is valid
163+
* @see bind()
154164
*/
155-
final public function bind($taintedValues, array $taintedFiles = null)
165+
public function bindGlobals()
156166
{
157-
if (null === $taintedFiles) {
158-
if ($this->isMultipart() && $this->getParent() === null) {
159-
throw new \InvalidArgumentException('You must provide a files array for multipart forms');
160-
}
167+
$values = $_POST[$this->getName()];
161168

162-
$taintedFiles = array();
163-
}
169+
// fix files array and convert to UploadedFile instances
170+
$fileBag = new FileBag($_FILES);
171+
$files = $fileBag->get($this->getName());
164172

165-
if (null === $taintedValues) {
166-
$taintedValues = array();
167-
}
173+
$this->bind(self::deepArrayUnion($values, $files));
174+
}
168175

169-
$this->doBind(self::deepArrayUnion($taintedValues, $taintedFiles));
176+
/**
177+
* {@inheritDoc}
178+
*/
179+
public function bind($values)
180+
{
181+
parent::bind($values);
170182

171183
if ($this->getParent() === null) {
172184
if ($this->validator === null) {
@@ -192,17 +204,6 @@ final public function bind($taintedValues, array $taintedFiles = null)
192204
}
193205
}
194206

195-
/**
196-
* Binds the form with the given data.
197-
*
198-
* @param array $taintedData The data to bind to the form
199-
* @return Boolean Whether the form is valid
200-
*/
201-
protected function doBind(array $taintedData)
202-
{
203-
parent::bind($taintedData);
204-
}
205-
206207
/**
207208
* @return true if this form is CSRF protected
208209
*/

tests/Symfony/Tests/Component/Form/FormTest.php

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
use Symfony\Component\Form\HiddenField;
2121
use Symfony\Component\Form\FieldGroup;
2222
use Symfony\Component\Form\PropertyPath;
23+
use Symfony\Component\HttpFoundation\Request;
24+
use Symfony\Component\HttpFoundation\File\UploadedFile;
2325
use Symfony\Component\Validator\ConstraintViolation;
2426
use Symfony\Component\Validator\ConstraintViolationList;
2527
use Symfony\Tests\Component\Form\Fixtures\Author;
@@ -222,26 +224,75 @@ public function testBindThrowsExceptionIfNoValidatorIsSet()
222224
$form->bind(array()); // irrelevant
223225
}
224226

225-
public function testMultipartFormsWithoutParentsRequireFiles()
227+
public function testBindRequest()
226228
{
227-
$form = new Form('author', new Author(), $this->validator);
228-
$form->add($this->createMultipartMockField('file'));
229+
$values = array(
230+
'author' => array(
231+
'name' => 'Bernhard',
232+
'image' => array('filename' => 'foobar.png'),
233+
),
234+
);
235+
$files = array(
236+
'author' => array(
237+
'error' => array('image' => array('file' => UPLOAD_ERR_OK)),
238+
'name' => array('image' => array('file' => 'upload.png')),
239+
'size' => array('image' => array('file' => 123)),
240+
'tmp_name' => array('image' => array('file' => 'abcdef.png')),
241+
'type' => array('image' => array('file' => 'image/png')),
242+
),
243+
);
244+
245+
$request = new Request(array(), $values, array(), array(), $files);
246+
247+
$form = new Form('author', null, $this->createMockValidator());
248+
$form->add(new TestField('name'));
249+
$imageForm = new FieldGroup('image');
250+
$imageForm->add(new TestField('file'));
251+
$imageForm->add(new TestField('filename'));
252+
$form->add($imageForm);
253+
254+
$form->bindRequest($request);
229255

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

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

236-
public function testMultipartFormsWithParentsRequireNoFiles()
263+
public function testBindGlobals()
237264
{
238-
$form = new Form('author', new Author(), $this->validator);
239-
$form->add($this->createMultipartMockField('file'));
265+
$_POST = array(
266+
'author' => array(
267+
'name' => 'Bernhard',
268+
'image' => array('filename' => 'foobar.png'),
269+
),
270+
);
271+
$_FILES = array(
272+
'author' => array(
273+
'error' => array('image' => array('file' => UPLOAD_ERR_OK)),
274+
'name' => array('image' => array('file' => 'upload.png')),
275+
'size' => array('image' => array('file' => 123)),
276+
'tmp_name' => array('image' => array('file' => 'abcdef.png')),
277+
'type' => array('image' => array('file' => 'image/png')),
278+
),
279+
);
280+
281+
282+
$form = new Form('author', null, $this->createMockValidator());
283+
$form->add(new TestField('name'));
284+
$imageForm = new FieldGroup('image');
285+
$imageForm->add(new TestField('file'));
286+
$imageForm->add(new TestField('filename'));
287+
$form->add($imageForm);
288+
289+
$form->bindGlobals();
240290

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

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

247298
public function testUpdateFromPropertyIsIgnoredIfFormHasObject()

0 commit comments

Comments
 (0)