-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Form] RFC: Adapt Form API to avoid exponential growth of the violation mapping #3903
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@bschussek During the sfPot 2 days ago, @rande told me that the |
@stof The performance of PropertyPath would not change. |
@bschussek this looks fine, but it's a pretty big BC break (other BC breaks are usually only configuration stuff and all) |
@stof it might be possible to implement some kind of cache there ? @bschussek could the |
@vicb yeah, this is what we talked about. These method could probably delegate the work to another object, which could be replaced by a cached implementation (or eventually an implementation used by generating some code during the cache-warming) |
@vicb the cache solution can be a generated set of classes which "know" how to set or get values. This will avoid the ReflectionClass initialization on each read/write and also checks done in the PropertyPath class. This can be also backed by the ORM metadata layer |
@r1pp3rj4ck Yes, this is unfortunate. @vicb Periods would then be allowed in names, the other restrictions would remain (in order to generate valid IDs). Also be aware that the name would still be wrapped into the parent's name, i.e. the real HTML value is "foo[ba.ar]" if you name your field "ba.ar" and its parent is called "foo". @stof Sounds good. I guess it's time to finally pull PropertyPath into a separate component. |
Although it's quite a BC break, I think it's all quite reasonable. 👍 |
I was never found on We will definitively need to have a big warning for this BC, though. |
See also #3272 |
This BC break is unfortunately definitely needed (and anyone who has tried to debug property paths in I'm not a big fan of the |
could |
@vicb For me this intuitively has a different meaning. |
right, your notation makes more sense. |
Commits ------- 6e4ed9e [Form] Fixed regression: bind(null) was not converted to an empty string anymore fcb2227 [Form] Deprecated FieldType, which has been merged into FormType bfa7ef2 [Form] Removed obsolete exceptions 2a49449 [Form] Simplified CSRF mechanism and removed "csrf" type Discussion ---------- [Form] Merged FieldType into FormType Bug fix: no Feature addition: no Backwards compatibility break: yes Symfony2 tests pass: yes Fixes the following tickets: #3878 Todo: update the documentation on theming  This PR is a preparatory PR for #3879. See also #3878. --------------------------------------------------------------------------- by juliendidier at 2012-04-13T14:25:19Z What's the benefit ? --------------------------------------------------------------------------- by henrikbjorn at 2012-04-13T14:26:40Z why `input_widget` ? and not just `widget` --------------------------------------------------------------------------- by Burgov at 2012-04-13T14:27:49Z @juliendidier dynamic inheritance is now obsolete which fixes some other issues --------------------------------------------------------------------------- by stloyd at 2012-04-13T14:37:26Z What about __not__ breaking API so *badly* and leaving `FieldType` which will be simple like (with marking as deprecated): ```php <?php class FieldType extends AbstractType { public function getParent(array $options) { return 'form'; } public function getName() { return 'field'; } } --------------------------------------------------------------------------- by bschussek at 2012-04-13T14:43:41Z @stloyd That's a very good idea. --------------------------------------------------------------------------- by mvrhov at 2012-04-13T17:41:21Z IMHO what @stloyd proposed sounds like a good idea, but removing FieldType class, if #3903 will come into life might ensure that more forms will broke and people will check them thoroughly. --------------------------------------------------------------------------- by r1pp3rj4ck at 2012-04-13T18:46:08Z @bschussek looks great, but I'm concerned about how quickly will the third-party bundles adapt to this BC break. I hope really quick, because if they don't the whole stuff will be useless :S of course it's not your problem to solve. --------------------------------------------------------------------------- by stof at 2012-04-13T18:50:32Z @r1pp3rj4ck there is already another BC break requiring to update custom types for Symfony master. So third party bundles already have to do some work. --------------------------------------------------------------------------- by r1pp3rj4ck at 2012-04-13T18:59:37Z @stof which one? I've looked into @bschussek 's RFC about these [foo].bar stuff, but it's not yet implemented. Are you refering to this or another one I've missed? --------------------------------------------------------------------------- by stof at 2012-04-13T19:04:06Z @r1pp3rj4ck the change regarding default options --------------------------------------------------------------------------- by r1pp3rj4ck at 2012-04-13T19:06:10Z @stof oh, I forgot that one. Weird thing is that I've already changed my default options today and still forgetting these stuff :D --------------------------------------------------------------------------- by bschussek at 2012-04-14T08:58:29Z I restored and deprecated FieldType now. I'd appreciate further reviews. --------------------------------------------------------------------------- by stloyd at 2012-04-14T09:02:32Z Maybe we should try to avoid this BC in templates ? What do you think about similar move like with `FieldType` ? (hold old, but inside just render new) --------------------------------------------------------------------------- by bschussek at 2012-04-14T09:07:22Z @stloyd You mean for those cases where people explicitely render the block "field_*"? We can do that. --------------------------------------------------------------------------- by stloyd at 2012-04-14T09:09:45Z @bschussek Yes I mean this case =) Sorry for not being explicit, I need some coffee I think =) --------------------------------------------------------------------------- by bschussek at 2012-04-17T14:45:35Z I added the field_* block 8000 s again for BC. Could someone please review again? Otherwise this can be merged. --------------------------------------------------------------------------- by Burgov at 2012-04-17T15:11:16Z @bschussek I'm not sure what has changed to cause this, but if I try out your branch on our forms, if I leave the value of an input empty, eventually the reverseTransform method receives a null value, rather than a '' (empty string) value, as on the current symfony master. DateTimeToLocalizedStringTransformer, for example, will throw an Exception if the value is not a string ```php if (!is_string($value)) { throw new UnexpectedTypeException($value, 'string'); } ``` Other than that, all forms render just the same as they do on symfony master --------------------------------------------------------------------------- by bschussek at 2012-04-17T15:30:29Z @Burgov Fixed.
Would probably also fix #3995 |
As a side note: This change will move the recommended Twig syntax from {{ form_widget(form.child) }} to {{ form_widget(form['child']) }}
{{ form_widget(form['[child]']) }}
{{ form_widget(form['[address][street]']) }} Alternatively (if that's too many a bracket for you), this could be: {{ form_widget(form.getChild('child')) }}
{{ form_widget(form.getChild('[child]')) }}
{{ form_widget(form.getChild('[address][street]')) }} What do you think? |
That's much less intuitive than the current version, and this is indeed a very big BC break. |
Yes. Trying to find something better is difficult though. |
... and it's absolutely ugly. |
I'm not sure if it's possible -- but what about mimicking the PHP api of the form objects? {{ form_widget(form.child) }}
{{ form_widget(form['child']) }}
{{ form_widget(form['address']['street']) }} |
A completely alternative approach to this problem could be to let a form whose "data_class" is set to Then we could keep the current approach and do the following: <?php
// Form backed by a My\Class object
// The construction is done by the framework
$builder = new FormBuilder($factory, $dispatcher, 'My\Class');
// Done by the user:
$builder
// mapped to $data->getCity()
->add('city')
// mapped to $data->getAddress()->getStreet()
->add('street', null, array(
'property_path' => 'address.street',
))
// not mapped at all
->add('terms', array(
'property_path' => false,
));
// Form backed by an array
$builder = new FormBuilder($factory, $dispatcher, null);
// Done by the user
$builder
// mapped to $data['city']
->add('city')
// mapped to $data->getAddress()->getStreet()
->add('street', null, array(
'property_path' => 'address.street',
))
// not mapped at all
->add('terms', array(
'property_path' => false,
)); As you can see, the only difference is when the "property_path" option is not explicitely set. Nevertheless, we can deterministically guess the default property path from the field name ("city" vs. "[city]"). Thoughts? |
@marijn when adding a field with |
@bschussek what if I need to map something to |
@stof |
oh, so a form backed by an object would still be able to use array access by forcing it with your previous suggestion ? Seems good |
So it's not only ugly in twig but also in PHP? (Excuse me if that sounds harsh, it just seems unintuitive and... well, ugly) |
btw, are you also dropping the suggestion about replacing the |
@bschussek Is this new syntax also necessarily needed for forms based on object data? |
My last suggestion was about leaving everything exactly as is, except for interpreting the case with "data_class"==null differently. About dots in HTML names, they are probably possible then, but I need to check. |
Why not using something different, I think twig can help here : |
@rande I don't understand you proposal. There is no issue about the |
@stof the proposed syntax is ugly, I just try to find another syntax ... |
@rande But you are not considering the appropriate stuff. The syntax to navigate in the tree comes from the way the object works (and would be as ugly in PHP with the proposal). |
Solution with minimal BC breaks available now at the linked PR. |
Commits ------- 1422506 [Form] Clarified the usage of "constraints" in the UPGRADE file af41a1a [Form] Fixed typos ac69394 [Form] Allowed native framework errors to be mapped as well 59d6b55 [Form] Fixed: error mapping aborts if reaching an unsynchronized form 9eda5f5 [Form] Fixed: RepeatedType now maps all errors to the first field 215b687 [Form] Added capability to process "." rules in "error_mapping" c9c4900 [Form] Fixed: errors are not mapped to unsynchronized forms anymore c8b61d5 [Form] Renamed FormMapping to MappingRule and moved some logic there to make rules more extendable d0d1fe6 [Form] Added more information to UPGRADE and CHANGELOG 0c09a0e [Form] Made $name parameters optional in PropertyPathBuilder:replaceBy(Index|Property) 081c643 [Form] Updated UPGRADE and CHANGELOG bbffd1b [Form] Fixed index checks in PropertyPath classes ea5ff77 [Form] Fixed issues mentioned in the PR comments 7a4ba52 [EventDispatcher] Added class UnmodifiableEventDispatcher 306324e [Form] Greatly improved the error mapping done in DelegatingValidationListener 8f7e2f6 [Validator] Fixed: @Valid does not recurse the traversal of collections anymore by default 5e87dd8 [Form] Added tests for the case when "property_path" is null or false. Instead of setting "property_path" to false, you should set "mapped" to false instead. 2301b15 [Form] Tightened PropertyPath validation to reject any empty value (such as false) 7ff2a9b Revert "[Form] removed a constraint in PropertyPath as the path can definitely be an empty string for errors attached on the main form (when using a constraint defined with the 'validation_constraint' option)" 860dd1f [Form] Adapted Form to create a deterministic property path by default 03f5058 [Form] Fixed property name in PropertyPathMapperTest c2a243f [Form] Made PropertyPath deterministic: "[prop]" always refers to indices (array or ArrayAccess), "prop" always refers to properties 2996340 [Form] Extracted FormConfig class to simplify the Form's constructor Discussion ---------- [Form] Improved the error mapping and made property paths deterministic Bug fix: yes Feature addition: no Backwards compatibility break: **yes** Symfony2 tests pass: yes Fixes the following tickets: #1971, #2945, #3272, #3308, #3903, #4329 Probably fixes: #2729 Todo: - This PR is ready for review. The algorithm for assigning errors to forms in the form tree was improved a lot. Also the error mapping works better now. There are still a few features to be added (e.g. wildcards "*"), but these can be implemented now pretty easily. This PR breaks PR in that a form explicitely needs to set the "data_class" option if it wants to map to an object and needs to leave that option empty if it wants to map to an array. Furthermore, property paths must be deterministic now: `foo` now only maps to `(g|s)etFoo()`, but not the index `["foo"]` (array or ArrayAccess), while `[foo]` only maps to the latter but not the former. See #3903 for more information. --------------------------------------------------------------------------- by travisbot at 2012-05-19T21:35:24Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1377086) (merged 9e346990 into 2229461). --------------------------------------------------------------------------- by Tobion at 2012-05-20T01:47:48Z Good stuff in general :) --------------------------------------------------------------------------- by bschussek at 2012-05-20T09:19:18Z Fixed everything mentioned here so far. --------------------------------------------------------------------------- by travisbot at 2012-05-20T09:22:22Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1379548) (merged 49918bef into 2229461). --------------------------------------------------------------------------- by Tobion at 2012-05-20T14:29:14Z many occurences of two spaces after `@param` (should be only one space). --------------------------------------------------------------------------- by Koc at 2012-05-20T14:40:18Z Sorry, I'm cannot observe all changes for form component in 2.1, so I have a question: ```php <?php protected $isPrivate; public function isPrivate() {} public function setPrivate() {} ``` Is it possible validate this property with accessors/mutators from code above in 2.1 now? --------------------------------------------------------------------------- by bschussek at 2012-05-20T14:41:09Z The type after `@param` used to be aligned with the type of the `@return` tag. Let's get the PHPDoc-guidelines straight before nitpicking more on these trivialities. --------------------------------------------------------------------------- by bschussek at 2012-05-20T14:42:34Z @Koc Please move your question to the user mailing list, let's keep this PR on topic. --------------------------------------------------------------------------- by bschussek at 2012-05-20T14:45:42Z Fixed everything mentioned until now. --------------------------------------------------------------------------- by travisbot at 2012-05-20T14:47:48Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1380903) (merged 03d60a03 into f433f6b). --------------------------------------------------------------------------- by bschussek at 2012-05-20T15:18:12Z CHANGELOG/UPGRADE is now updated. --------------------------------------------------------------------------- by travisbot at 2012-05-20T15:19:39Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1381047) (merged 48cc3eca into f433f6b). --------------------------------------------------------------------------- by Tobion at 2012-05-20T16:16:51Z All the deprecated methods and changed constructor arguments should probably be mentioned in the changelog/upgrade. --------------------------------------------------------------------------- by travisbot at 2012-05-21T07:31:47Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1386621) (merged c0ef69a1 into 1407f11). --------------------------------------------------------------------------- by travisbot at 2012-05-21T08:01:46Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1386826) (merged 4f3fc1fe into 1407f11). --------------------------------------------------------------------------- by travisbot at 2012-05-21T09:22:30Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1387263) (merged e3675050 into 1407f11). --------------------------------------------------------------------------- by bschussek at 2012-05-21T09:43:08Z This PR now fixes #1971. --------------------------------------------------------------------------- by travisbot at 2012-05-21T09:45:51Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1387370) (merged de33f9ef into 1407f11). --------------------------------------------------------------------------- by travisbot at 2012-05-21T11:06:53Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1387838) (merged da3b562e into 1407f11). --------------------------------------------------------------------------- by bschussek at 2012-05-21T11:07:45Z This PR now fixes #2945. --------------------------------------------------------------------------- by bschussek at 2012-05-21T15:33:33Z Native errors (such as "invalid", "extra_fields" etc.) are now respected by the "error_mapping" option as well. The option "validation_constraint" was deprecated, "constraints" is its replacement and a lot handier, because it allows you to work easily with arrays. ```php <?php $builder ->add('name', 'text', array( 'constraints' => new NotBlank(), )) ->add('phoneNumber', 'text', array( 'constraints' => array( new NotBlank(), new MinLength(7), new Type('numeric') ) )); ``` Ready for review again. --------------------------------------------------------------------------- by travisbot at 2012-05-21T15:33:45Z This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1390239) (merged e162f56d into ea33d4d). --------------------------------------------------------------------------- by travisbot at 2012-05-21T15:40:02Z This pull request [fails](http://travis-ci.org/symfony/symfony/builds/1390367) (merged e8729a7f into ea33d4d). --------------------------------------------------------------------------- by travisbot at 2012-05-21T16:06:03Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1390663) (merged ef39aba4 into ea33d4d). --------------------------------------------------------------------------- by travisbot at 2012-05-22T08:54:36Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1398153) (merged af41a1a into e4e3ce6). --------------------------------------------------------------------------- by travisbot at 2012-05-22T09:26:12Z This pull request [passes](http://travis-ci.org/symfony/symfony/builds/1398415) (merged 1422506 into e4e3ce6).
NOTE: I'm aware that 2.1 introduces quite a few BC breaks in the Form component. Unfortunately these are necessary in order to fix a number of bugs present in 2.0. Doing these changes now will hopefully help to stabilize the API after 2.1.
I suggest to make property paths first class citizens of Forms. I will start with explaining the API change and continue with the reasoning why I think this should be done.
Old API:
New API:
Negative consequences:
Positive consequences:
Reasoning:
The validator generates violation errors with property paths that must be mapped to the corresponding form fields. Right now, this mapping grows exponentially in the length of the property path:
[city]
address[city]
[address].city
address[city]
[address][city]
[address][city]
person.address[city]
person[address].city
person[address][city]
[person].address.city
[person].address[city]
[person][address].city
[person][address][city]
Changing the API would make property paths deterministic and greatly simplify the mapping:
A simplified mapping mechanism allows more elaborate mapping options, like specifying that
Feedback is appreciated.
The text was updated successfully, but these errors were encountered: