I think you're headed in the right direction, and I would like to add my voice that I would prefer RC1 be delayed so that something like this can make it in. Maybe a beta release next week?
I will attempt to put aside some of my time this weekend to go over it and see if I cant assist to help stuff get done. T On Fri, Feb 25, 2011 at 11:13, Bernhard Schussek <[email protected]>wrote: > Hi dear Symfony2 devs, > > I was pushed by several people to refactor the Form component to be > more decoupled and make better use of DI. Although I wasn't really > convinced of this approach at first, I decided to give it a try - and > am pretty satisfied with the results. Most of the features have been > refactored, but there are still details that need to be worked on. You > can find the current progress here: > > https://github.com/bschussek/symfony/tree/experimental > > Important: This is experimental. It is not decided whether this will > ever be merged into master. I also don't recommend to use this in any > application yet as CSRF protection is not ported yet. > > Thanks to Bulat for helping me. > > This post will outline the problems this refactoring tries to fix and > the benefits that we gain. Also, we need to find out how to deal with > the RC that is planned for next week. > > Fixed problems > ---------------------- > * The option implementation of Fields/Forms was buggy > * Forms could not be put into the DIC and retrieved from there > * Stubbing/mocking of Forms in controllers was impossible, because > they were created with "new" > * Dependencies where hidden inside configure() and could not be replaced > * Dependencies required in a field had to manually be added as options > of all parent forms (e.g. EntityManager) > * Field/Form by design contained lots of code that was relevant for > rendering only (getId(), getName(), getPattern() etc.) > * Because of the monolithic inheritance structure, it wasn't possible > to create fields that inherit the rendering of for example TextField > but the behaviour of another field > * Rendering was unflexible. It wasn't possible to override for example > the "row" template for a specific field type (needed for > RepeatedField, inline forms etc.) > > Additional advantages > -------------------------------- > * Fields and their renderers are now completely separated > * Rendering is more concise and flexible > * All fields of a specific type (e.g. text fields) used in an > application can be overridden/extended > > (probably more that I forgot right now) > > I want to explain how form creation and form rendering work with the > changed approach. Note that not all of the stuff I'm explaining here > is complete yet. > > Form handling > --------------------- > To create a form, you implement a form factory in your bundle. This > factory could look like this: > > https://gist.github.com/842827 > > Binding will look like this: > > https://gist.github.com/843094 > > And rendering something like this: > > https://gist.github.com/843115 > > Rendering improvements > ------------------------------------ > The most interesting part I believe is the rendering. As you can see, > we passed $form->getRenderer() to the template. This renderer encloses > variables and methods that are available there. Example variables are > "id", "name", "value", "class" etc. The methods are "errors", > "widget", "label", "row" and "rest". > > Each field and form has exactly one renderer. Depending on the field > type, this renderer has additional variables set that can be used in > the template. The renderer of a money field, for example, offers the > additional variable "money_pattern". The renderer of a form offers > "fields", "visible_fields" etc. All these variables can either be > statically set on the renderer by calling setVar(), or dynamically > using renderer plugins. They can also be overridden when calling > individual methods of the renderer, like "widget". > > In form themes, these variables are available as global variables in > the blocks of the field: > > {% block money_field %} > {{ money_pattern }} > {% endblock %} > > In normal templates, you can access the variables as properties of the > field renderer: > > {# Assuming the field "price" is a money field #} > {{ form.price.money_pattern }} > > As said above, each renderer also offers rendering methods. With > > {{ field.widget }} > > for example, you can output the widget of a field. You can also > override any of the variables in the call. > > {{ field.wigdet({ 'money_pattern': '...' }) }} > > Unlike before, there is no difference between HTML attributes and > template variables anymore. Each HTML attribute that should be > settable must be available as variable, for example: > > {{ field.wigdet({ 'class': 'myclass' }) }} > > {% block money_field %} > <div class="{{ class }}"> etc. > > Because renderers are simple PHP objects, you can extend them and add > functionality. You could implement this renderer > > https://gist.github.com/843139 > > and create a new form theme with a "help" block. You can then call > > {{ field.help('My help text') }} > > on all fields that have your custom renderer set. It is also possible > to override the renderers of all core fields to add functionality > globally. > > An interesting default rendering method is "rest" (not implemented > yet, if you have better names tell me). Because each field has a > stateful renderer, we can track which field was rendered at least > once. With > > {{ form.rest }} > > you can render all fields that weren't explicitely rendered. This > replaces the "hidden" helper and solves lots of other problems. If > you, for example, forgot to render the hidden fields in a subform, > these will be rendered here. If you added a field in the PHP code, but > not in your template, it will be rendered here. The designer will > notice the problem and manually render the field correctly. > > What about PHP rendering? > ---------------------------------------- > So far I've only talked about Twig. All renderers are connected to a > theme (an instance of ThemeInterface). By default, the component ships > with TwigTheme. By exchanging this object, you can either change the > template(s) used as themes or the whole theming engine. You could > implement a SmartyTheme that renders form fields using Smarty. Note > that the theming engine of the form and the templating engine where > you render the form are independent! > > For example, currently there is only a TwigTheme, but you can render > it in PHP template nevertheless. Just pass the form renderer to the > template and use it like in Twig: > > <?php echo $form->getWidget() ?> > <?php foreach ($form['visible_fields'] as $field): ?> > etc. > > I will cut this post for now. See my implementation if you want to learn > more. > > Conclusion > ---------------- > Because of DI, lots of problems in the form architecture could be > fixed and the rendering could be significantly improved. The reason > for this is that Twig and other dependencies can now be injected. > > Of course, there are problems too: The biggest one is that RC1 is > planned for next week. Most of the existing unit tests are green > again, but there are still lots of smaller things that need to be > fixed/worked on, and this won't be done next week. > > I am very confident though that this refactoring can be finished very > soon. Most of the existing features have been ported, for the > remaining ones (FieldFactoryGuesser, CSRF protection and > CollectionField) I don't see any showstoppers - it just needs to be > done. > > What I need: > ------------------ > * to know whether you want to see this in the first Symfony2 release. > Delivering it in later releases will be difficult because this is a > major BC break > * input. I have considered a lot of feedback in this refactoring that > I have got lately, but more input is always better. > * help. If you have time to help, you are very welcome. > > > Best wishes, > Bernhard > > -- > Software Architect & Engineer > Blog: http://webmozarts.com > Twitter: http://twitter.com/webmozart > > -- > If you want to report a vulnerability issue on symfony, please send it to > security at symfony-project.com > > You received this message because you are subscribed to the Google > Groups "symfony developers" group. > To post to this group, send email to [email protected] > To unsubscribe from this group, send email to > [email protected] > For more options, visit this group at > http://groups.google.com/group/symfony-devs?hl=en > -- If you want to report a vulnerability issue on symfony, please send it to security at symfony-project.com You received this message because you are subscribed to the Google Groups "symfony developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/symfony-devs?hl=en
