Updated: Comment #N
Problem/Motivation
Right now EntityManager calls out to \Drupal::formBuilder() in its getForm() method.
EntityManager is a service, the rest of its dependencies are injected except FormBuilder.
When trying to make FormBuilder an explicit dependency of EntityManager, I got this:
Circular reference detected for service "url_generator", path: "router_listener -> router -> router.dynamic -> url_generator -> route_processor_manager -> route_processor_csrf -> csrf_token -> current_user -> entity.manager -> form_builder -> url_generator
The functionality of getForm() is NOT actually related to what EntityManager does, and it only uses public methods. It is really just a wrapper around the entity manager's getFormController and the FormBuilder.
Proposed resolution
Make a separate EntityFormBuilder service, breaking the circular dependency.
Remaining tasks
N/A
User interface changes
N/A
API changes
EntityManager::getForm() is moved to EntityFormBuilder::getForm(), with no changes
ControllerBase gets a new entityFormBuilder() method
Comment | File | Size | Author |
---|---|---|---|
#17 | entity-form-2183923-17.patch | 41.08 KB | tim.plunkett |
#15 | entity-form-2183923-15.patch | 41.13 KB | tim.plunkett |
Comments
Comment #2
tim.plunkettUpdated the issue summary, and changed approach.
Comment #3
tim.plunkettComment #4
dawehnerI do consider this as a duplicate of #2182055: Comment module causes Circular reference error on a REST request. The actual issue is that the user is authenticated way to early.
As a developer I would totally not understand why entity forms as sooo different to entity lists or entity view builder. This fix sort of just fixes the symptons of the issue. The real fix would be that the current user is actually some sort of factory and the authentication manager is injected via setter injection. Damian wanted to work on it.
PS: please also try to provide the code you did to get to this statement.
Comment #5
dawehnerOh btw. I think that using setter injection for the form builder would already solve it.
Comment #6
tim.plunkettI ran Drupal\basic_auth\Tests\Authentication\BasicAuthTest locally with the patch from https://qa.drupal.org/pifr/test/715563, that's how I got it.
They all use Drupal\Core\Entity\EntityControllerInterface. Entity forms use Drupal\Core\DependencyInjection\ContainerInjectionInterface, because that's what FormInterface uses.
So they are separate, and I think that's fine. The EntityManager has getFormController, I don't really think the formBuilder parts of it are relevant to EntityManager at all.
Comment #7
tim.plunkettYes, setter injection would also "solve" it. But when do we use setter injection on services? And how does that make form building part of entity managing?
Comment #8
dawehnerIt seems to be quite common, especially for core, to build entity forms on arbitrary controllers.
So why don't we just inject the entity form builder now? We already have quite a lot of services in your create method.
Comment #9
tim.plunkettRerolled.
1) We need this for all 'add' forms, as well as other custom usages like Views UI.
2) This follows the pattern for other dependencies exposed by ControllerBase. It won't be as bad when #2110501: ControllerBase should implement ContainerInjectionInterface like FormBase is finally committed.
Comment #11
tim.plunkettUpdated for #2164827: Rename the entityInfo() and entityType() methods on EntityInterface and EntityStorageControllerInterface
Comment #12
dawehnerWell, I think that using ControllerBase for the sake of a single service is not worth it. Declaring explicit dependencies is still far better.
Comment #13
alexpottentity-form-2183923-11.patch no longer applies.
Comment #14
xjmComment #15
tim.plunkettRerolled, conflicted with #2110501: ControllerBase should implement ContainerInjectionInterface like FormBase
Comment #16
alexpottentity-form-2183923-15.patch no longer applies.
Comment #17
tim.plunkettJust a context conflict with #1857442: Make $values optional on entity_create, no changes.
Comment #18
dawehnerIt feels wrong to not edit the issue all the time :P
Comment #19
alexpottCommitted fe61b43 and pushed to 8.x. Thanks!
Comment #20
slewazimuth CreditAttribution: slewazimuth commentedBefore this change:
$advancedtour = $this->manager->getStorageController('advancedtour')->create(array());
return \Drupal::entityManager()->getForm($advancedtour);
Worked just fine.
However now with getForm function moving to EntityFormBuilder :
$advancedtour = $this->manager->getStorageController('advancedtour')->create(array());
return \Drupal::service('entity.form_builder')->getForm($advancedtour);
produces the error:
Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException: The "advancedtour" entity type did not specify a "default" form class. in Drupal\Core\Entity\EntityManager->getFormController() (line 206 of C:\wamp\www\d8_feb09\core\lib\Drupal\Core\Entity\EntityManager.php).
Adding a default form to the annotation of the advancedtour and clearing the cache changed nothing. Still getting the error. Suggestions?
Comment #21
slewazimuth CreditAttribution: slewazimuth commentedNevermind, figured it out.