Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
#1913084: Introduce a Form interface for building, validating, and submitting forms adds a standard form interface.
We already have EntityFormControllerInterface for entity forms, but it comes strangely coupled to entity_get_form(), entity_form_state_defaults(), and entity_form_id().
Once that issue is in, we should convert the existing forms to comply with FormInterface.
Comment | File | Size | Author |
---|---|---|---|
#54 | entity-form-controller-1913618-54.patch | 97.89 KB | tim.plunkett |
#54 | interdiff.txt | 1.57 KB | tim.plunkett |
#51 | entity-form-controller-1913618-51.patch | 97.62 KB | tim.plunkett |
#51 | interdiff.txt | 606 bytes | tim.plunkett |
#49 | entity-form-controller-1913618-49.patch | 97.76 KB | tim.plunkett |
Comments
Comment #1
tim.plunkettThis is also blocked on the changes in #1913742: Allow custom form state to be passed to entity_get_form()
Comment #2
tim.plunkettThat's all in now.
Comment #4
tim.plunkettWhoops. Made unneeded changes to EntityFormController::validate(), it's now untouched.
Comment #5
plachIt seems that most of the changes in this patch are originated by this hunk, which is not strictly required to implement
FormInterface
. Although it'll improve DX I'm afraid it has also the potential for introducing misalignments between the form controller and the form state entity references. This seems a bit out of scope here. We decided not to wrap the form state into the controller for similar reasons, see #1499596-96: Introduce a basic entity form controller.Do you think this change is necessary here?
Btw, this is the issue the linked post is referring to: #1728812: Prevent entity form controllers from being cached twice (in $form and $form_state).
Comment #6
tim.plunkettYes, that will be required. This patch was just the set-up for a conversion, I didn't actually switch anything.
Ideally #1913856: Convert Views UI forms to use FormInterface will go in soon, and I can convert one of those.
The eventual goal is a method on the form controller itself that can be addressed by a route. I need to talk to fubhy about his idea to put controllers in the DIC for that.
Comment #7
tim.plunkettSo this hardcodes a form controller to a route, which is not what we want, but is all I can do right now. Just a proof of concept.
Also, entity.inc contains entity_form_submit(), which mimics drupal_form_submit(). That seems like a huge hack, and to prove that point, it's only used by openid module to spoof a user registration.
I've also completely removed $form_state['entity'], so that there is only one place storing it. Either use $this->entity within the controller, or $form_state['controller']->getEntity() outside it (which should have been done anyway, since currently the location its stored in the form_state was variable!).
Comment #8
plachIsn't this out of scope wrt the straight conversion?
Removing
$form_state['entity']
and unifying the way we retrieve an entity in the form workflow was one of my original goals when working on the initial EFC patch, so I'm largely +1 on this. Moreover, in light of #5 this looks like the only sensible thing to do, although it makes the form controller a stateful object. I'd like to see what @fago thinks of this, since it was one of the points we discussed more.I guess we should use an injected entity manger to retrieve the needed controller in these cases. Similar issue: #1919322: entity_load_unchanged() should be part of the storage controller.
Comment #9
tim.plunkettSure, we can punt on actually using this correctly from routes, and continue to call entity_get_form(). It needs to happen, if you want a follow-up that's fine.
I'm not sure what you mean by injecting the manager, the referenced issue mentions it but doesn't explain it and the patch doesn't seem to do it.
Comment #10
plachNo strong preference on this, it's just that I can do a quite solid review of the form controller related code, but I have nfi of what the Views stuff is doing :)
I mean that by calling
entity_*_controller()
we are relying ondrupal_container()
, instead of having a properly injected entity manager. This makes unit testing stuff harder/dirtier.Comment #11
tim.plunkettOkay, I took a new approach.
I added EntityManager::getForm(), which is essentially OO-ified entity_get_form().
The best example of this is in the the user module (UserRouteController is now completely removed):
This works for Views' use case, so I'm reasonably happy with this.
Comment #13
tim.plunkettFix two views bugs.
Comment #15
tim.plunkettWhoops, I forgot to commit my fix to that logic before uploading. This should pass, so unassigning. Reviews please!
Comment #16
tim.plunkettWrong interdiff, right patch.
Comment #17
tim.plunkettTagging.
Comment #18
tim.plunkett#15: vdc-1913618-14.patch queued for re-testing.
Comment #19
andypostSuppose better to have entity type the leading name - {entity}_form__{bundle} and bundle (sub type) as context like hook_forms() usage
Suppose D8MI would like to pass lang_code here.
So third argument could be used for default values and having $entity as mixed parameter looks bad
great!
Nice clean-up but settings title from form controller is bad
This makes embedding of the form much harder. Not sure it's nice idea to affect page level elements from controllers!
Are you sure to move this to request level? needs code comment and mention in change notice
Comment #20
tim.plunkettOut of scope, see #1919930: Bundle entity form IDs violate module namespaces (both on server-side + front-end CSS)
That's fine if they so desire, but there is no need for it right now. It can be added.
Yes, putting drupal_set_title() in there is not optimal. Either #1830588: [META] remove drupal_set_title() and drupal_get_title() or #1889790: [Meta] Allow modules to register links for menus, breadcrumbs and tabs (if not with hook_menu) will have to handle that.
I'm rerolling this to take advantage of the recent routing/form patches.
This now depends on #1938980: Fix Ajax system; the last remnants of the old API must be swept away, and this is just the first pass.
I need to add docs, and figure out how to inject dependencies into a route enhancer.
Comment #22
tim.plunkettOkay, we should be good to go again.
Leaving assigned so that it gets rerolled once the enhancer issue goes in, but otherwise I think this is fine.
Comment #24
tim.plunkettI renamed getFormArg to getFormObject in one class but not the other.
Comment #26
tim.plunkett#24: entity-form-interface-1913618-24.patch queued for re-testing.
Comment #27
tim.plunkettOkay, this is now green, and blocked on #1938980: Fix Ajax system; the last remnants of the old API must be swept away
Comment #28
tim.plunkettThat went in.
Comment #29
tim.plunkettTagging for a review of the WSCCI bits here.
Comment #30
twistor CreditAttribution: twistor commented*used
This is weird. Clever, but weird.
Doesn't $entity have to be a string here?
So forms that aren't base forms can implement the BaseFormInterface?
Also, "The unique string identifying the form." seems redundant.
Comment #31
tim.plunkettI'm glad you think its clever. Not sure if its too weird :)
I suppose that could be just else, no elseif.
That redundancy is a reroll slip-up, I'll fix that and the typo later.
Also, YAY, that passed!
Comment #32
EclipseGc CreditAttribution: EclipseGc commentedThis just seems odd to me. I mean I get what you're doing here, but the name convention makes me think that FormInterface should extend BaseFormInterface. Maybe this could be BaseFormIdInterface? Does this need to be disconnected for the EntityFormControllerInterface?
$arg .= '.default';
Also not really ok with that line. It sounds like you aren't either so I'm just ++ing changing that line.
In general the updates to the implementations all look very sane. The actual changes to the EntityFormController itself give me pause since the updating process of the entity on the actual class is a sticky thing. It LOOKS right to me, but I don't feel comfortable being the person to rtbc this for that specific reason alone. The rest of it looks pretty good to me and like a good improvement. My one other question is just that it appears we now have a buildForm(), build() and form() methods and that gives me pause as well. Can you explain that a bit?
Eclipse
Comment #33
tim.plunkettThis replaces EntityFormControllerInterface::build() with FormInterface::buildForm().
EntityFormController::buildForm() calls:
EntityFormControllerInterface::init() to set up the form state and the entity
EntityFormControllerInterface::form() to build just the input elements
EntityFormControllerInterface::actionsElement() to allow easier adding of actions (submit/validate)
I've been very very tempted to move actionsElement() up to FormInterface, but as a protected helper method, it would need to be on a base form, and most of the awesomeness of FormInterface is that its an interface, and you can continue extending whatever base class you need. So I think we just need improved docs on EntityFormControllerInterface::form(), and leave the flow as is.
BaseFormInterface is poorly named, I'll revisit that.
I'm leaving the '.default' thing, according to the current structure of form controllers, its still necessary and that's a nice way to handle it.
This is the equivalent of entity_get_form($node), instead of entity_get_form($node, 'default').
I'll have a new patch up this evening, still leaving at needs review for more feedback.
Comment #34
EclipseGc CreditAttribution: EclipseGc commentedok, but entity_get_form() does pass 'default' as the second parameter already in a default. Is this strictly necessary? If so I'll happily drop the topic. It's a pretty minor point and what you're doing is definitely not prone to error, so I don't have complaints other than it's sort of weird looking.
Ok, so build() is gone, buildForm() is in its place, and the call to form() is permanent? or a temporary shim you want to revisit. Just trying to be clear here, I'm cool either way.
Definitely let's not put the actions thing on FormInterface, I think it's working perfectly without that right now. :-)
Eclipse
Comment #35
tim.plunkettYes, entity_get_form() passes 'default', but that's only when the procedural function is called.
When addressed from a route, its cannot be added in as a default, and these 2 lines handle all of the different cases.
Yes, form() is not temporary, it will stay.
Comment #36
Crell CreditAttribution: Crell commentedJust a quick skim through...
This seems redundant...
I don't even understand the purpose of this... That may help in coming up with a better name.
It took me 3 reads to figure out that $arg was actually the name of a form. Can we call it something more descriptive, like, $form? $form_def? Something with "form" in it?
Comment #37
tim.plunkettThis addresses #30, #32, and #36, thanks!
Comment #38
ParisLiakos CreditAttribution: ParisLiakos commentedThis looks awesome! i think it is very RTBCable.
Just two reallyy minor points:
why is the conditional needed?
This inheritdoc wont be parsed, cause it contains additional description..can we have it old style like below?
Comment #39
tim.plunkettsetOperation may be called later with NULL (happens in the Views UI) and we don't overwrite the old value. Added a line to that effect.
Good point about {@inheritdoc}, fixed that, some wrapping, and some ambiguous variable names.
Comment #40
ParisLiakos CreditAttribution: ParisLiakos commentedEdit, Nvm
Comment #41
ParisLiakos CreditAttribution: ParisLiakos commenteda lot better now:)
Comment #42
tim.plunkett#39: entity-form-interface-1913618-39.patch queued for re-testing.
Comment #43
alexpottNeeds a reroll
Comment #44
amateescu CreditAttribution: amateescu commentedRerolled.
Comment #46
amateescu CreditAttribution: amateescu commented#44: entity-form-interface-1913618-44.patch queued for re-testing.
Comment #47
ParisLiakos CreditAttribution: ParisLiakos commentedback to rtbc
Comment #48
tim.plunkettReroll for patch context conflicts, no actual changes.
Comment #49
tim.plunkettGit is smart.
Rerolled after #1820414: CHANGE NOTICE: Move views_ui.module directly into /core/modules/, it figured it all out for me.
Comment #51
tim.plunkettLIES.
Comment #52
tim.plunkett#51: entity-form-controller-1913618-51.patch queued for re-testing.
Comment #53
alexpottCouple of minor nits otherwise looks great...
Lets use Drupal::service() here
The comment no longer seems to be true...
Comment #54
tim.plunkettRoger that.
Comment #55
alexpottCommitted 620d497 and pushed to 8.x. Thanks!
Comment #56
dawehnerFollow up bug: #1983164: Entity Forms in ajax requests don't find the route
Comment #57
Crell CreditAttribution: Crell commentedComment #58
tim.plunkettI updated https://drupal.org/node/1734556, and also opened #2015923: Clean up entity form functions.
Comment #59
plachI updated the change notice to fix
::getEntity()
calls in a couple of examples.Comment #60
andypostSo what is better approach now:
1)
$form_state['controller']->getEntity()
?2)
$this->entity
?Comment #61
tim.plunkett1) is for hook_form_alter()
2) is for your class.
Comment #62
andypostMension about it https://drupal.org/node/1734556/revisions/view/2722135/2722977
Comment #63
tim.plunkettComment #64
plachLooks good to me as well, thanks, just replaced
FormInterface
withEntityFormControllerInterface
:)Edit: Oh, well, I added another example ;)
Comment #65
tim.plunkettOpened #2022875: Resolve difference between submitForm(), submit(), and save() in EntityFormController