Merge remote branch 'bschussek/form'

* bschussek/form:
  [Form] CSRF fields are not included in the children of a FormView anymore if the view is not the root
  [Form] FormView::offsetUnset() is now supported. It was possible anyway using getChildren() and setChildren().
  [Form] Split the option "modifiable" of the "collection" type into "allow_add" and "allow_delete"
  [Form] Added test for last commit by kriswallsmith and improved dealing with original names
  [Form] Fixed variable scope when entering nested form helpers
  [Form] Added tests for blocks/templates in the format _<ID>_(widget|row|label|...)
  [Form] updated listener to check that data is an array
This commit is contained in:
Fabien Potencier 2011-05-04 22:13:33 +02:00
commit 36bcfcc5ee
31 changed files with 427 additions and 332 deletions

View File

@ -103,6 +103,24 @@ beta1 to beta2
app/Resources/translations/catalogue.fr.xml
* The option "modifiable" of the "collection" form type was split into two
options "allow_add" and "allow_delete".
Before:
$builder->add('tags', 'collection', array(
'type' => 'text',
'modifiable' => true,
));
After:
$builder->add('tags', 'collection', array(
'type' => 'text',
'allow_add' => true,
'allow_delete' => true,
));
PR12 to beta1
-------------

View File

@ -27,10 +27,12 @@ class FormExtension extends \Twig_Extension
protected $templates;
protected $environment;
protected $themes;
protected $varStack;
public function __construct(array $resources = array())
{
$this->themes = new \SplObjectStorage();
$this->varStack = new \SplObjectStorage();
$this->resources = $resources;
}
@ -156,9 +158,8 @@ class FormExtension extends \Twig_Extension
{
$templates = $this->getTemplates($view);
$blocks = $view->get('types');
if ('widget' === $section || 'row' === $section) {
array_unshift($blocks, '_'.$view->get('id'));
}
array_unshift($blocks, '_'.$view->get('id'));
foreach ($blocks as &$block) {
$block = $block.'_'.$section;
@ -167,7 +168,15 @@ class FormExtension extends \Twig_Extension
$view->setRendered();
}
return $templates[$block]->renderBlock($block, array_merge($view->all(), $variables));
$this->varStack[$view] = array_replace(
$view->all(),
isset($this->varStack[$view]) ? $this->varStack[$view] : array(),
$variables
);
$html = $templates[$block]->renderBlock($block, $this->varStack[$view]);
return $html;
}
}

View File

@ -1,8 +0,0 @@
<?php if (!$form->hasParent() || !$form->getParent()->hasParent()): ?>
<input type="hidden"
<?php echo $view['form']->attributes() ?>
name="<?php echo $view->escape($name) ?>"
value="<?php echo $view->escape($value) ?>"
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
/>
<?php endif ?>

View File

@ -8,4 +8,5 @@
<?php echo $view['form']->widget($form['token']) ?>
<?php echo $view['form']->widget($form['name']) ?>
<?php echo $view['form']->widget($form['originalName']) ?>
</div>

View File

@ -1,4 +1,4 @@
<?php echo str_replace('{{ widget }}',
$view['form']->render('FrameworkBundle:Form:number_widget.html.php'),
$view['form']->render($form, 'FrameworkBundle:Form:number_widget.html.php'),
$money_pattern
) ?>

View File

@ -1 +1 @@
<?php echo $view['form']->render('FrameworkBundle:Form:number_widget.html.php') ?> %
<?php echo $view['form']->render($form, 'FrameworkBundle:Form:number_widget.html.php') ?> %

View File

@ -28,11 +28,14 @@ class FormHelper extends Helper
protected $engine;
protected $varStack = array();
protected $varStack;
protected $viewStack = array();
public function __construct(EngineInterface $engine)
{
$this->engine = $engine;
$this->varStack = new \SplObjectStorage();
}
public function attributes()
@ -40,8 +43,9 @@ class FormHelper extends Helper
$html = '';
$attr = array();
if (count($this->varStack) > 0) {
$vars = end($this->varStack);
if (count($this->viewStack) > 0) {
$view = end($this->viewStack);
$vars = $this->varStack[$view];
if (isset($vars['attr'])) {
$attr = $vars['attr'];
@ -101,9 +105,8 @@ class FormHelper extends Helper
{
$template = null;
$blocks = $view->get('types');
if ('widget' === $section || 'row' === $section) {
array_unshift($blocks, '_'.$view->get('id'));
}
array_unshift($blocks, '_'.$view->get('id'));
foreach ($blocks as &$block) {
$block = $block.'_'.$section;
$template = $this->lookupTemplate($block);
@ -121,19 +124,22 @@ class FormHelper extends Helper
$view->setRendered();
}
return $this->render($template, array_merge($view->all(), $variables));
return $this->render($view, $template, $variables);
}
public function render($template, array $variables = array())
public function render(FormView $view, $template, array $variables = array())
{
array_push($this->varStack, array_merge(
count($this->varStack) > 0 ? end($this->varStack) : array(),
$this->varStack[$view] = array_replace(
$view->all(),
isset($this->varStack[$view]) ? $this->varStack[$view] : array(),
$variables
));
);
$html = $this->engine->render($template, end($this->varStack));
array_push($this->viewStack, $view);
array_pop($this->varStack);
$html = $this->engine->render($template, $this->varStack[$view]);
array_pop($this->viewStack);
return $html;
}

View File

@ -18,9 +18,12 @@ class StubTemplateNameParser implements TemplateNameParserInterface
{
private $root;
public function __construct($root)
private $rootCustom;
public function __construct($root, $rootCustom)
{
$this->root = $root;
$this->rootCustom = $rootCustom;
}
public function parse($name)
@ -28,6 +31,8 @@ class StubTemplateNameParser implements TemplateNameParserInterface
$parts = explode(':', $name);
$name = $parts[count($parts)-1];
return new TemplateReference($this->root.'/'.$name, 'php');
$path = ($name{0} === '_' ? $this->rootCustom : $this->root).'/'.$name;
return new TemplateReference($path, 'php');
}
}

View File

@ -33,7 +33,8 @@ class FormHelperTest extends AbstractDivLayoutTest
parent::setUp();
$root = realpath(__DIR__.'/../../../Resources/views/Form');
$templateNameParser = new StubTemplateNameParser($root);
$rootCustom = realpath(__DIR__.'/Resources');
$templateNameParser = new StubTemplateNameParser($root, $rootCustom);
$loader = new FilesystemLoader(array());
$engine = new PhpEngine($templateNameParser, $loader);

View File

@ -0,0 +1,3 @@
<div id="container">
<?php echo $view['form']->render($form, 'FrameworkBundle:Form:text_widget.html.php') ?>
</div>

View File

@ -74,13 +74,6 @@
{{ block('field_widget') }}
{% endblock hidden_widget %}
{% block csrf_widget %}
{% if not form.hasParent or not form.getParent.hasParent %}
{% set type = type|default('hidden') %}
{{ block('field_widget') }}
{% endif %}
{% endblock csrf_widget %}
{% block hidden_row %}
{{ form_widget(form) }}
{% endblock hidden_row %}
@ -221,6 +214,7 @@
{{ form_widget(form.file) }}
{{ form_widget(form.token) }}
{{ form_widget(form.name) }}
{{ form_widget(form.originalName) }}
</div>
{% endspaceless %}
{% endblock file_widget %}

View File

@ -26,8 +26,6 @@ class FileToArrayTransformer implements DataTransformerInterface
if (null === $file || '' === $file) {
return array(
'file' => '',
'token' => '',
'name' => '',
);
}
@ -37,8 +35,6 @@ class FileToArrayTransformer implements DataTransformerInterface
return array(
'file' => $file,
'token' => '',
'name' => '',
);
}

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Extension\Core\EventListener;
use Symfony\Component\Form\Events;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\File\File;
@ -40,15 +41,22 @@ class FixFileUploadListener implements EventSubscriberInterface
public function onBindClientData(FilterDataEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
// TODO should be disableable
if (null === $data) {
$data = array();
}
// TESTME
$data = array_merge(array(
if (!is_array($data)) {
throw new UnexpectedTypeException($data, 'array');
}
$data = array_replace(array(
'file' => '',
'token' => '',
'name' => '',
), $event->getData());
'originalName' => '',
), $data);
// Newly uploaded file
if ($data['file'] instanceof UploadedFile && $data['file']->isValid()) {
@ -56,14 +64,15 @@ class FixFileUploadListener implements EventSubscriberInterface
$directory = $this->storage->getTempDir($data['token']);
$data['file']->move($directory);
$data['name'] = $data['file']->getName();
$data['originalName'] = $data['file']->getOriginalName();
}
// Existing uploaded file
if (!$data['file'] && $data['token'] && $data['name']) {
$path = $this->storage->getTempDir($data['token']) . DIRECTORY_SEPARATOR . $data ['name'];
$path = $this->storage->getTempDir($data['token']) . DIRECTORY_SEPARATOR . $data['name'];
if (file_exists($path)) {
$data['file'] = new File($path);
$data['file'] = new UploadedFile($path, $data['originalName'], null, null, null, true);
}
}

View File

@ -38,13 +38,14 @@ class ResizeFormListener implements EventSubscriberInterface
/**
* @var Boolean
*/
private $resizeOnBind;
private $allowAdd;
public function __construct(FormFactoryInterface $factory, $type, $resizeOnBind = false)
public function __construct(FormFactoryInterface $factory, $type, $allowAdd = false, $allowDelete = false)
{
$this->factory = $factory;
$this->type = $type;
$this->resizeOnBind = $resizeOnBind;
$this->allowAdd = $allowAdd;
$this->allowDelete = $allowDelete;
}
public static function getSubscribedEvents()
@ -71,7 +72,7 @@ class ResizeFormListener implements EventSubscriberInterface
// First remove all rows except for the prototype row
foreach ($form as $name => $child) {
if (!($this->resizeOnBind && '$$name$$' === $name)) {
if (!($this->allowAdd && '$$name$$' === $name)) {
$form->remove($name);
}
}
@ -86,10 +87,6 @@ class ResizeFormListener implements EventSubscriberInterface
public function preBind(DataEvent $event)
{
if (!$this->resizeOnBind) {
return;
}
$form = $event->getForm();
$data = $event->getData();
@ -102,28 +99,28 @@ class ResizeFormListener implements EventSubscriberInterface
}
// Remove all empty rows except for the prototype row
foreach ($form as $name => $child) {
if (!isset($data[$name]) && '$$name$$' !== $name) {
$form->remove($name);
if ($this->allowDelete) {
foreach ($form as $name => $child) {
if (!isset($data[$name]) && '$$name$$' !== $name) {
$form->remove($name);
}
}
}
// Add all additional rows
foreach ($data as $name => $value) {
if (!$form->has($name)) {
$form->add($this->factory->createNamed($this->type, $name, null, array(
'property_path' => '['.$name.']',
)));
if ($this->allowAdd) {
foreach ($data as $name => $value) {
if (!$form->has($name)) {
$form->add($this->factory->createNamed($this->type, $name, null, array(
'property_path' => '['.$name.']',
)));
}
}
}
}
public function onBindNormData(FilterDataEvent $event)
{
if (!$this->resizeOnBind) {
return;
}
$form = $event->getForm();
$data = $event->getData();
@ -135,9 +132,11 @@ class ResizeFormListener implements EventSubscriberInterface
throw new UnexpectedTypeException($data, 'array or \Traversable');
}
foreach ($data as $name => $child) {
if (!$form->has($name)) {
unset($data[$name]);
if ($this->allowDelete) {
foreach ($data as $name => $child) {
if (!$form->has($name)) {
unset($data[$name]);
}
}
}

View File

@ -13,13 +13,15 @@ namespace Symfony\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
class CollectionType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
if ($options['modifiable'] && $options['prototype']) {
if ($options['allow_add'] && $options['prototype']) {
$builder->add('$$name$$', $options['type'], array(
'property_path' => false,
'required' => false,
@ -27,15 +29,24 @@ class CollectionType extends AbstractType
}
$listener = new ResizeFormListener($builder->getFormFactory(),
$options['type'], $options['modifiable']);
$options['type'], $options['allow_add'], $options['allow_delete']);
$builder->addEventSubscriber($listener);
$builder->addEventSubscriber($listener)
->setAttribute('allow_add', $options['allow_add'])
->setAttribute('allow_delete', $options['allow_delete']);
}
public function buildView(FormView $view, FormInterface $form)
{
$view->set('allow_add', $form->getAttribute('allow_add'));
$view->set('allow_delete', $form->getAttribute('allow_delete'));
}
public function getDefaultOptions(array $options)
{
return array(
'modifiable' => false,
'allow_add' => false,
'allow_delete' => false,
'prototype' => true,
'type' => 'text',
);

View File

@ -45,7 +45,8 @@ class FileType extends AbstractType
->addEventSubscriber(new FixFileUploadListener($this->storage), 10)
->add('file', 'field')
->add('token', 'hidden')
->add('name', 'hidden');
->add('name', 'hidden')
->add('originalName', 'hidden');
}
public function buildViewBottomUp(FormView $view, FormInterface $form)

View File

@ -13,6 +13,8 @@ namespace Symfony\Component\Form\Extension\Csrf\Type;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
class FormTypeCsrfExtension extends AbstractTypeExtension
{
@ -34,7 +36,19 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
$csrfOptions['csrf_provider'] = $options['csrf_provider'];
}
$builder->add($options['csrf_field_name'], 'csrf', $csrfOptions);
$builder->add($options['csrf_field_name'], 'csrf', $csrfOptions)
->setAttribute('csrf_field_name', $options['csrf_field_name']);
}
}
public function buildViewBottomUp(FormView $view, FormInterface $form)
{
if ($view->hasParent() && $form->hasAttribute('csrf_field_name')) {
$name = $form->getAttribute('csrf_field_name');
if (isset($view[$name])) {
unset($view[$name]);
}
}
}

View File

@ -50,6 +50,8 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
function getData();
function getNormData();
function getClientData();
function isBound();

View File

@ -147,7 +147,7 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
public function offsetUnset($name)
{
throw new \BadMethodCallException('Not supported');
unset($this->children[$name]);
}
public function getIterator()

View File

@ -71,7 +71,8 @@ class UploadedFile extends File
* @throws FileException If file_uploads is disabled
* @throws FileNotFoundException If the file does not exist
*/
public function __construct($path, $originalName, $mimeType, $size, $error, $moved = false)
public function __construct($path, $originalName, $mimeType = null,
$size = null, $error = null, $moved = false)
{
if (!ini_get('file_uploads')) {
throw new FileException(sprintf('Unable to create UploadedFile because "file_uploads" is disabled in your php.ini file (%s)', get_cfg_var('cfg_file_path')));

View File

@ -29,9 +29,13 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest
$loader = new StubFilesystemLoader(array(
__DIR__.'/../../../../../../src/Symfony/Bundle/TwigBundle/Resources/views/Form',
__DIR__,
));
$this->extension = new FormExtension(array('div_layout.html.twig'));
$this->extension = new FormExtension(array(
'div_layout.html.twig',
'custom_widgets.html.twig',
));
$environment = new \Twig_Environment($loader);
$environment->addExtension($this->extension);

View File

@ -29,9 +29,13 @@ class FormExtensionTableLayoutTest extends AbstractTableLayoutTest
$loader = new StubFilesystemLoader(array(
__DIR__.'/../../../../../../src/Symfony/Bundle/TwigBundle/Resources/views/Form',
__DIR__,
));
$this->extension = new FormExtension(array('table_layout.html.twig'));
$this->extension = new FormExtension(array(
'table_layout.html.twig',
'custom_widgets.html.twig',
));
$environment = new \Twig_Environment($loader);
$environment->addExtension($this->extension);

View File

@ -0,0 +1,6 @@
{% block _text_id_widget %}
<div id="container">
{# TODO find a smarter way to render the parent type #}
<input type="text" id="{{ id }}" value="{{ value }}" />
</div>
{% endblock _text_id_widget %}

View File

@ -35,6 +35,21 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
);
}
public function testRowForwardsVariables()
{
$view = $this->factory->createNamed('text', 'name')->createView();
$html = $this->renderRow($view, array('label' => 'foo&bar'));
$this->assertMatchesXpath($html,
'/div
[
./label[@for="name"][.="[trans]foo&bar[/trans]"]
/following-sibling::input[@id="name"]
]
'
);
}
public function testRepeatedRow()
{
$form = $this->factory->createNamed('repeated', 'name');

View File

@ -192,6 +192,23 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
);
}
public function testWidgetById()
{
$form = $this->factory->createNamed('text', 'text_id');
$html = $this->renderWidget($form->createView());
$this->assertMatchesXpath($html,
'/div
[
./input
[@type="text"]
[@id="text_id"]
]
[@id="container"]
'
);
}
public function testCheckedCheckbox()
{
$form = $this->factory->createNamed('checkbox', 'na&me', true, array(
@ -463,19 +480,6 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
);
}
public function testCsrfWithNonRootParent()
{
$form = $this->factory->createNamed('csrf', 'na&me', null, array(
'property_path' => 'name',
));
$form->setParent($this->factory->create('form'));
$form->getParent()->setParent($this->factory->create('form'));
$html = $this->renderWidget($form->createView());
$this->assertEquals('', trim($html));
}
public function testDateTime()
{
$form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
@ -647,8 +651,9 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
./input[@type="file"][@id="na&me_file"]
/following-sibling::input[@type="hidden"][@id="na&me_token"]
/following-sibling::input[@type="hidden"][@id="na&me_name"]
/following-sibling::input[@type="hidden"][@id="na&me_originalName"]
]
[count(./input)=3]
[count(./input)=4]
'
);
}

View File

@ -0,0 +1,167 @@
<?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\Tests\Component\Form\Extension\Core\EventListener;
use Symfony\Component\Form\Event\FilterDataEvent;
use Symfony\Component\Form\Extension\Core\EventListener\FixFileUploadListener;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FixFileUploadListenerTest extends \PHPUnit_Framework_TestCase
{
private $storage;
private $destination;
public function setUp()
{
$this->storage = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\TemporaryStorage')
->disableOriginalConstructor()
->getMock();
}
public function testValidNewlyUploadedFile()
{
$passedToken = null;
$this->storage->expects($this->any())
->method('getTempDir')
->will($this->returnCallback(function ($token) use (&$passedToken) {
$passedToken = $token;
return __DIR__.DIRECTORY_SEPARATOR.'tmp';
}));
$file = $this->createUploadedFileMock('randomhash', 'original.jpg', true);
$file->expects($this->once())
->method('move')
->with(__DIR__.DIRECTORY_SEPARATOR.'tmp');
$data = array(
'file' => $file,
'token' => '',
'name' => '',
'originalName' => '',
);
$form = $this->getMock('Symfony\Tests\Component\Form\FormInterface');
$event = new FilterDataEvent($form, $data);
$filter = new FixFileUploadListener($this->storage);
$filter->onBindClientData($event);
$this->assertEquals(array(
'file' => $file,
'name' => 'randomhash',
'originalName' => 'original.jpg',
'token' => $passedToken,
), $event->getData());
}
public function testExistingUploadedFile()
{
$test = $this;
$this->storage->expects($this->any())
->method('getTempDir')
->will($this->returnCallback(function ($token) use ($test) {
$test->assertSame('abcdef', $token);
return __DIR__.DIRECTORY_SEPARATOR.'Fixtures';
}));
$data = array(
'file' => '',
'token' => 'abcdef',
'name' => 'randomhash',
'originalName' => 'original.jpg',
);
$form = $this->getMock('Symfony\Tests\Component\Form\FormInterface');
$event = new FilterDataEvent($form, $data);
$filter = new FixFileUploadListener($this->storage);
$filter->onBindClientData($event);
$this->assertEquals(array(
'file' => new UploadedFile(
__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'randomhash',
'original.jpg',
null,
null,
null,
true // already moved
),
'name' => 'randomhash',
'originalName' => 'original.jpg',
'token' => 'abcdef',
), $event->getData());
}
public function testNullAndExistingFile()
{
$existingData = array(
'file' => new UploadedFile(
__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'randomhash',
'original.jpg',
null,
null,
null,
true // already moved
),
'name' => 'randomhash',
'originalName' => 'original.jpg',
'token' => 'abcdef',
);
$form = $this->getMock('Symfony\Tests\Component\Form\FormInterface');
$form->expects($this->any())
->method('getNormData')
->will($this->returnValue($existingData));
$event = new FilterDataEvent($form, null);
$filter = new FixFileUploadListener($this->storage);
$filter->onBindClientData($event);
$this->assertSame($existingData, $event->getData());
}
/**
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testExpectNullOrArray()
{
$form = $this->getMock('Symfony\Tests\Component\Form\FormInterface');
$event = new FilterDataEvent($form, 'foobar');
$filter = new FixFileUploadListener($this->storage);
$filter->onBindClientData($event);
}
private function createUploadedFileMock($name, $originalName, $valid)
{
$file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor()
->getMock();
$file->expects($this->any())
->method('getName')
->will($this->returnValue($name));
$file->expects($this->any())
->method('getOriginalName')
->will($this->returnValue($originalName));
$file->expects($this->any())
->method('isValid')
->will($this->returnValue($valid));
return $file;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

View File

@ -59,7 +59,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
$data = array(1 => 'string', 2 => 'string');
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', false);
$listener = new ResizeFormListener($this->factory, 'text', false, false);
$listener->preSetData($event);
$this->assertFalse($this->form->has('0'));
@ -67,25 +67,25 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($this->form->has('2'));
}
public function testPreSetDataRemovesPrototypeRowIfNotResizeOnBind()
public function testPreSetDataRemovesPrototypeRowIfNotAllowAdd()
{
$this->form->add($this->getForm('$$name$$'));
$data = array();
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', false);
$listener = new ResizeFormListener($this->factory, 'text', false, false);
$listener->preSetData($event);
$this->assertFalse($this->form->has('$$name$$'));
}
public function testPreSetDataDoesNotRemovePrototypeRowIfResizeOnBind()
public function testPreSetDataDoesNotRemovePrototypeRowIfAllowAdd()
{
$this->form->add($this->getForm('$$name$$'));
$data = array();
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true);
$listener = new ResizeFormListener($this->factory, 'text', true, false);
$listener->preSetData($event);
$this->assertTrue($this->form->has('$$name$$'));
@ -98,7 +98,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
{
$data = 'no array or traversable';
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', false);
$listener = new ResizeFormListener($this->factory, 'text', false, false);
$listener->preSetData($event);
}
@ -108,28 +108,40 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
$data = null;
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', false);
$listener = new ResizeFormListener($this->factory, 'text', false, false);
$listener->preSetData($event);
}
public function testPreBindResizesFormIfResizable()
public function testPreBindResizesUpIfAllowAdd()
{
$this->form->add($this->getForm('0'));
$this->factory->expects($this->once())
->method('createNamed')
->with('text', 1, null, array('property_path' => '[1]'))
->will($this->returnValue($this->getForm('1')));
$data = array(0 => 'string', 1 => 'string');
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true, false);
$listener->preBind($event);
$this->assertTrue($this->form->has('0'));
$this->assertTrue($this->form->has('1'));
}
public function testPreBindResizesDownIfAllowDelete()
{
$this->form->add($this->getForm('0'));
$this->form->add($this->getForm('1'));
$this->factory->expects($this->once())
->method('createNamed')
->with('text', 2, null, array('property_path' => '[2]'))
->will($this->returnValue($this->getForm('2')));
$data = array(0 => 'string', 2 => 'string');
$data = array(0 => 'string');
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true);
$listener = new ResizeFormListener($this->factory, 'text', false, true);
$listener->preBind($event);
$this->assertTrue($this->form->has('0'));
$this->assertFalse($this->form->has('1'));
$this->assertTrue($this->form->has('2'));
}
// fix for https://github.com/symfony/symfony/pull/493
@ -139,20 +151,20 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
$data = array();
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true);
$listener = new ResizeFormListener($this->factory, 'text', false, true);
$listener->preBind($event);
$this->assertFalse($this->form->has('0'));
}
public function testPreBindDoesNothingIfNotResizable()
public function testPreBindDoesNothingIfNotAllowAddNorAllowDelete()
{
$this->form->add($this->getForm('0'));
$this->form->add($this->getForm('1'));
$data = array(0 => 'string', 2 => 'string');
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', false);
$listener = new ResizeFormListener($this->factory, 'text', false, false);
$listener->preBind($event);
$this->assertTrue($this->form->has('0'));
@ -167,7 +179,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
{
$data = 'no array or traversable';
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true);
$listener = new ResizeFormListener($this->factory, 'text', false, false);
$listener->preBind($event);
}
@ -177,7 +189,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
$data = null;
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true);
$listener = new ResizeFormListener($this->factory, 'text', false, true);
$listener->preBind($event);
$this->assertFalse($this->form->has('1'));
@ -190,31 +202,31 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
$data = '';
$event = new DataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true);
$listener = new ResizeFormListener($this->factory, 'text', false, true);
$listener->preBind($event);
$this->assertFalse($this->form->has('1'));
}
public function testOnBindNormDataRemovesEntriesMissingInTheFormIfResizable()
public function testOnBindNormDataRemovesEntriesMissingInTheFormIfAllowDelete()
{
$this->form->add($this->getForm('1'));
$data = array(0 => 'first', 1 => 'second', 2 => 'third');
$event = new FilterDataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true);
$listener = new ResizeFormListener($this->factory, 'text', false, true);
$listener->onBindNormData($event);
$this->assertEquals(array(1 => 'second'), $event->getData());
}
public function testOnBindNormDataDoesNothingIfNotResizable()
public function testOnBindNormDataDoesNothingIfNotAllowDelete()
{
$this->form->add($this->getForm('1'));
$data = array(0 => 'first', 1 => 'second', 2 => 'third');
$event = new FilterDataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', false);
$listener = new ResizeFormListener($this->factory, 'text', false, false);
$listener->onBindNormData($event);
$this->assertEquals($data, $event->getData());
@ -227,7 +239,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
{
$data = 'no array or traversable';
$event = new FilterDataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true);
$listener = new ResizeFormListener($this->factory, 'text', false, false);
$listener->onBindNormData($event);
}
@ -237,7 +249,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase
$data = null;
$event = new FilterDataEvent($this->form, $data);
$listener = new ResizeFormListener($this->factory, 'text', true);
$listener = new ResizeFormListener($this->factory, 'text', false, true);
$listener->onBindNormData($event);
$this->assertEquals(array(), $event->getData());

View File

@ -45,15 +45,15 @@ class CollectionFormTest extends TypeTestCase
$this->assertEquals('foo@baz.com', $form[0]->getData());
}
public function testSetDataAdjustsSizeIfModifiable()
public function testSetDataAddsPrototypeIfAllowAdd()
{
$form = $this->factory->create('collection', null, array(
'type' => 'field',
'modifiable' => true,
'allow_add' => true,
'prototype' => true,
));
$form->setData(array('foo@foo.com', 'foo@bar.com'));
$form->setData(array('foo@foo.com', 'foo@bar.com'));
$this->assertTrue($form[0] instanceof Form);
$this->assertTrue($form[1] instanceof Form);
$this->assertTrue($form['$$name$$'] instanceof Form);
@ -75,20 +75,6 @@ class CollectionFormTest extends TypeTestCase
$form->setData(new \stdClass());
}
public function testModifiableCollectionsContainExtraForm()
{
$form = $this->factory->create('collection', null, array(
'type' => 'field',
'modifiable' => true,
'prototype' => true,
));
$form->setData(array('foo@bar.com'));
$this->assertTrue($form['0'] instanceof Form);
$this->assertTrue($form['$$name$$'] instanceof Form);
$this->assertEquals(2, count($form));
}
public function testNotResizedIfBoundWithMissingData()
{
$form = $this->factory->create('collection', null, array(
@ -103,11 +89,11 @@ class CollectionFormTest extends TypeTestCase
$this->assertEquals(null, $form[1]->getData());
}
public function testResizedIfBoundWithMissingDataAndModifiable()
public function testResizedDownIfBoundWithMissingDataAndAllowDelete()
{
$form = $this->factory->create('collection', null, array(
'type' => 'field',
'modifiable' => true,
'allow_delete' => true,
));
$form->setData(array('foo@foo.com', 'bar@bar.com'));
$form->bind(array('foo@bar.com'));
@ -115,6 +101,7 @@ class CollectionFormTest extends TypeTestCase
$this->assertTrue($form->has('0'));
$this->assertFalse($form->has('1'));
$this->assertEquals('foo@bar.com', $form[0]->getData());
$this->assertEquals(array('foo@bar.com'), $form->getData());
}
public function testNotResizedIfBoundWithExtraData()
@ -130,11 +117,11 @@ class CollectionFormTest extends TypeTestCase
$this->assertEquals('foo@foo.com', $form[0]->getData());
}
public function testResizedUpIfBoundWithExtraDataAndModifiable()
public function testResizedUpIfBoundWithExtraDataAndAllowAdd()
{
$form = $this->factory->create('collection', null, array(
'type' => 'field',
'modifiable' => true,
'allow_add' => true,
));
$form->setData(array('foo@bar.com'));
$form->bind(array('foo@foo.com', 'bar@bar.com'));
@ -146,29 +133,14 @@ class CollectionFormTest extends TypeTestCase
$this->assertEquals(array('foo@foo.com', 'bar@bar.com'), $form->getData());
}
public function testModifableButNoPrototype()
public function testAllowAddButNoPrototype()
{
$form = $this->factory->create('collection', null, array(
'type' => 'field',
'modifiable' => true,
'allow_add' => true,
'prototype' => false,
));
$this->assertFalse($form->has('$$name$$'));
}
public function testResizedDownIfBoundWithLessDataAndModifiable()
{
$form = $this->factory->create('collection', null, array(
'type' => 'field',
'modifiable' => true,
));
$form->setData(array('foo@bar.com', 'bar@bar.com'));
$form->bind(array('foo@foo.com'));
$this->assertTrue($form->has('0'));
$this->assertFalse($form->has('1'));
$this->assertEquals('foo@foo.com', $form[0]->getData());
$this->assertEquals(array('foo@foo.com'), $form->getData());
}
}

View File

@ -1,172 +0,0 @@
<?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\Tests\Component\Form\Extension\Core\Type;
use Symfony\Component\Form\FileField;
use Symfony\Component\HttpFoundation\File\File;
class FileTypeTest extends TypeTestCase
{
public static $tmpFiles = array();
protected static $tmpDir;
protected $form;
public static function setUpBeforeClass()
{
self::$tmpDir = sys_get_temp_dir().DIRECTORY_SEPARATOR.'symfony-test';
if (!file_exists(self::$tmpDir)) {
mkdir(self::$tmpDir, 0777, true);
}
}
protected function setUp()
{
parent::setUp();
$this->form = $this->factory->create('file');
}
protected function tearDown()
{
foreach (self::$tmpFiles as $key => $file) {
@unlink($file);
unset(self::$tmpFiles[$key]);
}
}
public function createTmpFile($path)
{
self::$tmpFiles[] = $path;
file_put_contents($path, 'foobar');
}
public function testSubmitUploadsNewFiles()
{
$tmpDir = self::$tmpDir;
$generatedToken = '';
$this->storage->expects($this->atLeastOnce())
->method('getTempDir')
->will($this->returnCallback(function ($token) use ($tmpDir, &$generatedToken) {
// A 6-digit token is generated by FileUploader and passed
// to getTempDir()
$generatedToken = $token;
return $tmpDir;
}));
$file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor()
->getMock();
$file->expects($this->once())
->method('move')
->with($this->equalTo($tmpDir));
$file->expects($this->any())
->method('isValid')
->will($this->returnValue(true));
$file->expects($this->any())
->method('getName')
->will($this->returnValue('original_name.jpg'));
$file->expects($this->any())
->method('getPath')
->will($this->returnValue($tmpDir.'/original_name.jpg'));
$this->form->bind(array(
'file' => $file,
'token' => '',
'name' => '',
));
$this->assertRegExp('/^\d{6}$/', $generatedToken);
$this->assertEquals(array(
'file' => $file,
'token' => $generatedToken,
'name' => 'original_name.jpg',
), $this->form->getClientData());
$this->assertEquals($tmpDir.'/original_name.jpg', $this->form->getData());
}
public function testSubmitKeepsUploadedFilesOnErrors()
{
$tmpDir = self::$tmpDir;
$tmpPath = $tmpDir . DIRECTORY_SEPARATOR . 'original_name.jpg';
$this->createTmpFile($tmpPath);
$this->storage->expects($this->atLeastOnce())
->method('getTempDir')
->with($this->equalTo('123456'))
->will($this->returnValue($tmpDir));
$this->form->bind(array(
'file' => null,
'token' => '123456',
'name' => 'original_name.jpg',
));
$this->assertTrue(file_exists($tmpPath));
$file = new File($tmpPath);
$this->assertEquals(array(
'file' => $file,
'token' => '123456',
'name' => 'original_name.jpg',
), $this->form->getClientData());
$this->assertEquals(realpath($tmpPath), realpath($this->form->getData()));
}
public function testSubmitEmpty()
{
$this->storage->expects($this->never())
->method('getTempDir');
$this->form->bind(array(
'file' => '',
'token' => '',
'name' => '',
));
$this->assertEquals(array(
'file' => '',
'token' => '',
'name' => '',
), $this->form->getClientData());
$this->assertEquals(null, $this->form->getData());
}
public function testSubmitEmptyKeepsExistingFiles()
{
$tmpPath = self::$tmpDir . DIRECTORY_SEPARATOR . 'original_name.jpg';
$this->createTmpFile($tmpPath);
$file = new File($tmpPath);
$this->storage->expects($this->never())
->method('getTempDir');
$this->form->setData($tmpPath);
$this->form->bind(array(
'file' => '',
'token' => '',
'name' => '',
));
$this->assertEquals(array(
'file' => $file,
'token' => '',
'name' => '',
), $this->form->getClientData());
$this->assertEquals(realpath($tmpPath), realpath($this->form->getData()));
}
}

View File

@ -30,4 +30,24 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
$this->assertEquals(0, count($form));
}
public function testCsrfTokenIsOnlyIncludedInRootView()
{
$view =
$this->factory->createBuilder('form', null, array(
'csrf_field_name' => 'csrf',
))
->add('notCsrf', 'text')
->add(
$this->factory->createNamedBuilder('form', 'child', null, array(
'csrf_field_name' => 'csrf',
))
->add('notCsrf', 'text')
)
->getForm()
->createView();
$this->assertEquals(array('csrf', 'notCsrf', 'child'), array_keys(iterator_to_array($view)));
$this->assertEquals(array('notCsrf'), array_keys(iterator_to_array($view['child'])));
}
}