Spin-off from: #1263478: Identify pieces of Drupal that could be replaced by Symfony code

Reasons

Converting the form system seems to make sense for several reasons:
1) less code to maintain,
2) one less drupalism,
3) decreased memory footprint [based on some basic comparisons]
4) lazy loading due to class loader

Details

- Symfony form component documentation - http://symfony.com/doc/current/book/forms.html
- Currently, the FAPI and render API are similiar, but not entirely the same. In order to use symfony2 form component the render API will need class components as well that will probably stay Drupal specific and simply work together with form API. Otherwise I suppose we would have to use templates for everything, unless there is some other existing mechanism to mimic the render API in symfony.

Tasks

- Determine what parts of the render API need to be mimicked as classes
- Evaluate wrapping Symfony validation and submit handlers with Drupal hooks vs using directly
- Work on a prototype

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

webmozart’s picture

I'm the maintainer of the Symfony Form component. Is there any way in which I can help with its evaluation or integration?

sun’s picture

btw, I spent some time tinkering about this, and I believe that Symfony's Form component would rather map to Drupal's Field API concept of field types/widgets/formatters, instead of Drupal's pure Form API.

@yched was or is working on converting Field API to the new unified plugin system though, which isn't based on any Symfony components AFAIK. (Some details in http://groups.drupal.org/node/195618)

Overall, however, I still think this is too much for D8.

(Although, admittedly, it slightly depends on the Twig template system implications and consequences on Drupal's theme system, render system, and thus also form system - if that's going to happen.)

webmozart’s picture

btw, I spent some time tinkering about this, and I believe that Symfony's Form component would rather map to Drupal's Field API concept of field types/widgets/formatters, instead of Drupal's pure Form API.

Why is that? As I don't know the Drupal Form API very well, which are the significant things you see missing? I'd be very interested in hearing your ideas about what should be improved.

I quickly read through the Form API Quickstart and the Form API Reference and found the general ideas behind Drupal's and Symfony's form system very similar:

  • Each form consists of a set of fields or subforms (fieldsets in the case of Drupal)
  • Fach field has a name, a type and some options
  • Field options control the way a field behaves and is rendered

A list of Symfony's interesting features for Drupal might be:

  • Each type (also core types) is completely encapsulated within a PHP class. Writing a custom type is as easy as creating a new class.
  • You can extend types using vertical inheritance (creating subtypes) or horizontal inheritance (augmenting an existing type and all of its subtypes).
  • Types take care of converting your data between the view and model representation. If dates are input using separate checkboxes, but represented as e.g. DateTime instances, the conversion will be done by the framework.
  • Forms can consume and produce both (potentially nested) arrays (like Drupal) and complex object graphs of POPOs. It is also easily possible to write custom data mappers that consume and produce graphs of EAV-objects or similar.
  • Validation using the Symfony Validator is very powerful. Optionally, validation constraints can be placed directly in the domain model (also POPOs), like seen in the Validator documentation.
  • Forms internally trigger events that you can attach listeners to. This way it is possible to dynamically modify individual forms based on e.g. the submitted data.
  • Forms integrate with other metadata of your model. For example, if a property is marked to be validated as not-empty email, the form guesses the field type to be "email" with the option "required" set to true. Custom guessers can be easily integrated.
  • Form processing and rendering is completely decoupled. The Form component deals only with form building, processing and validation and creates view objects that contain all view-relevant data. The rendering engine consumes these objects and displays the data in whatever way it likes. Symfony ships two renderer bridges, one for Twig and another for the PHP Templating component. Of course, you can omit these and write your own engine. Using type extensions you can easily augment Symfony's core types to bundle information required by your rendering engine ("collapsible", JS options etc.).

.
After two years of intensive development, the main Form API becomes stable in Symfony 2.1 which will be released soon. The documentation unfortunately does not reflect all of its capabilities, but I want to work on this during the summer and I can personally give support should you have any doubts.

Crell’s picture

I suspect it's the data binding logic in the Form component that sun is referring to, since Drupal has no such automatic equivalent at this point except the Widget portion of the Field API.

webchick’s picture

David Strauss was talking about this this weekend, worrying that at issues related to CMI I18N we are adding an awful lot to Drupal's form API that's already in Symfony's. I haven't evaluated either those patches or Symfony Form API to be able to comment on this, but figured I would raise it.

Crell’s picture

This is probably worth a BoF in Munich, especially if we can coax some Symfonians into attending. Maybe we can sneak someone in the back door just for a few BoFs? :-) I know Nils will be there, but he's a PHPBB guy primarily (which is also adopting Symfony).

I don't know either system well enough yet to have an opinion on the matter, other than it is worth considering, but would be an OMG huge change.

webmozart’s picture

Depending on the specific date of that BoF I could attend it to give you some insight into Symfony Forms.

Crell’s picture

DrupalCon Munich is August 20-24: http://munich2012.drupal.org/ Monday the 20th is a training day, but there are some side sprints being planned. Tuesday-Thursday is the conference, lots of of sessions and also lots of BoFs. Friday is a sprint day.

Technically only registered attendees can be on-site for Tuesday-Thursday, but the sprint day (and anything extra happening Monday besides trainings) is open to all. (If you want to register, tickets are still available! :-) )

webchick’s picture

Status: Active » Postponed

Ok, it's official: https://groups.google.com/forum/?hl=en_US&fromgroups=#!topic/symfony-dev...

Symfony has classified this as a component that they can't guarantee backwards-compatibility for 2.3 (the LTS release Drupal 8 will be relying on), which means this needs to be postponed until Drupal 9.

webchick’s picture

webchick’s picture

Also, I know there was some kind of meeting that happened at DrupalCon Munich with the creator of the Symfony Form component. Is there a write-up of that somewhere that could either be pasted or linked to from here?

effulgentsia’s picture

Here's the slides that Bernhard presented. There's no write up of the discussion we had that I'm aware of, but these slides are a very good start. Perhaps we can add more comments to this issue as we remember things from the discussion.

David Strauss’s picture

This comparison document is great. I think it makes a good case for moving to Symfony 2's form system as the natural, object-oriented successor to Drupal's Form API.

tim.plunkett’s picture

Version: 8.x-dev » 9.x-dev
Xano’s picture

Each type (also core types) is completely encapsulated within a PHP class. Writing a custom type is as easy as creating a new class.

I suggested something similar at DrupalCon Chicago, but the major criticism was a lack of flexibility. Now we can easily change a form element to another type by changing its #type property (and perhaps a few extra properties that are specific to the element type). With classes we'll have to throw away the existing object and create a new one. IMHO this might actually be a cleaner approach, but I believe performance was another objection.

webmozart’s picture

These problems are solved in Symfony2. Each type has a name (e.g. "text") and a corresponding object (e.g. TextType) that exists exactly once in your application (performance++). You have different alternatives for augmenting a type:

  1. Load a different class for type "text" by default (TextType won't even be created).
  2. Add a type extension for "text" which mixes in additional functionality on top of TextType.
  3. Use a different type, like "mail" or "custom_text".
  4. Use type "text" and modify the field at runtime.

1. and 2. are good ways of changing all fields using a given type. 3. and 4. are the preferred options if you want to change only specific fields.

chx’s picture

FileSize
468 bytes

I did a search on one word in this issue and in the PDF and having not found it, here's a patch to get you started. This will be my only contribution to this travesty.

That word, obviously, is "security". CSRF protection and the options checker should've been the first things to verify they survive, perhaps even improve. That noone here even mentions them shows priorities crystal clear.

stevector’s picture

Does anyone have the expertise/desire to submit this topic as a Drupalcon Portland Core Conversation? And potentially answer Chx's security concern?

Heyrocker is asking for D9 topics: http://portland2013.drupal.org/news/drupalcon-portland-call-core-convers...

David Strauss’s picture

I've submitted a proposal for Core Conversations for this discussion.

webmozart’s picture

Great! Unfortunately I won't be there, but I will support you as good as I can. Maybe you can also get a hold of Fabien who will be there.

Crell’s picture

I'd love to see Fabien in the Core Conversation track. He's already written more Drupal code than Lukas, who was in Core Conversations a year ago. :-)

stevector’s picture

David, your proposal isn't showing up at http://portland2013.drupal.org/program/sessions/proposed?field_experienc...

Did you submit it already?

David Strauss’s picture

I absolutely submitted it. This is the URL for me to see my submission (apparently not publicly available):
http://portland2013.drupal.org/node/3518/submission/1753

catch’s picture

Category: Task » Plan
Issue summary: View changes
Status: Postponed » Postponed (maintainer needs more info)
Issue tags: +Needs issue summary update

This would need actual review before there's anything to do. Last time I looked at Symfony forms (which was a while ago), it wasn't an improvement. I think we'd be better off with 'OOP render API' and applying that to our own form systm.

webmozart’s picture

If there's anything I can do to help or clarify your doubts, let me know.

sinasalek’s picture

This is certainly an interesting change, i used symphony form quite some time and it's truly a modern form API which makes maintaining and developing Drupal Form API pointless.
I disagree with @catch because that's awful lot of work implementing something similar from scratch, but agree about the actual reviews, i read the issue from top to bottom and does seem fully clear whether it's possible to use symfony form in Drupal core in a practical way or not, and the issue itself is pretty much outdated.
Considering the provided document by @webmozart, great deal of my questions are answered, so think the main question now is how i can be implemented in core, what are the obstacles and limitations that need to be addressed

catch’s picture

I disagree with @catch because that's awful lot of work implementing something similar from scratch

We have a form/render API that's been used in production for years, and have already moved most of the processing code from procedural code to services. It also supports the full set of features we need (apart from things it doesn't, for which there are open issues). Modernising an existing system is not the same thing as 'implementing from scratch'.

With the routing system, while much was made of how much code was shared, we had to port Drupal 6/7's actual routing algorithm because there was no scalable equivalent in Symfony, not to mention problems with access checking, link generation etc. which took months to resolve. The entire start to finish of the router conversion (once you include link generation, menu links) took nearly the entire 8.x cycle. Much of this was because there was an initial assumption that current routing had to be replaced wholesale, and a lack of attention to the features that the system as a whole needs to support, so that many were 'forgotten' and had to be re-introduced much later on.

We've generally done quite well out of low-level components like YAML parsing, or very specific things like serializers. Anything central to Drupal as an application like routing and forms needs to be approached much more critically.

dawehner’s picture

Yeah like the idea to move as much as possible to twig template just doesn't work with the way how Drupal deals with really generic forms. Drupal is not just a developer tool,
but also something for sitebuilders, which need additional abstractions. Just take config as example. In an ideal world we would just have everything in code, done. Sadly config and its capability to load more code after deploying configuration makes things more complex than an "unopinionated" component, like some of the symfony ones, can handle out of the box.

The form component itself is even more tricky because we partially have coupled the form system to the render system, so it can be really tricky.

sinasalek’s picture

@catch
That's true, but we're still using big arrays for creating forms.
I understand that Drupal has a lots of specific things that are considered unrelated to Symfony forms. But we don't have to use the Symfony form as it's. We can either extend it and add Drupal specific requirements or patch it to make it more extensible, that way we can inject Drupal specific requirements without having to directly extends it and then use it as a service. One of the examples is binding to an entity, which apparently works in a very different way that Drupal does.
My point is it might be better to offload maintaining form API of core maintainers shoulders :)

i think it's great that people like @webmozart with good knowledge about symfony forms are willing to help, we can certainly leverage that.

So what would be the next step for this? i think having a list of major roadblocks would help people join in, maybe someone can comeup with a solution that addressed your concerns, what do you think ?

AaronMcHale’s picture

More relevant discussion in that issue.

I was going to post something here but seemed better to post on that issue, comment #29 was roughly what I was going to post here.

xjm’s picture

Version: 9.x-dev » 8.8.x-dev

Under our continuous upgrade path and deprecation policy, feature and API additions should be added with backwards compatibility in minor releases, so moving to 8.8.x.

This would be especially difficult to solve given how intrinsic the form API is to Drupal core, but we'd have to come up with a way to ship both APIs at once for a major, or to allow FAPI as an alternative way to use the component, or something. I also remember that the component was not nearly as fully-featured as we needed, at least previously. In any case, it would have to be solved as a backwards-compatible API addition with the old API being deprecated somehow.

hchonov’s picture

If we were to touch the form API then let's ensure we have common grounds for the form API and and for decoupled Drupal. I really like the suggestion from #2913372: Allow forms to be defined in three segments: schema, UI, data:

Form arrays are a tight coupling of three concepts:

Schema: The fields represented by the form, their title, and their data type. Also includes validation definitions like "minimum value".
UI: The presentational information, like "radios vs select list". Also includes whether the element is disabled.
Data: The current values of the form (either default values, or the live values as they are changed by the user).
Separating these concerns will be essential to moving any form rendering to the client side.

Everyone would profit from such an architecture. The backend developers will then be defining forms for the Drupal form API and for decoupled clients the very same way!
Therefore they will be able to ship a different schema while leaving no work for the frontend, as with such an architecture it should be possible for it to use the corresponding components according to the schema.

This is going to simplify the form handling in a great way.

One of the firsts steps would be to first adapt our current form API to build forms out of such definitions. Afterwards a transition to another form builder whether from symfony or somewhere else should be rather easy.

Thoughts on that?

David Strauss’s picture

Since this is active again (and it's been seven years), I think we should also examine options with rich support for automatically saving work-in-progress and other modern functionality. I'm particularly interested in looking at the capabilities of AMP forms, which are being decoupled from dependence on actually running on AMP pages (as part of Bento AMP) and support more modern user interaction patterns (via XHR-style data-bound controls) than FAPI or Symfony forms (AFAIK).

I'm particularly curious if there's an elegant integration of Symfony forms with AMP form components. They're mostly distinct in what they handle, except for the data binding.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Chi’s picture

Drupal Form API hasn't got much attention since the issue has been created 8 years ago. Nowadays it seems very outdated. However migrating to Symfony Forms or to any other form component seems not realistic as it requires a huge amount of efforts. For the record, FormStateInterface consists of 92(!) methods. Also replacing Form API implies a major BC break. Looks like we have reached an impasse.

tim.plunkett’s picture

Create/introduce a new API alongside the existing one. Deprecate the existing one. Remove it in a future version.
Which is how we do all changes now in D8/D9+.

effulgentsia’s picture

Version: 8.9.x-dev » 9.1.x-dev

Since it will be a new API, 9.1 is now the earliest branch this can go into, so updating the Version field accordingly. That doesn't mean planning can't start/continue in the meantime. This will be a lot of work, so even if it's started now, I wouldn't expect patches to be ready for commit before 9.1 or later anyway.

Frankly, I'm not convinced that a major rewrite of Form API onto Symfony forms is worthwhile, but that's just my current opinion, and I'm happy to be convinced otherwise, or for others to take on the bulk of the work if they find it worthwhile.

In the long run (Drupal 10? Drupal 11?), I think we should replace our Form and Render APIs with JavaScript (Node.js), as I wrote about in #2645666: [policy, no patch] Require Node.js for a future Drupal major version and rewrite some of Drupal's UI code from PHP to JS. Perhaps that was premature then, and maybe still is, but I still think that at some point, the time will be right for that, and I think Drupal's more or less existing Form API can get us through in the meantime.

I'm very much in favor of #2913372: Allow forms to be defined in three segments: schema, UI, data though, as that would be beneficial for both the PHP API and the eventual JS API. I don't think that issue requires the Symfony form component, but if the Symfony form component makes that issue easier to implement, then great!

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Chi’s picture

Drupal Form API hasn't got much attention since the issue has been created 8 years ago.

Actually, that applies to Symfony Form as well. It is quite complex and looks outdated. The only benefit of using it is built-in integration with Twig and a few other Symfony components that we are already using (Http Foundation, Validator, Event Dispatcher).

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.