Follow-up to #2490966: [Meta] Replace deprecated usage of entity_create with a direct call to the entity type class
Problem/Motivation
According to #2346261: Deprecate entity_create() in favor of a <EntityType>::create($values) or \Drupal::entityManager()->getStorage($entity_type)->create($values), entity_create() function is going to be deprecated so we shouldn't use it anymore. When the entity type is known we should directly call <EntityType>::create()
. What to do when the entity type is not known or is variable is upon discussions.
Beta phase evaluation
Issue category | Task |
---|---|
Issue priority | Normal because it's just about code cleanup and good practices |
Prioritized changes | The main goal of this issue is DX, performance and removing code already deprecated for 8.0.0. (Direct calls to EntityType::create are better than generic calls to entity_create for readability) |
Disruption | This change is not disruptive at all as it only replaces deprecated functions call by their exact equivalent. |
Proposed resolution
Replace the deprecated call to entity_create('config_test')
by a proper call to ConfigTest::create()
.
Edit: in this specific issue we must use the long chaining method, as the EntityTypeRepository::getEntityTypeFromClass()
is expected to work in 90% of the cases, but for the other 10% we should use the long chaining way. See #40 for a better explanation, and #38 with 2 similar patches using the different methods, failing only with the short one.
Before:
entity_create('config_test', $params)->save();
After:
\Drupal::entityTypeManager()->getStorage('config_test')->create($params)->save();
Remaining tasks
Task | Novice task? | Contributor instructions | Complete? |
---|---|---|---|
Create a patch | Instructions | Done | |
Manually test the patch | Instructions | ||
Review patch to ensure that it fixes the issue, stays within scope, is properly documented, and follows coding standards | Instructions |
User interface changes
None.
API changes
None.
Comment | File | Size | Author |
---|
Comments
Comment #2
Mac_Weber CreditAttribution: Mac_Weber as a volunteer commentedComment #3
Mac_Weber CreditAttribution: Mac_Weber as a volunteer commentedComment #5
Mac_Weber CreditAttribution: Mac_Weber as a volunteer commentedAs @xano pointed at another issue Tests must use
$this->container->get('entity_type.manager')->getStorage('config_test')->create()
.Comment #6
chx CreditAttribution: chx at Smartsheet commentedXano is wrong. https://api.drupal.org/api/drupal/core%21includes%21entity.inc/function/...
Comment #7
Mile23Depends on what you're testing.
In this case, the test depends on a test module which implements the entity. If we're testing the service discovery mechanism to that entity, then we'd say something like
$this->container->get('entity_type.manager')->getStorage('config_test')->create()
. If we're usingconfig_test
as a fixture to, for instance, feed into some other system, then we don't need (and probably shouldn't use) the service container or the type manager explicitly.So in the patch:
Here, we only care about the ability of the diff component to accurately diff two entities, so we don't need the rest of it, so it's proper to say
EntityTest::create()
.But let's look at the
create()
static used byconfig_test
we'll be calling (It lives in\Drupal\Core\Entity\Entity
):See how it just grabs the deprecated entity manager, gets its storage, and then uses it to create an entity, from the static
\Drupal
? The SimpleTest test base pokes the same fixture container as$this->container
into\Drupal
pseudo-global, enabling sloppy code like that. Meaning: Drupal 8 refuses to be opinionated on how you generate your entities, even though it should, as exemplified here: Not only what are we testing, but how can we test it without inadvertently testing a bunch of other things at the same time?Anyway. @Xano is mostly right in principle, but we'd have to be careful what we're really testing here, rather than explicitly exercising the service container in all cases.
I'd err on the side of using
ContainerTest::create()
because it's easier to type, and things will break more instructively later.Comment #8
Mile23As for a review: The patch in #5 applies and removes all but one occurrence of entity_create('config_test:
Comment #9
naveenvalechaAs we are sticking with the static methods for now. So please reroll the patch from #2
Comment #10
nesta_ CreditAttribution: nesta_ at La Drupalera by Emergya commentedApplying patch #5 and change line 43 for #8
Comment #11
dimaro CreditAttribution: dimaro at La Drupalera by Emergya commentedI checked with my IDE and its fine, there's no occurance left.
RTBC?
Comment #12
Mile23This kind of change still works but we want to use
ConfigTest::create()
rather than poking around the service container.We do this because the deprecation notes for
entity_create()
look like this:So:
Thanks.
Comment #13
Sriparna Khatua CreditAttribution: Sriparna Khatua as a volunteer and at Faichi Solutions Pvt Ltd for Faichi Solutions Pvt Ltd commentedComment #14
Sriparna Khatua CreditAttribution: Sriparna Khatua as a volunteer and at Faichi Solutions Pvt Ltd for Faichi Solutions Pvt Ltd commentedComment #15
rakesh.gectcrDidn't get update on this issue from more than 8days.
So i rerolled with patch.
According to our scope its should be replaced in the following way.
Comment #17
aditya_anurag CreditAttribution: aditya_anurag as a volunteer and at Valuebound commentedComment #19
heykarthikwithuComment #20
heykarthikwithuComment #23
anchal29 CreditAttribution: anchal29 as a volunteer commentedHere's a patch for it.
Comment #25
Mac_Weber CreditAttribution: Mac_Weber as a volunteer commentedIt seems the tests work fine for this issue with the long chaining method.
I am not sure if we should use it or not, as (at least) most of the other patches use the short method to call.
Comment #26
Mile23Patch no longer applies:
Also it's true that
$this->container
is preferred for tests.Some other review stuff:
There are probably other places like this where you could get the storage service once and then re-use it, but it's not a huge problem to leave it this way.
Why are we adding use statements but making no other changes in these files?
Comment #27
dimaro CreditAttribution: dimaro at La Drupalera by Emergya commentedRerolled #25.
I will work in points 1 and 2 on #25.
Comment #28
arunkumarkHi,
patch #21 is works fine as per depricated.
Comment #29
Mac_Weber CreditAttribution: Mac_Weber as a volunteer commentedPatch #27 does not fix the problems pointed at #26
Comment #30
sdstyles CreditAttribution: sdstyles at FFW commentedComment #31
naveenvalechaThe patch is not applying anymore.
Comment #32
naveenvalechaThe patch in #31, used the chain function but we are using the Entity static function for keeping the consistency throughout the core.
Comment #34
naveenvalechaThe patch failed b/c the https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21...
got the multiple definitions of ConfigTest entity.
Any suggested approach how to proceed with it with static functions ? instead of chain methods
Comment #35
Mac_Weber CreditAttribution: Mac_Weber as a volunteer commenteduse the long chain method as in #25 and it will work
Comment #36
tstoecklerComment #37
dimaro CreditAttribution: dimaro at La Drupalera by Emergya commentedReading the comments above on #34 and #35.
Finally, what we should use?
Comment #38
Mile23What's weird about this is that it works in all the other replacements from the meta.
The problem arises during Entity::create(), which ends up calling EntityTypeRepository::getEntityTypeFromClass() based on the calling class.
Somehow config_test can't be discovered properly during this process, from its class name.
However, as pointed out, if you use the plugin type ID, all is well.
Perhaps there's a problem with the plugin definition?
Setting to NR to trigger the testbot.
Comment #40
Mac_Weber CreditAttribution: Mac_Weber as a volunteer commented@Mile23 IKR. I found this same weird behavior in another issue of this meta. I had pinged other core developers at #drupal-contribute on that time and they told me that
EntityTypeRepository::getEntityTypeFromClass()
is expected to work in 90% of the cases, but for the other 10% we should use the long chaining way. I am still think this is weird, but this is the way it is right now.Changing it back to needs work because there are many other entries that have arguments and are not included in the previous patch.
Comment #41
Sutharsan CreditAttribution: Sutharsan commentedRemoving Novice tag because of the length of the issue.
Comment #42
dimaro CreditAttribution: dimaro at La Drupalera by Emergya commentedI upload this patch using the chaining way.
I checked in my IDE all occurrences and everything looks fine.
Does this patch go on the right way?
Thanks!
Comment #43
Mac_Weber CreditAttribution: Mac_Weber as a volunteer commentedLooks good, passes on tests, and do not have any missing occurrences.
Thank you @dimaro
Comment #44
heykarthikwithu+1 RTBC
Looks good, passes on tests :)
Comment #46
cilefen CreditAttribution: cilefen commentedMy first reaction to the current patch is that the issue title doesn't match the current plan (i.e. using the container). I see there was discussion and work done as to whether we should use the container or the static method. It looks like #38 contains explanations. In addition, in the very few other children of the parent I looked at, it was the static method. Is it correct that the static method was causing the test failures? If so, if the container is the way forward, could we add a brief explanation in the issue summary please?
Comment #47
xjmComment #48
Mac_Weber CreditAttribution: Mac_Weber as a volunteer commented@cilefen #40 has the explanation I got from other core maintainers. The patches at #38 shows that this issue with the short/long method is a real issue sometimes.
I'm marking the issue as RTBC, as other similar ones with long chain method are already applied to core by now and this one also looks good.
Issue summary updated, too.
Comment #49
xjmThanks @Mac_Weber.
I read over the thread here as well as the meta issue, and discussed this with @alexpott and @cilefen. Here's my feedback:
Thanks for the summary update. The summary still says the proposed resolution is to use the actual class, though, which contradicts the patch. The title also does not reflect the current patch.
Regarding:
What is an example? All the ones we looked at use the actual class, which is an architectural decision the framework and release managers made for these conversions.
Regarding:
That's not really an explanation, unfortunately.
Regarding:
Who recommended this? I'm fairly certain none of alexpott, catch, nor I would have recommended
$this->container
in tests since we're all aware of the bugs that have been caused because of it.@alexpott said regarding this issue:
So, we should use
\Drupal
here rather than introduce a risky pattern. Thanks!Comment #50
xjmTo clarify, we should replace it with
ConfigTest::create()
except where the alter hook leads to the exception... and try\Drupal::entityTypeManager()
only for the calls that would fail. And, possibly, file a followup to give the alter hook its own test implementation so it doesn't pollute other stuff.Comment #51
dimaro CreditAttribution: dimaro at La Drupalera by Emergya commentedThe latest patch no longer applies.
Reroll against 8.3.x
I will work on this to fix #49 and #50.
Comment #53
dimaro CreditAttribution: dimaro at La Drupalera by Emergya commentedOMG!
Upload again
Comment #54
dimaro CreditAttribution: dimaro at La Drupalera by Emergya commentedLooking at #49 and #50 I try to replace all ocurrences to
ConfigTest::create()
, however when i run the test locally I have some fails, so I try using\Drupal::entityTypeManager()
. I'm not sure if we want this, but could be a first approach.Comment #55
dimaro CreditAttribution: dimaro at La Drupalera by Emergya commentedUps! I forgot check as unassigned.
Comment #56
Mile23Use this pattern for methods that have a lot of calls to
entity_create()
:Then whenever the entity is needed, you'd do this:
Comment #57
pk188 CreditAttribution: pk188 at OpenSense Labs commentedI have changed it in two files where it is using multiple times. Please check whether i have done it correctly?
Comment #59
pk188 CreditAttribution: pk188 at OpenSense Labs commentedComment #61
andypostPlease move storage retrieval out of loop
get storage only once
Comment #62
anya_m CreditAttribution: anya_m as a volunteer and at Skilld commentedComment #63
andypostThere's no places left, so +1RTBC but needs to update summary
Comment #64
anya_m CreditAttribution: anya_m as a volunteer and at Skilld commentedComment #65
andypostGood to go now
Comment #67
xjmSo, this patch does not follow the instructions in #49 and #50. Please be sure to read the comments on an issue carefully as they will often contain important instructions about the patch.
In the case of this issue, the replacements are at least consistent since it's used only in tests, and the patch is small enough to be manageable. So, I decided to commit it as-is. Also, after this patch, there are only a few
entity_create()
calls left in core. Nice work!Committed and pushed to 8.5.x. I also cherry-picked it to 8.4.x since it only cleans up deprecated code usage in tests.
Note that a few people didn't receive issue credit when their uploaded patches didn't seem to help the issue's progress. To get credit in the future, make sure to read and take into account other comments on the issue, post your own comment explaining what you did and why, and provide an interdiff to help reviewers see the changes you made. These things will help everyone collaborate on fixing the issue.
Next up: We need to remove a few stray documentation references to
entity_create()
as well as a few calls that use a variable entity type. We can do that in new child issues of #2490966: [Meta] Replace deprecated usage of entity_create with a direct call to the entity type class. Hooray!Comment #69
rakesh.gectcr