Closed (fixed)
Project:
Drupal core
Version:
11.1.x-dev
Component:
entity system
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
23 Oct 2023 at 18:31 UTC
Updated:
14 Nov 2025 at 17:46 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
berdirComment #4
amateescu commentedWould this be a good time to do #3048483: Explore splitting entity type definitions into two storage/non-storage related definitions as well?
Comment #5
berdirI'd rather not mix that. This only affects the attribute/discovery class. We then get all values from it and instantiate the definition object form it, those two are completely disconnected apart from sharing the same properties (for the most part). While some options related to that were discussed, the current discovery only supports a single class and a discovered definition currently also needs to be a single array/object thing.
I would expect the BC implications of that issue massive also on the entity type level, this doesn't affect it at all, what you interact with once plugins are discovered is 100% identical to before. Even the build and alter hooks 100% identical to before.
Comment #6
berdirComment #7
longwave+1 to only doing 1:1 mappings from annotations to attributes in these conversion issues, otherwise we risk dragging them out when we want to get them all done reasonably quickly. If we want to refactor them later at least attributes will hopefully make that easier.
Comment #8
andypostComment #12
bbralaI'm testing out some automation.
Got dev branch from drupal-rector:
composer require palantirnet/drupal-rector:dev-feature/annotation-configentitytypeAdded a rector.php
Then ran rector in core (my setup is with joachim's core dev setup):
vendor/bin/rector process repos/drupal/core/Opening a seperate MR to see how it does.
Comment #14
bbralaPhp didn't want to run locally.
Phpstan wasn't happy with missing \ for the translatable markup. Manually fixed those.
There might be more needed, but out of time.
Might try later.
Comment #15
joachim commented> public readonly ?string $field_ui_base_route = NULL,
This doesn't belong in core, it's added by Field UI.
We discussed the problem of 3rd-party annotation properties in the original issue to add attributes to core, but I don't remember how it was decided it would be dealt with.
Comment #16
mstrelan commentedCan we let modules like Field UI define additional attributes on plugins?
#[Entity()]
#[FieldUIBaseRoute]
Comment #17
berdirIt's an existing, documented property, we're not introducing it here. I agree it shouldn't be here, but having multiple attributes is not supported by our parser and I don't see an easy way to introduce that. Field UI would then need it's own discovery and cache and it would be an API change to any code looking for that info.
The EntityType attributes class both defines an additional key where extra stuff can be put and also supports variadics for extra stuff that is then put it additional what of that exactly makes it in is still to be determined.
Comment #18
joachim commented> I agree it shouldn't be here, but having multiple attributes is not supported by our parser and I don't see an easy way to introduce that.
Is this going to break BC for modules which put their own top-level properties in entity annotations?
And what about the annotations we've already converted? I thought the general attribute issue was covering this and now it seems it hasn't.
Comment #19
ghost of drupal pastreturn !($value === NULL && ($key === 'deriver' || $key === 'provider' || $key == 'entity_type_class'));
maybe
return isset($value) || in_array($key, ['deriver', 'provider', 'entity_type_class'], TRUE);
alternatively
return isset($value) || isset(array_flip(['deriver', 'provider', 'entity_type_class'])[$key]);
Comment #20
berdir#18: This only affects the annotation/attribute discovery. alter hooks and resulting definitions work unchanged. That's exactly why we're trying to do this 1:1. It will not break/change until you convert your specific annotation to an attribute and whether or not there will be changed in the structure is still to be defined.
Comment #21
berdirRecent changes to discovery broke the ability to have subclasses. This is being implemented in #3420984: Convert Layout DisplayVariant, PageDisplayVariant discovery to attributes, so blocked on that.
Comment #22
godotislatePer suggestion from @alexpott on Slack, handling the subclass discovery changes in #3427388: Update Drupal\Component\Annotation\Doctrine\StaticReflectionParser::hasClassAttribute() to allow attribute subclasses. So that's the blocker instead of #3420984: Convert Layout DisplayVariant, PageDisplayVariant discovery to attributes.
Comment #23
kristiaanvandeneyndeI'm seeing the constructor for the attributes specify some strings as
?stringand others asstring. Yet for all but the $id parameter we specify defaults, making them all count as optional. This is why php and phpstan aren't throwing a hissy fit when we put parameters with question marks before those without one.Shouldn't we be consistent and mark them all as optional then? I just got bitten by this when I tried to copy this MR for Group and had some constructor args without default values, making both phpstan and php 8.1 explode.
Also, this means that you could technically create a new entity type by providing nothing but an entity type ID, right?
Comment #24
berdirphpstan is complaining, but it's on a level that core ignores atm. Your configuration might be more strict?
It's not a PHP error exactly because of named arguments, they can be in any order as long as they *are* defined, the phpstan error is just a consistency thing.
But I will most likely drop the current trickery anyway and re-define all properties on the child classes because I don't care about phpstan, but I do care about autocomplete support in PHPStorm and that can't handle this either.
* Note: There are tons of test fails because there are undefined named properties, that part is indeed not working, it might work if I implement logic that puts unknown stuff directly in aditional, will need to test. But I'm honestly also fine with just requiring that those need to move inside the explicit additional array. That's what happens after after discovery internally on the EntityType plugin definition class already now anyway (that is a different class than the one we use for parsing the plugin definition)
Comment #25
kristiaanvandeneyndeUgh, never mind. I forgot that the question mark means "You can omit this or specifically set this to NULL", whereas omitting the question mark while providing a default value means: "You can omit this or set this to something else, but not NULL"
Sorry, I confused myself.
Thanks for that, while converting to attributes I loved the autocomplete feature.
Comment #26
berdirI suspected already that this would be related to config entity cache tags.
There's an interesting and subtle change here between the way the annotation and attribute work. The entity annotation classes didn't really have any properties defined, we have them on the plugin definition object and were too lazy to do both. So the list_cache_tags property was by default NULL/not defined at all. Now we define it as an array with a default value of []. That means that \Drupal\Core\Entity\Attribute\EntityType::get() no longer filters out out, because an empty array is not NULL.
Then, \Drupal\Core\Config\Entity\ConfigEntityType::__construct() has this strange copypaste snippet from the parent that sets a default value to the $this->list_cache_tags before calling the parent constructor, so that the similar snippet there is skipped. However, no $definition has a list_cache_tags entry set to an empty array and replaces that again.
Fix is pretty easy, we just set the default on $definition['list_cache_tags'] if that is empty, instead of the completely bogus
if (empty($this->list_cache_tags)) {which at that point definitely always was empty.Note sure if there are other subtle differences like this, hopefully not as the plugin definition object should have property defaults for things, lets see if any test fails remain I guess.
Comment #27
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. 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 #28
godotislateApplied my own suggestions and rebased.
Comment #30
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 #31
berdirRebased. Rebasing this is pretty tough with the formatting commits, we might want to squash that all together. And just get it in asap.
Comment #32
kingdutchI realize this may be out of scope but #2813895: Combine entity type labels in an array has been open for a while and would be a breaking change in any existing system. However the conversion to attributes might be the perfect time to make the grouping since people will have to re-write their annotations anyway (so it's not more or less breaking than what we're already doing).
I only just came across that issue so sorry if this is a bit late in the process.
Comment #33
godotislatePer @Berdir in #31, it's probably best for this to land ASAP without additional blockers. Though maybe a compromise solution is to add support to set labels per #2813895: Combine entity type labels in an array now, convert maybe 1 entity type to confirm it works, then do the remainder of the conversion in the other issue? My thinking here would be something like this:
In the constructors of the new attributes, add
protected readonly array $labels = [],.Then in the
get()methods of theEntityTypeattribute:Or maybe do the mapping before the filtering so the property order is maintained.
Comment #34
joachim commented> It's an existing, documented property, we're not introducing it here. I agree it shouldn't be here, but having multiple attributes is not supported by our parser and I don't see an easy way to introduce that.
What do you mean by our parser?
Native PHP can read multiple attributes from a thing:
> Field UI would then need it's own discovery and cache and it would be an API change to any code looking for that info.
I don't see why we can't have the entity type manager (or indeed any plugin manager) read ALL attributes from plugin classes, and merge the definitions.
Comment #35
joachim commentedSomething like this would work?
Comment #36
godotislateCurrently attribute discovery only works with one attribute class passed from the plugin manager, though subclasses are allowed. Adapting for multiple attribute classes would be non-trivial.
In addition, if the idea is for something like a
FieldableEntityTypeattribute to live in thefield_uimodule and not core, then when field_ui is not installed, discovery will hit fatal errors trying to instantiate ReflectionClass on a class having an attribute of an unknown class.Comment #37
joachim commentedIt doesn't crash while you're just working with class names:
Comment #38
kristiaanvandeneyndeRegarding the $field_ui_base_route discussion: What if we move those to constants (or properties) with attributes on the entity type's class?
We could declare those as Attribute::TARGET_CLASS_CONSTANT and only look for them in classes that are tagged with the EntityType attribute.
E.g.:
Then we can do away with putting non-core properties on the EntityType attribute and immediately have a way for other modules to declare their own third-party properties on entity type definitions.
Comment #39
joachim commentedThis works in AttributeClassDiscovery:
What needs to be figured out is where we put 3rd party definition data on the EntityType definition object. For array definition plugins we just shove into the array! :D
Comment #40
joachim commentedProof of concept pushed to branch 3396166-convert-entity-type-extension-annotations.
Comment #41
godotislateNice! Though one additional thing that needs to be solved is to delete the plugin class data from APCU file cache when modules are installed or uninstalled.
That being said, I am +1 with @berdir and @longwave to getting this in as near 1:1 as possible so we can move the meta #3396165: [meta] Convert all core plugin types to attribute discovery forward and close in on deprecation #3265945: Deprecate plugins using annotations and plugin types not supporting attributes.
Comment #42
kim.pepperComment #43
joachim commented> Nice! Though one additional thing that needs to be solved is to delete the plugin class data from APCU file cache when modules are installed or uninstalled.
That's probably just a call to opcache_reset() in the extension system?
Though even without that, I don't think it matters:
- you uninstall module Foo
- plugins are re-discovered. Because the Foo attribute class is still in memory cache from the last discovery, Foo module's attributes are parsed and stored in the plugin discovery cache. But nothing is going to read them anyway.
- when opcache is eventually cleared, a subsequent re-discovery won't read the Foo attributes
I'm torn between making incremental improvements, and getting this right with attributes rather than carrying over a mess from the annotation system.
It also opens up lots of possibilities for plugins in general - there's a long-standing issue to get Views data handling declared on field type plugins, which is exactly the same problem of component and module hierarchy. That would be fixed by this concept too.
Comment #44
godotislateIt'd probably have to be
apcu_clear_cache(). That does reduce some of the advantage of using file cache, but modules probably aren't installed all that frequently.And the issue is on install (I spent a week and a half chasing down a test failure similar to this for migrate source plugins):
Comment #45
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 #46
quietone commentedComment #47
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 #48
godotislateRebased after tour removal.
Comment #49
catchI think we should be doing 1-1 conversions in the first pass, then splitting attributes in a follow-up. It will mean another layer of bc for the single-vs-multiple attribute definitions but it also means we can get off annotations quicker once core is fully converted and we start implementing deprecations for contrib. A new issue for multi-attribute-plugin-discovery would be great though.
Comment #50
joachim commentedThat sounds like a good roadmap to me.
One small problem is that I'd thought it would be good DX if supplementary attributes were not able to redeclare a property that's in the main plugin attribute:
If we later on want to move a property like field_ui_base_route to a supplementary attribute, we need a way to make an exception to that rule, for BC handling, because there will be a period when the property is in both the main attribute and the supplementary attribute.
That could fairly easily be done by marking the property with an attribute to say it's expected that it does that, but it's an extra piece of complexity.
Comment #51
joachim commentedComment #52
smustgrave commentedSeems to need a manual rebase.
Comment #53
godotislateRebased and resolved merge conflicts.
Comment #54
smustgrave commentedSwear I reviewed and marked this one yesterday but guess it didn't save :(
As this is approaching the 2 month mark of #needs-review-queue going to give my best shot.
Applied the MR and verified all instances of @ConfigEntityType have been replaced.
Reverted the change to Media.php to make sure annotation still works (it did)
Tried to pull from reviews from other convert tickets and believe the main points have been hit.
Appears all threads in the MR have been resolved so believe this one to be good.
Comment #55
quietone commentedComment #56
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 #57
godotislateRebased, back to RTBC.
Comment #58
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 #59
godotislateRebased again, back to RTBC.
Comment #60
godotislateSome test failures after rebasing.
Comment #61
godotislateTest fixed. Back to review to confirm changes after rebase.
Comment #62
nicxvan commentedThis needs another rebase I think.
Comment #63
godotislateRebased again.
Comment #64
nicxvan commentedI pulled this down and ran the same check as @smustgrave.
Everything seems good, and all @ContentEntityType's have been converted.
There are still a few references in comments, should those be cleaned up if the attribute is the way to go. If this should be a follow up then I think this issue is RTBC otherwise.
core.api.php:
entity.api.php:
EntityStorageInterface.php:
Example.php.twig:
Comment #65
smustgrave commentedThink we should address the comments here too.
Comment #66
smustgrave commentedWill try and keep an eye out for this one so maybe we can land it in 11.1, else believe we would have to wait for 11.2
Comment #67
godotislateUpdated comments in core/lib/Drupal/Core/Entity/entity.api.php and core/lib/Drupal/Core/Entity/EntityStorageInterface.php.
I think this file comes from chi-teck/drupal-code-generator and not in Drupal core?
The documentation here is not specific to entity types, and the three paragraphs+ of whole topic probably need a significant rewrite. I think that should be done in a follow up, if it's not already part of the Attribute conversion meta.
Comment #68
nicxvan commentedYou're right on Example PHP.
I think it makes sense to handle core.api.php documentation in a follow up since it isn't directly about this annotation.
I'll create a follow up issue on the parent meta issue.
I reviewed the other two comment updates and they look great now.
RTBC since it seems ready now!
Comment #70
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 #73
godotislateRebased, back to RTBC.
Comment #74
quietone commentedLeft some suggestions for comments on the MR.
Comment #75
godotislateApplied some suggested changes.
Comment #76
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 #77
godotislateRebased. Put it back to RTBC since that was where it was before the bot detected the merge conflict.
Comment #78
larowlanComment #79
larowlanThere's a couple of open threads on the MR
Pretty keen to see this in the beta
Comment #80
godotislateI believe all previous threads were addressed, but I can't resolve them because I didn't open the MR.
Will take a look at the new threads for the config entity attributes a bit later.
Comment #81
godotislateRemoved some unneed arguments from ConfigEntityType attribute constructor and rebased.
Comment #82
catchI think I found some additional ConfigEntityType constructor arguments we don't need. We might want a follow-up to try to rationalise these anyway?
Comment #83
godotislateUpstream issue fixed. Rebased and tests are green again.
@catch, @larowlan can you clarify the follow up requests?
Is to use constants/enums for common form keys such "default" and "delete"?
Is this to discuss restoring some properties that were removed?
Comment #84
catch@godotislate no I meant checking if there's anything else like
bundle_entity_typeto drop. There might not be.Comment #85
godotislate@catch Follow up created: #3487038: Confirm which ConfigEntityType attribute contructor arguments are needed.
Comment #86
nicxvan commentedOk I took a look, looks great!
I see no open MR comments other than for the follow ups.
There are two new things to do in a follow up:
1. Update docs around annotations: #3476278: Update *.api.php Annotation documentation
These are in core.api.php entity.api.php and EntityStorageInterface.php that I could find.
2. Trailing comma and bracket in these 10 files larowlan said we could address in a followup: #3487088: Fix trailing comma in entity type Attribute declarations
core/lib/Drupal/Core/Datetime/Entity/DateFormat.php
core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php
core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php
core/modules/config/tests/config_test/src/Entity/ConfigTest.php
core/modules/language/src/Entity/ContentLanguageSettings.php
core/modules/media/src/Entity/Media.php
core/modules/media/src/Entity/MediaType.php
core/modules/menu_link_content/src/Entity/MenuLinkContent.php
Comment #89
larowlanCommitted to 11.x and backported to 11.1.x, thanks all. See you in the followups.
Comment #91
chi commentedWhat was the reason that 'label_count' is moved away from other 'label_*' parameters?
Comment #92
chi commentedI think such a big change deserves a change record and 11.1 release highlights.
Comment #93
nicxvan commentedComment #94
claudiu.cristeaI can't find a change record for this. If an existing one covers also this change, could it be linked?
Comment #95
tr commented"I think such a big change deserves a change record"
"I can't find a change record for this. If an existing one covers also this change, could it be linked?"
I agree. No change records mention ContentEntityType, for example, or any other of the types changed (in core) by this issue.
It is unclear to me whether I can use attributes for these types in 10.3 like with most of the other annotation->attribute conversions, or whether using attributes for these types is only supported in 11.1+. Usually that information is found in the change record.
The only change records that talk about annotation->attribute are:
Plugins converted from Annotations to Attributes in 10.3.0
and
Plugin implementations should use PHP attributes instead of annotations
The latter says Drupal 10.2, warns that not everything is done yet, and claims it will be updated with additional plugin types as they are converted in core. That hasn't happened.
Neither of these change records mentions any of the types converted by this issue.
Comment #96
quietone commentedYes, this was missed. A new CR is needed for the conversions made in 11.1. I can do that, unless someone else has started. No, I don't see an new draft CR, so I will proceed.
Comment #97
quietone commentedThe CR is published. It would be good to confirm it is correct.
Comment #98
kristiaanvandeneyndeTitle might make it a bit harder to find, but I saw that it follows a pattern from previous CRs, so I guess it's fine.
Comment #99
quietone commentedI see the followup created in #85
Comment #100
ressaI agree that such a big improvement deserves a 11.1 release highlight (as suggested by @chi) but it looks like it wasn't mentioned?
https://www.drupal.org/project/drupal/releases/11.1.0
Comment #101
joachim commentedThere's been a regression here:
label_count used to be a PluralTranslation, which enforced the keys:
Now it's just an array and there's no check of the keys:
Comment #102
joachim commentedFiled #3557963: [Regression] entity type label_count property no longer enforces its sub-properties.