Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6ff4120

Browse filesBrowse files
Bernhard Schussekfabpot
Bernhard Schussek
authored andcommitted
[Form] Added Form option "by_reference" so that objects received from parent forms are modified by reference when this option is true (the default)
The implication is that set<Reference>() in the object of the parent form will not be called (and thus not has to be implemented/public). If you want to suppress this behaviour, manually set "by_reference" to false.
1 parent 42a3e40 commit 6ff4120
Copy full SHA for 6ff4120

File tree

Expand file treeCollapse file tree

5 files changed

+173
-0
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+173
-0
lines changed

‎src/Symfony/Component/Form/DateField.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/DateField.php
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,19 @@ class DateField extends HybridField
8989
*/
9090
protected $formatter;
9191

92+
/**
93+
* {@inheritDoc}
94+
*/
95+
public function __construct($key, array $options = array())
96+
{
97+
// Override parent option
98+
// \DateTime objects are never edited by reference, because
99+
// we treat them like value objects
100+
$this->addOption('by_reference', false);
101+
102+
parent::__construct($key, $options);
103+
}
104+
92105
protected function configure()
93106
{
94107
$this->addOption('widget', self::CHOICE, self::$widgets);

‎src/Symfony/Component/Form/DateTimeField.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/DateTimeField.php
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,19 @@ class DateTimeField extends Form
7575
TimeField::INPUT,
7676
);
7777

78+
/**
79+
* {@inheritDoc}
80+
*/
81+
public function __construct($key, array $options = array())
82+
{
83+
// Override parent option
84+
// \DateTime objects are never edited by reference, because
85+
// we treat them like value objects
86+
$this->addOption('by_reference', false);
87+
88+
parent::__construct($key, $options);
89+
}
90+
7891
protected function configure()
7992
{
8093
$this->addOption('date_widget', DateField::CHOICE, self::$dateWidgets);

‎src/Symfony/Component/Form/Form.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/Form.php
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public function __construct($name = null, array $options = array())
9393
$this->addOption('virtual', false);
9494
$this->addOption('validator');
9595
$this->addOption('context');
96+
$this->addOption('by_reference', true);
9697

9798
if (isset($options['validation_groups'])) {
9899
$options['validation_groups'] = (array)$options['validation_groups'];
@@ -880,6 +881,21 @@ public function validateData(ExecutionContext $context)
880881
}
881882
}
882883

884+
/**
885+
* {@inheritDoc}
886+
*/
887+
public function writeProperty(&$objectOrArray)
888+
{
889+
$data = $this->getData();
890+
891+
// Don't update parent if data is a composite type (object or array)
892+
// and "by_reference" option is true, because then we expect that
893+
// we are working with a reference to the parent's data
894+
if (!(is_object($data) || is_array($data)) || !$this->getOption('by_reference')) {
895+
parent::writeProperty($objectOrArray);
896+
}
897+
}
898+
883899
/**
884900
* Merges two arrays without reindexing numeric keys.
885901
*

‎src/Symfony/Component/Form/TimeField.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Form/TimeField.php
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ class TimeField extends Form
5959
self::RAW,
6060
);
6161

62+
/**
63+
* {@inheritDoc}
64+
*/
65+
public function __construct($key, array $options = array())
66+
{
67+
// Override parent option
68+
// \DateTime objects are never edited by reference, because
69+
// we treat them like value objects
70+
$this->addOption('by_reference', false);
71+
72+
parent::__construct($key, $options);
73+
}
74+
6275
/**
6376
* {@inheritDoc}
6477
*/

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

Copy file name to clipboardExpand all lines: tests/Symfony/Tests/Component/Form/FormTest.php
+118Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,59 @@ protected function configure()
4141
}
4242
}
4343

44+
// behaves like a form with a value transformer that transforms into
45+
// a specific format
46+
class FormTest_FormThatReturns extends Form
47+
{
48+
protected $returnValue;
49+
50+
public function setReturnValue($returnValue)
51+
{
52+
$this->returnValue = $returnValue;
53+
}
54+
55+
public function setData($data)
56+
{
57+
}
58+
59+
public function getData()
60+
{
61+
return $this->returnValue;
62+
}
63+
}
64+
65+
class FormTest_AuthorWithoutRefSetter
66+
{
67+
protected $reference;
68+
69+
protected $referenceCopy;
70+
71+
public function __construct($reference)
72+
{
73+
$this->reference = $reference;
74+
$this->referenceCopy = $reference;
75+
}
76+
77+
// The returned object should be modified by reference without having
78+
// to provide a setReference() method
79+
public function getReference()
80+
{
81+
return $this->reference;
82+
}
83+
84+
// The returned object is a copy, so setReferenceCopy() must be used
85+
// to update it
86+
public function getReferenceCopy()
87+
{
88+
return is_object($this->referenceCopy) ? clone $this->referenceCopy : $this->referenceCopy;
89+
}
90+
91+
public function setReferenceCopy($reference)
92+
{
93+
$this->referenceCopy = $reference;
94+
}
95+
}
96+
4497
class TestSetDataBeforeConfigureForm extends Form
4598
{
4699
protected $testCase;
@@ -1130,6 +1183,71 @@ public function testValidateDataDoesNotWalkScalars()
11301183
$form->validateData($context);
11311184
}
11321185

1186+
public function testSubformDoesntCallSetters()
1187+
{
1188+
$author = new FormTest_AuthorWithoutRefSetter(new Author());
1189+
1190+
$form = new Form('author', array('validator' => $this->createMockValidator()));
1191+
$form->setData($author);
1192+
$refForm = new Form('reference');
1193+
$refForm->add(new TestField('firstName'));
1194+
$form->add($refForm);
1195+
1196+
$form->bind($this->createPostRequest(array(
1197+
'author' => array(
1198+
// reference has a getter, but not setter
1199+
'reference' => array(
1200+
'firstName' => 'Foo',
1201+
)
1202+
)
1203+
)));
1204+
1205+
$this->assertEquals('Foo', $author->getReference()->firstName);
1206+
}
1207+
1208+
public function testSubformCallsSettersIfByReferenceIsFalse()
1209+
{
1210+
$author = new FormTest_AuthorWithoutRefSetter(new Author());
1211+
1212+
$form = new Form('author', array('validator' => $this->createMockValidator()));
1213+
$form->setData($author);
1214+
$refForm = new Form('referenceCopy', array('by_reference' => false));
1215+
$refForm->add(new TestField('firstName'));
1216+
$form->add($refForm);
1217+
1218+
$form->bind($this->createPostRequest(array(
1219+
'author' => array(
1220+
// referenceCopy has a getter that returns a copy
1221+
'referenceCopy' => array(
1222+
'firstName' => 'Foo',
1223+
)
1224+
)
1225+
)));
1226+
1227+
// firstName can only be updated if setReferenceCopy() was called
1228+
$this->assertEquals('Foo', $author->getReferenceCopy()->firstName);
1229+
}
1230+
1231+
public function testSubformCallsSettersIfReferenceIsScalar()
1232+
{
1233+
$author = new FormTest_AuthorWithoutRefSetter('scalar');
1234+
1235+
$form = new Form('author', array('validator' => $this->createMockValidator()));
1236+
$form->setData($author);
1237+
$refForm = new FormTest_FormThatReturns('referenceCopy');
1238+
$refForm->setReturnValue('foobar');
1239+
$form->add($refForm);
1240+
1241+
$form->bind($this->createPostRequest(array(
1242+
'author' => array(
1243+
'referenceCopy' => array(), // doesn't matter actually
1244+
)
1245+
)));
1246+
1247+
// firstName can only be updated if setReferenceCopy() was called
1248+
$this->assertEquals('foobar', $author->getReferenceCopy());
1249+
}
1250+
11331251
/**
11341252
* Create a group containing two fields, "visibleField" and "hiddenField"
11351253
*

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.