Problem/Motivation
A form used for the _entity_form route property must inherit from EntityForm, not FormBase.
This should be documented.
Steps to reproduce
Try it.
You get:
Error: Call to undefined method MyEntityForm::setModuleHandler() in Drupal\Core\Entity\EntityTypeManager->getFormObject() (line 230 of core/lib/Drupal/Core/Entity/EntityTypeManager.php).
Drupal\Core\Entity\EntityTypeManager->getFormObject('group', 'member-bulk-edit') (Line: 82)
Drupal\Core\Entity\HtmlEntityFormController->getFormObject(Object, 'group.member-bulk-edit.default') (Line: 76)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
Proposed resolution
Throw exception when form handler doesn't implement EntityFormInterface
Remaining tasks
Review
User interface changes
None
API changes
None
Data model changes
None
Release notes snippet
None
| Comment | File | Size | Author |
|---|
Issue fork drupal-3205577
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #7
joachim commentedComment #9
longwaveShould we add a runtime assertion so anyone who makes this mistake gets a better error message?
Comment #10
aditi saraf commentedi will work on this ..
Comment #11
aditi saraf commented@Joachim i am not able to reproduce this issue .
Comment #12
joachim commentedI can still see the call to setModuleHandler in getFormObject(), which AFAICT isn't in FormBase.
Comment #13
xdequinze@joachim, I am trying to understand the issue. Would you like to provide more details about it ? What are you trying to achieve ?
Comment #14
joachim commentedIf you define a route that uses an entity form, you use '_entity_form' in the route definition, and set a form class name as a value.
If your form class inherits the standard form class base, it crashes.
The docs for _entity_form in entity.api.php should say that you need to use a specific base class.
Comment #15
anjali rathodComment #18
acbramley commentedEncountered this in #3461700: Allow vocabulary overview form class to be overridden and I agree we should improve this by throwing an error. I don't think this is novice based on the test coverage required.
Comment #19
acbramley commentedComment #20
joachim commentedThe check in core/lib/Drupal/Core/Entity/EntityTypeManager.php is not what I was expecting, and it's a good idea because it'll give a better error for people who use the wrong sort of form class as an entity handler.
But it won't catch the case where you use _entity_form directly in a route definition.
Comment #21
acbramley commentedIt does catch it, try adding this (mimics VocabularyRouteProvider::getOverviewPageRoute)
EntityRouteEnhancer::enhanceEntityFormsets the controller tocontroller.entity_form:getContentResultbased on the_entity_formdefault. That callsHtmlEntityFormController::getFormObjectwhich callsEntityTypeManager::getFormObjectThe
_entity_formroute default is tied directly to the form handler class.Comment #22
joachim commentedAh, I hadn't spotted that!
The exception message will be wrong in that scenario though:
> 'The "%s" form handler of the "%s" entity type specifies a class "%s" that does not extend "%s".'
because it's not been caused by a form handler.
Comment #23
acbramley commentedThe form handler is the second part of the _entity_form string, e.g the example above maps to the overview form handler of the Vocabulary entity type.
I also wondered if we should just through the error when the entity type is parsed, but technically at the moment you can have form handlers that aren't tied to routes and therefore don't need to implement the interface.
In Vocabulary's case it had the form handler but the route for it isn't using the _entity_form method and afaik form handlers aren't used in many other ways?
We also might need to throw a deprecation first before a full exception so sites don't blow up?
Comment #24
joachim commented> I also wondered if we should just through the error when the entity type is parsed, but technically at the moment you can have form handlers that aren't tied to routes and therefore don't need to implement the interface.
In that scenario, is there something like DefaultHtmlRouteProvider setting up the route?
Or are there entity types that specify a form handler for a form that's only shown embedded in something else?
Comment #25
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #26
acbramley commentedComment #28
smustgrave commentedReviewed the CR and pretty straight forward and warns it must use EntityFormInterface
Test coverage is here https://git.drupalcode.org/issue/drupal-3205577/-/jobs/7267720
Fixed the title and component best I could
Comment #29
longwaveAs it has a CR and there is an outside chance someone was doing something weird before, let's get this into 11.x/11.3.x only.
Committed and pushed 9976cfec451 to 11.x and 6e88a2d4084 to 11.3.x. Thanks!
Comment #34
joachim commentedI'm not sure we needed a CR here!
Previously, using the wrong form caused a PHP error -- ie a crash. Now it causes an exception with a clearer message -- still a crash (but a better one).
> Previously, if a form handler was used in an _entity_form route definition and didn't extend EntityForm, an obscure error was reported
'reported' implies it was logged, rather than what it was -- a crash.
Comment #35
longwaveIt's probably unlikely but if we didn't check the interface then it's still possible someone has implemented the necessary methods without it? Still, it's largely a DX improvement and 11.3 is out next month so I think it makes little difference.