Problem/Motivation
The concept of base fields (e.g., "title" and "status" for nodes) is intended to model the situation where code needs to rely on a field existing and being of a certain type without relying on something in active configuration to make it so. For example, if node title and status fields were managed as configurable fields, then someone could run a config deployment that removed them, and that would result in a lot of code breaking.
However, there is no inherent requirement that nothing about base fields be configurable. For example, HEAD already allows the label of the node title field and the default value of the node status field to be configured, and stores that configuration within the NodeType
config entity.
#2143291: Clarify handling of field translatability is adding 'translatable' to FieldInstanceConfig, but is continuing to store translatability of base fields in its own YAML file. And #2224761: Add a generic way to add third party configuration on configuration entities and implement for field configuration needs to make 'translation_sync' configurable for both base and configurable fields, as well as provide contrib modules (e.g., Field Permissions) with a mechanism to add in their settings.
Since the use cases for configuring something about a base field are numerous, this issue is about adding a new ConfigEntity
type, similar to FieldInstanceConfig
, to centralize the storing of all such configuration.
Proposed resolution
- Create a new ConfigEntity type (
BaseFieldBundleOverride
) with the same schema asField[Instance]Config
. Configuration files are prefixed withcore.base_field_override.
- Move all of HEAD's base field overrides (e.g., label of node title, default value of node status, 'translatable') from their currently disparate locations into config entities of this type as possible. Currently the default values of node flags are not possible since to get a default value we need an entity.
- Create a base class that
BaseFieldBundleOverride
andField[Instance]Config
can share common functionality -FieldConfigBase
- Create a common interface
FieldConfigInterface
that differentiatesBaseFieldBundleOverride
andField[Instance]Config
fromFieldDefinition
Possibly remove ContentEntityInterface::bundleFieldDefinitions(), unless a real or theoretical use case is identified for needing content entity types to define bundle-specific field customizations in some way other than through a BaseFieldBundleOverride entity.This is not possible due to Comment::bundleFieldDefinitions()
During DrupalCon Austin, @fago, @plach, @alexpott, and @effulgentsia discussed this approach, and a concern we initially had was that conceptually equivalent configuration would thus be spread across two config entity types. For example, the translatability of an Article title (a base field) would be in a BaseFieldBundleOverride
entity while the translatability of an Article body (a configurable field) would be in a Field[Instance]Config
entity. However, the reason for this separation is that the meaning of the existence (or nonexistence) of these entities is different: if a field.instance.node.article.body.yml
file doesn't exist, it means there is no body field on articles; whereas if a core.base_field_override.node.article.title.yml
file doesn't exist, it means there is a title field on articles, just without any bundle-specific customization. This results in hook_ENTITY_TYPE_delete()
having a different meaning for these cases, which we think justifies them being different entity types.
Comment | File | Size | Author |
---|---|---|---|
#152 | d8_field_override.interdiff.txt | 5.03 KB | fago |
#152 | d8_field_override.patch | 104.98 KB | fago |
#141 | 135-141-interdiff.txt | 1.13 KB | effulgentsia |
#141 | 2283977.141.patch | 101.69 KB | effulgentsia |
#135 | 134-135-interdiff.txt | 4.82 KB | effulgentsia |
Comments
Comment #1
yched CreditAttribution: yched commentedThanks @eff, great summary.
Comment #2
yched CreditAttribution: yched commentedIn order to store stuff like c_t's "translation_sync", both the new FieldDefinitionOverride and the existing FieldInstanceConfig will need to support entry for "3rd party settings", with roughly the same constraints and API needs than what is being done in #2005434: Let 3rd party modules store extra configuration in EntityDisplay :
- internally keyed by module name so that we can have config schemas (and cleanup on 3rd party module uninstall)
- with dedicated API getter and setter next to getSettings() / setSettings()
I guess this "extensibility by 3rd party settings" feature would be supported by the base class shared by FieldDefinitionOverride and FieldInstanceConfig ?
Also, in the hangout with @plach @fago @xjm @alexpott last saturday, it was agreed that FieldDefinitionOverride config would not show up as edit forms in Field UI for base fields - not fully convinced we won't want to go there at some point, but that's the current hypothesis.
I am not sure we have decided whether those "3rd party settings" would be shown as form snippets in the existing edit forms for FieldInstanceConfig. In which case we also need to add a hook to generate those form snippets (again, as #2005434: Let 3rd party modules store extra configuration in EntityDisplay is currently doing)
Comment #3
Gábor HojtsyI think we want the extending modules to be able to provide forms too. Eg. currently field translatability settings are displayed on the field form too. (I'm not sure the triggering translation_sync one is, that is for fields that have component values some of which may be synched).
Comment #4
Gábor HojtsyHere is a very basic start with a base class and a FieldDefinitionOverride class. Not entirely sure how to untangle the maze of interfaces as they apply to these, I did not componentize the interfaces (yet?).
Looking at how #2005434: Let 3rd party modules store extra configuration in EntityDisplay implements third party settings, it is based on PluginSettingsInterface/PluginSettingsBase which participate in widget/entity display settings. This does not participate in field settings that I can see. So don't know if it would be viable to refactor based on that vs. writing our own similar API.
Comment #5
yched CreditAttribution: yched commented@Gabor : yeah, PluginSettingsInterface/PluginSettingsBase was added in the first steps of "convert Field API pluggable types to Plugins, starting with Widgets and Formatters", as a way to mutualize the handling of settings and their default values.
It was not leveraged for "Field type" plugins (FieldItem clases), because those have a split notions of "field-level settings" and "instance-level settings".
I might be wrong, but I'm not sure there's lots to gain by mutualizing the methods that handle "3rd party settings". Could be worth a dedicated interface though ?
Comment #6
yched CreditAttribution: yched commentedclass FieldInstanceConfig extends FieldConfigBase
So, sure, from the POV of Core/Field/FieldDefinition[Interface], FieldConfigBase is the right name.
But then for configurable fields we have
- FieldConfig
- FieldInstanceConfig
- it's the latter that extends FieldConfigBase, not the former :-)
Not saying we should name that new base class differently, just that it raises the nomenclature WTF...
Just to stop sounding like a broken record, I went ahead and opened #2287727: Rename FieldConfig to FieldStorageConfig :-). Will need a core committer green light for D8...
Comment #7
Gábor HojtsyAll righto then. Here is a changeset with an initial API formed after the API in #2005434: Let 3rd party modules store extra configuration in EntityDisplay. Note the methods are not "thirdParty..." because this entity is *designed* to store third party settings only. I assume we'll proxy this object from the field instance where we'll need "thirdParty" method equivalents to most of these and create the object when at least one option is set and delete it if !hasSettings() (which is the reason I introduced that method).
Also added initial config schema coverage for the settings structure with possibility for the modules to provide their relevant schema snippets by module name.
Feedback please if you have time :)
Comment #9
Gábor Hojtsy7: 2283977-7.patch queued for re-testing.
Comment #10
Gábor HojtsyWith proxy code now for CRUD of the field definition overrides from field instances. I think we want to make these a trait and share it with whatever API is used to manage the base fields, no? :) Not sure how best to do that, but this definitely needs feedback at this point.
Comment #11
effulgentsia CreditAttribution: effulgentsia commentedI apologize for any confusion I caused by splitting this issue from #2224761: Add a generic way to add third party configuration on configuration entities and implement for field configuration, but this is not the case. This issue is about making FieldDefinitionOverride have a schema that's almost (or maybe entirely) identical to FieldInstanceConfig. For example, the node title (base) field needs to have its label configurable in FieldDefinitionOverride, and "label" is not a third party setting. Or another example: a custom site may want the node author (base) field on a certain bundle to have its entity reference selection handler be a View, and that handler configuration is part of the field-type-specific (i.e., not third party) "settings" of an ER field.
Meanwhile, #2224761: Add a generic way to add third party configuration on configuration entities and implement for field configuration is the issue for adding thirdPartySettings to both FieldDefinitionOverride and FieldInstanceConfig. Or, if we want to get that issue in first, to just FieldInstanceConfig, and then it'll be this issue's job to also add it to FieldDefinitionOverride, as part of this issue's scope to make FieldDefinitionOverride nearly identical to FieldInstanceConfig.
If it's easier, I'm open to us remerging the two issues together. But I see the creation of a new ConfigEntity type (FieldDefinitionOverride) and the addition of a new property (thirdPartySettings) to an existing ConfigEntity type (FieldInstanceConfig) as separable pieces of work.
I hope the above is clear. If not, let's discuss tomorrow.
Comment #12
Gábor HojtsyI don't think FieldInstanceConfig can even be identical to FieldDefinitionOverride? It was not clear to me if you envisioned FieldDefinitionOverride to be a kind of instance config object for base fields (so default value, label, etc. could be overridden for them? But also a third party settings container for both base fields and configurable fields? However then the FieldDefinitionOverride base properties would not apply to configurable fields, only the 3rd party settings?
Comment #13
alexpottI think both
FieldInstanceConfig
andFieldDefinitionOverride
need to support third party settings but we should leave that to #2224761: Add a generic way to add third party configuration on configuration entities and implement for field configuration. After all modules like field permissions and field validation need somewhere to store their stuff. The third party system should be generic but for configurable fields it should store it's settings in field.instance.* and for base fields it should store them infield.override.*
.Also I think the base field override should be in
core/Drupal/lib/Field
Comment #14
Gábor HojtsyLet's start over from #4 then. Having the field_uuid on this does not seem to make sense then because AFAIS base fields don't have such a value. I so far have a hard time seeing what FieldDefinition properties this should contain that overlap with FieldInstanceConfig. For one they store their values entirely differently, eg. FieldDefinition has $definition['label'] while FieldInstanceConfig has $label. So not sure how much of an overlap there is between the two that we want to rely on.
Also looked at where merging of the two data sets would happen, EntityManager::buildBaseFieldDefinitions() has a colorful set of sources already with the original class, hook_entity_base_field_info() and hook_entity_base_field_info_alter(). I *think* we would merge in values somehow there after the existing sources but it is not clear to me what would provide the management of these objects for base fields and ensure their presence when there are overrides and their disappearance when there are none.
Comment #16
Gábor HojtsyAlso moving the FieldConfigBase and FieldDefinitionOverride to where @alexpott suggested. I thought config entities are to be provided by modules and not from lib, but he says this will be fine. Since I don't have code to exercise this because I don't understand what to even put into them (see #14), it will most likely be green either way and not proving anything.
Comment #18
Gábor HojtsyHelps to use the right case.
Comment #19
alexpottI'm currently working on this.
Comment #20
alexpottHere's a first cut at a patch... lots to do. But I've moved label overriding from node types to the field definition overrides successfully.
I have to pop out now but I will come back to the issue later to add notes on things - just posting now in case of the proverbial bus.
Comment #22
Gábor HojtsySo why is it so important to go all through these hoops to define this vs. just providing from field module? Is the use case of no customizable fields at all on the site but using base fields overrides is a viable thing? If there are no configurable fields, I would assume people coded their base fields the way they wanted and not going to override them?
Looks to me lots of hoops for a theoretical use case.
Not a field instance / FieldConfig though?
Base fields don't have UUID though? Will override have a 'field UUID'?
How is this possible on a field definition override? Some other properties are similarly confusing to me as to why/how they apply to overrides.
Comment #23
yched CreditAttribution: yched commentedRegarding #22.3 / public $field_uuid :
Just a note that #2282627: Remove field_uuid from field instance config records removes it from FieldInstanceConfig - and is RTBC ;-)
Comment #24
alexpottSo discussed this a bit with @plach in IRC he suggested some renames of things. The patch attached adds:
We cannot much progress on removing Node::bundleFieldDefinitions until FieldDefinitionInterface::getDefaultValue does not require an entity since we need to get the default values for status, promote and sticky on the NodeTypeForm.
Other than that I think this patch is ready for some architectural / naming review. The patch works and is used to change the title field label so testing is as simple as going to the node type edit from and changing the title label.
This patch also makes it possible to change the title description :) So changing
'The title of this node, always treated as non-markup plain text.'
for forum posts to'The subject of this forum post, always treated as non-markup plain text.'
is now very simple.I'm not a huge fan of FieldConfigBase as a name especially since FieldConfig does not extend it - this directly relates to #2287727: Rename FieldConfig to FieldStorageConfig
I'm going to continue on an change content_translation to use the bundle field definitions instead of
hook_entity_bundle_field_info_alter
@Gábor Hojtsy's review
Comment #26
yched CreditAttribution: yched commentedRe: $bundle_rename_allowed
This was added just to allow field.module's hook_entity_bundle_rename() to update the 'bundle' stored in field.instance.* config records by doing a save() - which otherwise forbids changing the 'bundle' of an existing FieldInstanceConfig.
That's something I never really agreed with : changing the value of the 'bundle' stored in a config record in reaction to the bundle name being renamed is strictly internal housekeeping, and shouldn't result in an API save with hooks firing IMO. The FieldInstance is not being changed, we just keep it in line with some external changes. In D7 we made a direct UPDATE request in the {field_instance_config} table.
Comment #27
alexpottThe last patch broke hard because of a renamed property... $originalFieldDefinition => $baseFieldDefinition... fixed and converted content_translation to use bundle field definitions :) it works!
Comment #28
alexpottPatch generation fail :(
Comment #29
effulgentsia CreditAttribution: effulgentsia commentedI took an initial quick skim through the patch, and it's looking pretty good. Very nice to see this this far along already. Just some initial thoughts; not a full review:
Seems like quite a few hunks in the patch are dealing with this. How about spinning that off into a separate issue?
I'm not crazy about the naming. Will sit with it for a bit to see if any alternatives come to mind.
So, looks like if we have an override, then the entity contains all of the data, not only the overriden values? Is that by design, or just a temporary artifact?
If the answer to above is "by design", then perhaps the prefix could just be "field"? It's already namespaced with "core", so "base" is redundant, and if it contains all data, then "override" is not fully accurate.
Yuck!
Comment #30
tim.plunkettYes, I hit the Core.* thing while working on a prototype of #2292733: [meta] Introduce Display objects, let's spin that out to #2294177: Allow Drupal\Core to provide [config] entity types
Comment #31
alexpott@effulgentsia's review
Comment #32
yched CreditAttribution: yched commented@alexpott
I don't get this either. A FieldDefinition *is* bundle aware, it's FieldStorageDefinitions that are not. So I don't get why we'd need FieldDefinitionInterface::getBundleFieldDefinition($bundle) ?
Comment #33
alexpottHow is a field definition's for base fields bundle aware?
#2144263: Decouple entity field storage from configurable fields adds this method to FieldDefinitionInterface.
EntityManager::buildBundleFieldDefinitions() attaches field definition objects to bundles - but all bundles share the same object instance unless something clones and overrides.
Comment #34
yched CreditAttribution: yched commentedRight, sorry. Fields exposed in EntityType::baseFieldDefinitions() and not explicitly overrriden in bundleFieldDefinitions() or (with the patch) in a ConfigEntity, are not tied to a bundle - and god I hate this. That's what #2289391: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface is about.
Trying to articulate thoughts about the direction this is taking, adding the notion of BundleFieldDefinitionInterface to the set of *Definitions we already have, but running out of time atm.
Sorry for the FUD, but I'm frankly worried about the complexity of the system we're ending up with, I'm having a hard time figuring it out myself :-(
Comment #35
plachAs discussed in IRC, I'd rename this to
bundle_field_definition_base
.Shouldn't this be
core.bundle_field_definition.*.*.*
?Not sure I'd explicitly mention overriding here. This will be implemented also by
FieldInstanceConfig
.Mmh, we need a core version of this (or just move this to
\Drupal\Core\Field
)This should be available through
$this->getFieldStorageDefinition()
, why do we need another class member?"an field"? Is that a typo or is it correct? I thought the "an" form was used only with initial vowels...
As above this could use
$this->getFieldStorageDefinition()
. An explicit method wrapping it looks good to me though.Why do we need this? Again, cannot we rely on
$this->getFieldStorageDefinition()
?Won't this be a problem when we restore it? It will no longer be a reference to the original wrapped base field definition. Can't it just be null and retrieved again through
$this->getFieldStorageDefinition()
?As discussed in IRC I'd rename
FieldConfigBase
toBundleFieldDefinitionBase
.Here and below, shouldn't we be using camel case for class members?
Maybe not in this issue but we should really rename this to
getTargetBundleId()
for consistency.Maybe I'm not reading it right, but doesn't this code belong to the parent class?
Here and below: we can use
$this->entityManager()
.Bogus blank line
I am not sure about this: if we need to explicitly instantiate bundle field definitions (and ideally from a DX pov I'd really wish we hadn't to), I'd put this method on the
EntityManager
. Two reasons:FieldDefinition
would not look right.This is exactly the kind of DX wtf I'd like to avoid:
I'd tend to agree with @eff: is defining the whole config file strictly required? Would it be so hard to provide just the overrides, at least in the default config?
Comment #36
plach@yched:
IMHO we are not adding new concepts, we are just giving explicit names to concepts that are already existing implicitly in our current system. Maybe this is not making things easier, but it's definitely improving consistency.
Comment #37
alexpottThe interdiff is a pseudo interdiff due to the reroll.
Comment #38
effulgentsia CreditAttribution: effulgentsia commentedBut this creates a change from HEAD behavior in the following way: in HEAD, by virtue of
title_label
being innode.type.BUNDLE.yml
, if we decided in Drupal 8.1 to change Node::baseFieldDefinitions() to change the description, required, or default value of the title field, that change would automatically take effect for all bundles. However, with the patch as-is, for any bundle where the label is customized, then every other aspect of the title field gets disconnected from what is code-defined, so future code changes don't carry over to it.Maybe that's ok? But it's not really clear in the Node Type UI that customizing the title label would have a potential side effect on its default value, description, or other aspects.
So, if we're concerned about that, then an alternative way of conceptualizing an "override" config entity is that individual properties can be set to NULL, the meaning of which would be: have the getter return what is in the code-defined base field definition. I think that still counts as a full config entity: just that there's business logic related to the meaning of NULL.
I agree that the above alternative adds a type of complexity that possibly isn't worth it. Though it also removes a type of complexity as well, in the sense of the entanglement between customizing the title label and customizing other things about the title. So, putting it out there for mulling over.
Comment #39
yched CreditAttribution: yched commentedYep, that's an issue IMO. Just because one value is overriden in config means that all other values also get "masked" and disconnected from the code definition.
In practice, we'll want to use overrides for what currently lies in Node::bundleFieldDefinitions() - i.e by-node-type overrides of title, status, promote, sticky. Meaning, de-facto all node types will be disconnected from their code definition from the get go, and never get back. Thus, any update in the code field definition on any property will never be actually reflected without an update function.
I too thought we were going for shallow overrides ?
Comment #40
Gábor HojtsySo sounds like the shallow override problem is a good reason to return back to where I started this issue to have a generic override array container and only include keys that are necessary vs. a full on entity with properties where you need to specify all of the properties.
Comment #41
alexpottBut here's the thing - if we did
We'd be putting quite an onus on existing sites to be retested / retranslated. I think changing any of these would be madness.
Also moving away from the common base between (what are currently know as) field instances and the overrides means that we have yet another thing for people to learn. In my mind there is a certain elegance to the current solution that is completely lost if we do shallow overrides.
Comment #42
catchI think this is fine as a limitation. We already have that issue for default configuration. This is only being discussed because base fields aren't defined in default configuration - but that makes them the exception.
Comment #43
alexpottRerolled - and a few cleanups.
Comment #44
effulgentsia CreditAttribution: effulgentsia commentedI haven't reviewed the full patch in detail yet (that shouldn't stop someone else from RTBC'ing if they have), but just wanted to comment that related to the shallow overrides discussion, I'm ok with the answer in #42. @plach, @yched: how about you?
Comment #45
plachI have no strong opinion about this: the DX is a bit concerning but if there are architectural reasons behind this choice, let's go on with it. Anyway, I think @yched should have the final word on this.
Comment #46
plachAbout RTBC, I didn't look at the code yet, but per alex's comment I think we are still missing a couple of items from my review.
Comment #47
alexpottYeah we need to address points 16 and 17 from #36.
Comment #48
alexpottFinally addressed 16,17 from @plach's review in #35.
I agree this it is a nicer dx just to have a
getBundleFieldDefinition()
method on the entity manager. We can't make getFieldDefinitions() always return saveable bundle definitions since this will totally break @Berdir's elegant caching in getFieldDefinitions() with the way it combines the entity_bundle_field_definitions and entity_base_field_definitions cache objects for each entity type.Patch needed a simple reroll so the interdiff is a pseudo interdiff again.
Comment #49
plachLooks great to me! I guess now we definitely need at least @yched to have a look to this.
Just a couple of minor notes:
Yay!
Perhaps we could rename
::createFromFieldDataDefinition()
to::createFromFieldDefinitionData
? Unless I am missing something that would sound more understandable to my ears.Also: should we update the EM field definition static cache?
Surplus empty line
@alexpott:
Why not? Unless something changes in #2289391: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface, a base field definition is a field storage definition. Or would they be referencing different object instances?
Comment #50
alexpottwas meant to be... "The original base field definition is not JUST the Field storage storage definition" we can't use getFieldStorageDefinition because we are relying on method on the FieldDefinitionInterface not FieldStorageDefinitionInterface.
Let's go with
createFromFieldDefinition
since this corresponds nicely toFieldDefinition::createFromFieldStorageDefinition
Comment #52
yched CreditAttribution: yched commentedWill try to get back to this soon.
Meanwhile, posted some related thoughts in #2289391-7: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface.
Comment #53
alexpott#1498662: Refactor comment entity properties to multilingual added:
This patch makes those test assertions obsolete.
Comment #54
plachI am still wondering whether we should update the EM static cache so that subsequent calls of getFieldDefinitions() return the bundle field definition.
(I think so :)
Comment #55
alexpottre #54 - I don't think this is needed - it looks kinda ugly https://gist.github.com/alexpott/644c1146af8afac8bd76 plus it would be different from FieldInstanceConfig. Actually what we do is share the postSave - which sorts this out for us.
In BundleFieldDefinitionBase
Comment #56
alexpottRerolled cause #2294177: Allow Drupal\Core to provide [config] entity types landed.
Comment #57
andypostLooks great! could be useful for comment field to change "required" flag for subject base field
Comment #58
alexpottRemoved some uses and updated summary.
Comment #59
BerdirWarning: I didn't read most of the issue and only partially followed some discussions.
for configurable fields/instances, we use an entity query with a STARTS_WITH condition on the id. That's not optimized yet, but there's an issue to do that.
So far, I've only seen config_prefix used to get rid of an unnecessary module prefix. This is a pretty different name, which seems a bit weird?
Overall, this looks pretty nice. Two things I'm worried about, a) the naming, which has been discussed at length already. b) The amount of config entities that we might end up. This just converts the title label but I assume we'd want to update sticky/promote/status too, so we'd end up with 4 additional config entities per node type, just to control some default values and the label.
Comment #60
BerdirOh, and as soon as you make them translatable, you end up with more overrides. Ownership is also interesting, the entity type is owned by core, but multiple modules might mess with the same override. And while that's kind of clear in an alter hook, it's less obvious if you load, change and save a config entity.
I agree that completely overriding makes sense, otherwise we have to load the storage definition + bundle/field definition + the overrides right now. However, we at least need a documented strategy on how to update base fields. Yes, you might not want overridden values to be replaced but the problem is that we don't know which values where. Maybe the module author adds an additional setting or make it required, but that change will not affect any site that stored an override just to change the label. And we don't know what was overidden and what not.
Comment #61
alexpottRerolled and convert the node workflow options.
#59:
I tried to convert Comment::bundleFieldDefinitions() but this was extremely problematic since the setting being altered here is on the storage level and not the instance level.
Comment #63
alexpottFixed some of the tests.
We have a problem with the boolean default value schema
Configurable fields are always ready for multiple cardinality whereas these base fields have a cardinality of 1 and the default value is a bool. Not sure what to do here - ideas anyone?
Comment #65
alexpottWell of course we can do this.
Comment #66
yched CreditAttribution: yched commentedRe #65: That's a convoluted fix IMO. Plus, we still hope to be able to have base fields with multiple values at some point, then they can specify default values as multiple too.
setDefaultValue() is inherently about multiple values. It accepts specifying a default value as either a litteral or an array of default values keyed by delta - mostly because it just passes the result to $entity->field->setValue(), that is flexible / sloppy as to what it accepts.
That does provide nicer DX when defining a base field in code, but that's only a shorthand. Internally, and especially if those things can now be put in CMI, we should always store the same shape - an array of multiple values keyed by delta.
That is, if setDefaultValue() receives $litteral, it should translate it to array(array([first property for the field type] => $litteral), which is basically what FiieldItemList->setValue() does.
Other than that, I'm slowly going through the patch :-)
Comment #67
yched CreditAttribution: yched commentedAlso : the fix in #65 would force every new/contrib/cutsom field type to provide two different schema entries for "default_value" (when used in a configurable field / when used in a base field override), which would suck :-)
Comment #68
alexpottAnother approach that standardise default value storage regardless of cardinality. Also rerolled for #2293773: Field allowed values use dots in key names - not allowed in config
I've attached a couple of interdiffs so you can see that #65 is fully reverted and it is easy to see how it's been fixed.
Comment #70
alexpottThis should fix some of the test fails.
Comment #72
alexpottGotta love tests where the test runner and the site under test get different containers. Use of
$this->container->get('module_handler')->install()
and then making requests to the site is very dodgy.Comment #73
yched CreditAttribution: yched commentedFine, but we cannot hardcode the 'value' property, this would only be valid for a couple field types.
It should be the name of the first property for the field type.
This can be obtained through $this->getFieldStorageDefinition()->getPropertyNames()[0].
Ouch. but yeah, i have nothing better to propose :-/.
Comment #74
alexpottRe; #73
Comment #75
yched CreditAttribution: yched commentedHmm - I'm wary of getMainPropertyName(), it's semantics is kind of shaky, and it's not defined for every field type :-/.
We're doing something symmetric to FieldItemBase::setValue() here, and what is done there is :
which is equivalent to getPropertyNames()[0] (the getPropertyNames() method didn't exist when this code was written)
Comment #76
alexpottOk... weird to have
getMainPropertyName()
then... but here's the change to usegetPropertyNames()
Comment #77
yched CreditAttribution: yched commentedStill mulling on terminology a bit, meanwhile, a couple down-to-earth code remarks :
So we remove setTranslatable() and add setDefaultValue() - not sure why in both cases :-) ?
Also, the phpdoc of FieldDefinition::setDefaultValue() should be switched to {@inheritdoc}.
then the phpdoc content_translation_save_settings() should be updated, it still mentions a 'field' key (BTW, it also mentions a 'settings' entry that doesn't seem used at all ?)
Plus:
- So content_translation_set_config() is never used to save 'fields' anymore - does it mean some config schema somewhere should be updated/removed ?
- content_translation_set_config() is actually only ever called to save 'enabled' - means there could be some simplification in this area ?
Overall, looks like there could be some refactoring / simplification in this area as a followup
Hmm, sure, but this is NodeTypeForm, so why not just directly 'node' ?
Apparently there remains some of these in a couple node.type.*.yml files present in core.
Minor : matter of taste, but I'd think the code would be more readable if $override_entity_class var was inlined (same thing lower in the file)
+ I might be missing something but this looks like we only add "setup" stuff but don't actually use it to test more things ?
Comment #78
yched CreditAttribution: yched commentedAlso :
FieldInstanceConfigInterface should extend BundleFieldDefinitionInterface ?
And then, what's left in FICI that's not in BFDI ? Do we really need two interfaces here ?
[edited : fixed wrong class name]
Comment #79
effulgentsia CreditAttribution: effulgentsia commentedJust a reroll. Nothing else.
Comment #81
effulgentsia CreditAttribution: effulgentsia commentedRelated to this entire patch, especially terminology and what belongs on which interface: #2289391-17: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface
Comment #82
alexpottRemoving failing parts of
\Drupal\migrate_drupal\Tests\d6\MigrateNodeTypeTest
so we can concentrate on #2289391-17: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface for now.Comment #83
alexpottRenamed:
Field[Instance]Config and BaseFieldOverride both extend FieldConfigBase which implements FieldConfigInterface.
FieldConfigInterface extends ConfigEntityInterface, FieldDefinitionInterface.
There is still a FieldInstanceConfigInstance but once we implement bundle renames (which might be complex) all of it's functionality might be rolled in FieldConfigInterface.
Let me know if these changes accord with #2289391-17: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface
Comment #84
plach#2289391: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface is proposing to rename
FieldConfigInterface
toFieldConfigurationInterface
. If that's approved IMO we should do it here.Comment #85
yched CreditAttribution: yched commented"FieldConfigInterface / FieldConfigurationInterface" : might be my bad in IRC :-/. I think FieldConfigInterface would be best.
Comment #86
plachPersonally I'd prefer the full version as we don't have
FieldDefInterface
, but I won't fight for this :)Comment #87
alexpottRealised that #2289391-17: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface wanted BaseFieldOverride to be BaseFieldBundleOverride and it to have a config prefix of 'field'. Patch fixes that and renames EntityManager::getBundleFieldDefinition() to EntityManager::getConfigurableField()
Comment #88
alexpottTidied up a few things
FieldInstanceConfigInterface
and made bundle renames work. I could not think of anywhere other than the system module to put the implementation ofhook_entity_bundle_rename()
- if we don't like this the only other option is to add this tofield_entity_bundle_rename()
.This additional functionality has only been manually tested - need to add tests for this and most of the functionality in BaseFieldBundleOverride and the changes to EntityManager.
Whilst coding this I was lead to wonder if we'd to implement functionality that if you save a BaseFieldBundleOverride config entity and this changes it to make the original BaseField and therefore obsoletes the override should we actually do a delete in BaseFieldBundleOverride::postSave()? Obviously it is super odd calling save on something and it being deleted so maybe this thought can be ignored.
Comment #89
benjy CreditAttribution: benjy commentedThis statement been an if/elseif implies that the operation could be something other than add or edit but $node is used below to build $workflow_options regardless. If the operation wasn't add or edit it would throw an error. Same goes for $fields.
Comment #90
alexpottRerolled and added a test and for renaming.
So calling the base field override files
core.field.*
seems a bit odd - isn'tcore.base_field_override.*
better since it explains better what the file is doing and what will happen when it is removed - i.e. the field is not going to go away, the override is.Apart from that I think the all that remains is to decide on the appropriate level of test coverage - I think all of the functionality is implicitly covered by content_translation tests, the existing Field[Instance]Config tests and the changed NodeTypeRenameConfigImportTest.
@benjy re #89
I'm not sure this form really could be used for anything else looking at the NodeType annotation. Otherwise what will the
$form['#title']
be?Comment #91
benjy CreditAttribution: benjy commentedYeah agreed, maybe we should make it simply an if/else.
Comment #92
yched CreditAttribution: yched commented@alexpott:
- core.field.* / core.base_field_override.*:
Yeah, you're probably right. Longer CMI names, but consistency with the entity_type_id reduces confusion.
- auto-deleting overrides when the overriden values equal the underlying code values:
That's an interesting idea, but I suspect there could be tricky aspects (right, "save() turns into delete()" might be surprising, not sure whether it's a real issue).
Plus, we still intend to have a 'third_party_settings' in there, right ? For those, we don't have any knowledge of 'default values', so there's no way to decide that "the current override values are equal to defaults and can be removed".
We should keep that for a followup IMO.
Not sure whether #77 has been adressed ?
Comment #93
yched CreditAttribution: yched commentedAlso :
- The more I think of it, the more I'm leaning towards :
FDI::getConfig($bundle) returns FCI
rather than
EM::getConfigurableField($entity_type, $bundle, $field_name)
I.e : if you're one of the very rare code that needs a guaranteed FCI because you're going to write to it, you can get it from the FDI the "generic EM API" gives you, but we don't clutter EM itself with this additional notion.
(additionally, the current EM::getConfigurableField() is a bit off, because it's the only one to "target a single field", while the others - EM::getFieldDefinitions(), EM::getBaseFieldDefinitions() are all plural, currently without single-field variants)
- See thoughts in #2289391-21: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface about the impact of the existence of FCIs on EntityType::bundleFieldDefinitions()
Comment #94
yched CreditAttribution: yched commentedLast "also" for the day : The optimization done in #2313875: Preserve the 'field_type' within FieldInstanceConfig will most likely impact this patch - a similar optim for BaseFieldOverride would probably make sense ?
Comment #95
alexpottAddressed #77 and renamed core.field.* to core.base_field_override.* - NOTE this is still not exactly inline with the name - which would be core.base_field_bundle_override but I think it is long enough.
re #77
re #93 I've implemented
getConfig
in this latest patch. Personally I thinkIsn't great since you are passing the bundle into
getFieldDefinitions
and you have to pass the bundle intogetConfig
as well. AsgetConfig
needs a better name.re #94 shall we address this here on in a follow-up or that issue? Since we can probably implement most of this on
FieldConfigBase
?Comment #96
benjy CreditAttribution: benjy commentedI wrote the three new migrations and a test to fix the migrate issues. Put the patch in a follow-up. #2315167: Create migrations for status/promote/sticky
Comment #97
alexpottBrought issue summary in line with latest patch and #2289391-17: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface
Comment #98
yched CreditAttribution: yched commentedNo biggie, but $this->getBaseFieldDefinition() would also work, wouldn't it ?
- #2313053: Field storage and instance call toArray() in __wakeup() is very slow, remove it? removed __wakeup() from FieldInstanceConfig.
- the __sleep() code is now specific to FIC, won't work for BFBOverride - those have a 'baseFieldDefinition' property rather than 'fieldStorage', and no 'itemDefinition'.
That's exactly why I wish we had #1977206: Default serialization of ConfigEntities - currently stalled on toArray() not working for fresh config entities ;-)
Comment #99
alexpottre #98:
Comment #100
alexpottRerolled.
Comment #102
alexpottFixed
EntityManagerTest
- wow that test has a lot of mocking.Comment #103
effulgentsia CreditAttribution: effulgentsia commentedThis patch looks great to me. I don't know if yched still has any outstanding feedback, but the following are my only nits. I think we're very close to RTBC here.
I like the class name, but not the "id" or "config_prefix". How about setting both to "field_override"? I don't think "bundle" is needed, since that's implied by it being a config entity, given that we only configure on a per-bundle basis. And I don't think "base" is needed, because a) it's not properly namespaced (we have no module or component named "base") and b) there's actually nothing about the concept of a field override that requires it to be restricted to base fields only -- it's an implementation choice by BaseFieldBundleOverride only (and a perfectly fine one, but not something that needs to bleed to the entity type or config names).
Need to remove the obsolete reference to "instance".
This seems like a weird way to test this condition. What is it that we actually care about? That we're given a FSD that corresponds to a base field, so that getBaseFieldDefinition() will work? If so, perhaps we need FSDI to have an isBaseField() method? Maybe out of scope for this issue, in which case, can be a followup.
Need to remove "instance" terminology from here.
I disagree with this @todo; can we remove it? It's on FieldConfigInterface where it belongs.
An @todo to the issue where we need to address getDefaultValue() requiring an entity would be nice.
Also, the patch looks to me like it has adequate test coverage, so removing the "Needs tests" tag.
Comment #104
alexpottbase_field_override
since for me core.field_override could be thought to override field.field.*I also removed fullstops from the exception messages in BaseFieldBundleOverride
Comment #105
alexpottTalked some more with @effulgentsia and he realised that we did not need the ability to pass a field object into the constructor since with have
createFromFieldDefinition()
. Less code++Also removed remnants of the old name
Bundle field definitions
Comment #106
effulgentsia CreditAttribution: effulgentsia commentedAgreed on needing more feedback on this before implementing. Here's my thinking on why people thinking that
core.field_override
might override more than only base fields is ok, maybe even desirable.The only code that couples field overrides to only overriding base fields is:
Within BaseFieldBundleOverride
We're typehinting on FieldDefinition rather than the interface, but that's an implementation choice. Another implementation could be more permissive and allow an override of any FDI.
This avoids infinite recursion by requiring the definition we're overriding to be a base field. If another implementation wanted to allow overriding a non-base field, it would need to change this to getOriginalFieldDefinition() and find a way to get that without infinite recursion.
External to BaseFieldBundleOverride
This is the only thing external to the implementation of the new config entity that limits the override to base fields only. But it's not a firm limit; it's just that EntityManager only auto-applies overrides for base fields. But a contrib module could choose to implement hook_entity_bundle_field_info(_alter)() in a way that loads and uses 'field_override' config entities for non-base fields if it replaced the BaseFieldBundleOverride implementation to support it.
So, again, I think that there's nothing conceptual about field overrides that makes them only applicable to base fields. It's only our implementation that limits the scope to that. And there's no reason to discourage contrib from swapping out that implementation. And therefore, I think we should name the config entity type and YAML files with only the conceptual bit (that it's for overriding fields), and not with the implementation-detail bit (that in core, by default, we're only using those config entities for base fields).
Comment #107
effulgentsia CreditAttribution: effulgentsia commentedTo summarize, the naming issue of #103.1/#106 is now the only thing left before this is RTBC.
My opinion is we should change the name from
core.base_field_override.*.yml
tocore.field_override.*.yml
, so that contrib could use the exact same entity type for overriding non-base fields. Core has no use case for this, because in core, the only non-base fields are the ones managed with field.module, which are already represented with field module's config entities, and it's silly to support overriding via config something that is already managed in config. However, potentially, there might be a contrib use case for non-base fields that are code-defined rather than config-managed, but still allow them to be overridden via config.alexpott's opinion is that we should keep them named
core.base_field_override.*.yml
, since that reflects core's implementation, and minimizes the possibility of confusing people as to what these config entities are for, and which fields can be overridden and which can't.Feedback from others on this would be helpful, so that we can make a decision, and (finally!) get this issue done!
Comment #108
yched CreditAttribution: yched commentedNo clear opinion yet, and happy to let others chime in, but if the entity type was field_override, then the class name should be FieldOverride as well (rather than BaseFieldBundleOverride) for the same reasons ?
Comment #109
fagoGreat work, thanks Alex. This looks close to be ready to me as well.
I do not think we should do this. There is a difference between a value overriding the default although the value is the same and having no override - when the default changes one will follow and the other one not. I do think that you only expect your configuration to follow defaults when your override is *deleted*, but not when it coincidentally matches defaults.
Usually label and id match. I actually think base_field_override describes it better anyway, base_field_bundle_override sounds confusing to me as it sounds like an override of a "base_field_bundle", whatever that should be. That the override is stored on bundle level does not have to be reflected in the name imo.
Agreed . I do like core.base_field_override - it tells quite clearly what it really does.
Implementation wise, it's overriding base fields only now - so having config that implies something that is not happening seems confusing to me.
If contrib swaps out that implementation, it can easily move to a fitting config file as well imho. Also I cannot think of good use case for doing so right now - thus, without use-cases I don't think this is something we should prepare for here. However, I'd be interested in possible use-cases for this?
I'd prefer FieldConfiguration instead of FieldConfig as well as it works out nicely besides FieldDefinition. I do see that CMI goes with "config" all over the place, so I'm ok with sticking to FieldConfig also.
Yep, we really should do this. See how field_entity_bundle_field_info() does it.
One new line too much.
Another NL too much. ;)
I think this needs more documentation on when you want a config object and what you'd use it for.
Also it should explain that it will create a new config object in case there is non yet.
This should use the manager, especially as it is already there.
As the bundle overrides are handled directly by the entity system, I think it's the job of the entity system to take care of the changes as well? I.e. move it to entity_invoke_bundle_hook()?
Comment #110
Gábor HojtsyComment #111
alexpott@fago #109:
entity.query
since it depends on theentity.manager
in entity_invoke_bundle_hook() - putting actual business logic in that function looked really bad.
Other considerations
I've gone for base field override - since that is exactly what is occurring. The class, ID and config_prefix now all match.
The only thing left to do is to add tests for the new code
Since this now potentially loads overrides for base fields that do not exist - we should be testing that the expected exception is thrown.
Comment #112
alexpottWhilst writing a test for the exception I realised that throwing an exception is wrong since at this point your site is not broken but it would be unrecoverable. Added a test to ensure that overriding a non existing base field does not cause the field definition to come into existence.
Comment #113
effulgentsia CreditAttribution: effulgentsia commentedGreat! This all looks good now, except a few docs nits, so RTBC.
Acts.
Parens.
Do our standards require this to be shorter to fit on 1 line?
Comment #115
chx CreditAttribution: chx commentedDo our standards require this to be shorter to fit on 1 line?
summaries can be over 80 characters if necessary.
Comment #116
fagoThanks, changes are great. Here a couple of remarks, no biggies though:
This misses a defined property.
Great to see that implemented already - thanks!
*a* base field
We probably should move the whole function to the manager? I'd suggest we deal with that in its own issue.
Shouldn't that be part of the interface? But that can be dealt with in the same issue.
Comment #117
plachThis is looking great to me as well! Just a couple of minor remarks that can be addressed post-commit or if we happen to reroll this.
We could specify the involved bundle names (plus trailing dot).
This should be camel case.
Comment #118
alexpottRe #113
Re #116
Re #117
Comment #119
alexpottRerolled since I committed #2315237: Rename FieldDefinition to BaseFieldDefinition
Comment #121
alexpottSlightly borked reroll :(
Comment #122
yched CreditAttribution: yched commentedAgreed with earlier comments that entity_invoke_bundle_hook() should be moved to a method on the EM.
Opened #2319171: Move entity_invoke_bundle_hook() to EntityManager.
Minor: the EFQ could be built with "id IN [list of known base fields]" rather than with "STARTS WITH" + filter unknown base fields ?
The order is a bit anti-intuitive here. The code order is generally "build stuff incrementally on top of the previous step", but here we discard results of that step if the previous step says something about the field.
We could start by calling $class::bundleFieldDefinitions(), and then collect overrides on top of that ?
There is a dedicated FICStorage, but no dedicated BFOStorage class.
But at least some of FICStorage would make sense for BFOStorage too :
mapFromStorageRecords(), mapToStorageRecord() ?
loadByProperties() ?
(note : we might take the opportunity to update the comment about import order and alphabetical order at the beginning of FieldInstanceConfigStorage, which seems quite stale now)
Comment is useless now, there are no "either case" anymore here :-)
Maybe the method order could be enhanced a bit ? The class looks like a bag of methods without much structure.
Nitpick : could we reorder methods so that setters are grouped together (allowBundleRename() & targetBundle() sit in the middle of two setters)
"a base field bundle override" is something we moved away from in the last couple interations. maybe just "to create an override that can be saved in configuration" ?
So, yeah, "full override" means it's not too clear why we add those - i.e. what's the diff with the original code definition.
Maybe we could add a comment ? Would be lost once this gets merged in the active store, but still worthwhile to document in the yaml in config/install ?
Also, we'll have to remind to update those if we later change the code definition - but nothing in the code definition warns that core defines an override somewhere...
--> From now on, each time we adjust a base field definition, we need to check for the existence of overrides...
All in all, still not sure that "full override" is the right approach, but that can be re-discussed / adjusted in a followup if need be.
Greping 'title_label' in the codebase brings quite a few results still, looks like at least some of them are stale now ?
Minor: $field_config rather than $definition ?
Minor: $field_override rather than $bundle_definition ?
Now that part of the logic is delegated to the parent, "Manage dependencies" is a bit dumb for a comment :-)
--> "Mark the field_storage_config as a a dependency" ?
(the similar inline comment in the parent implementation could similarly be detailed a bit)
Lots of @todos in there - what's the process for those ?
\Drupal::entityManager()->clearCachedFieldDefinitions();
Call EM->getStorage()->onFieldDefinition*Update*() ? (rather than onFieldDefinitionDelete...)
Comment #123
yched CreditAttribution: yched commentedAlso, @alexpott, @plach, @Gabor:
Lost track a bit - IIRC, 'translation_sync' was the main reason we went with "all fields can be configured". So in which issue do we generalize this snippet to all fields ? In the issue where we add "third party settings" ?
(also, not the fault of this patch, but the comment is quite stale / misleading, this is about 'translation_sync', not about "field translation enabled or not")
Comment #124
yched CreditAttribution: yched commentedLast : see #2289391-21: Reconsider whether FieldDefinition should implement FieldStorageDefinitionInterface - IMO the existence of BaseFieldOverride means EntityType::bundleFieldDefinitions(), hook_entity_bundle_field_info[_alter]() should be made to return FCIs rather than clones of BFDs ? And thus, renamed to bundleFieldConfig() ?
Might be best deferred to a followup ?
Comment #126
alexpottRe #122:
mapFromStorageRecords
andmapToStorageRecords
- I don't think loadByProperties is needed since this is all about including deleted fields.Re: #123
Updated comment. The translation_sync stuff will be handled in the postponed beta blocker - #2224761: Add a generic way to add third party configuration on configuration entities and implement for field configuration
Re #124
Yep let's handle that in a followup.
Comment #128
alexpottFixed up the post delete.
Comment #129
yched CreditAttribution: yched commentedThanks @alexpott.
6. 7. (method order) : those are entirely new files, so pushing a clean method order to a followup feels a bit artificial :-p
But fine, opened #2319787: Reorder methods in FieldConfigBase & FieldConfigInterface
10. title_label : indeed, sorry, my bad.
About #124: opened #2319821: Make EntityType::bundleFieldDefinitions(), hook_entity_bundle_field_info[_alter]() return FieldConfigInterface objects
- Comment is outdated now.
- The comment above about "overrides take priority" could be moved to this place here where we do load the overrides ?
+ matter of taste: in-place turning an array of field names into an array of config ids is a tad cryptic and makes a var name that can't be accurate for both. Could be two separate arrays with an array_map() ?
Already present in FCStorageBase --> no need to be re-defined here ?
(same for FICStorage)
Also means BFOStorage::__construct() could move to FCStorageBase::__construct() ?
(at this point, there's not much left in BFOStorage, but it's probably best to still keep an empty FCStorageBase class rather than directly use FCStorageBase as the storage handler for base_field_override ?)
Leftover empty line.
Why do we need this ? IIRC $this->original should be automatically populated for us upstream, and there's nothing similar in FIC ?
Comment #130
alexpottRe #129:
$fieldTypeManager
- I think I prefer to keep the constructor on the concrete object so that it aligns nicely with the createInstance()onFieldDefinitionUpdate
at the bottom of preSave passing the updated or new override and the original override or base field definition. An FIC when it is new does not need an original.Comment #131
alexpottAnd now for the patch :)
Comment #132
alexpottUpdate fixes some unused variables and incorrect PHPDoc blocks.
Comment #133
yched CreditAttribution: yched commentedThanks @alexpott !
Down to the very last nitpicks, after that, I swear I'll shut up :-)
- re #130-1 :
What I meant about the comments in EM::buildBundleFieldDefinitions() is that the code currently reads :
Those two comments blocks talk about "overrides", but it's not the same for the two code blocks. That second comments looks like the code below is about checking something about the "overrides" included in the 1st code block.
The comment that's missing for the overall method to make sense is that this second code block "loads the overrides stored in configuration". The fact that we ensure only those for known base fields are loaded is only a nice-to-have side note, but misses the point if on its own :-)
- re #130-4 :
Oh - right. If isNew(), we place a value in $this->original so that we can use $this->original later on. A bit hackish IMO.
I'd suggest populating a $previous_definition var in both branches of the
if (isNew()) {..} else {...}
, and then using $previous_definition in the common branch ?Do we really have to call the parent specifically between two operations here ? It's easily missed there.
Could we move this at the beginning of the method ?
(side note : apparently FIC::preSave() doesn't bother with calling the parent at all :-/ - opened #2320253: FIC/FSC::preSave() do not call the parent implementation)
Comment #134
alexpottre #133 hopefully this addresses both points.
Comment #135
effulgentsia CreditAttribution: effulgentsia commentedSome additional docs for #133.1.
Also, +1 for everything done since #122, so +1 to this being re-RTBC'd when yched is happy with it.
Comment #136
effulgentsia CreditAttribution: effulgentsia commentedThe above two hunks contradict each other, but the use of both is an edge-case, so I think it's okay to punt that to a followup.
Comment #137
xjmThe docs in #135 are a big improvement.
Can we get an explicit followup for #136 so we can call this done? :)
Comment #138
effulgentsia CreditAttribution: effulgentsia commentedI'll open a followup for #136 and reroll the patch with an @todo linking to it in a few hours, but meanwhile, RTBC'ing this to get it in the queue of people who follow that, because AFAICT, all of yched's feedback has been addressed, but I think he might be too busy right now to confirm.
Comment #139
yched CreditAttribution: yched commented#136 questions me a bit, not sure whether there's an actual problem here, but fine with looking into this in a followup.
RTBC +1, was about to do it myself :-). Thanks a lot @alexpott!
Comment #140
xjmWoot!
Assigning to catch for committer review based on previous discussion with effulgentsia and alexpott. :)
Comment #141
effulgentsia CreditAttribution: effulgentsia commentedAs promised in #138.
Comment #142
fagoThanks, updates look good to me also. +1 on the added docs.
hm, so when I have non-configuration driven entity type and provide some bundle field definitions, the configuration entities which might be added in a general manner,e.g. by content translation module, will undo my bundle field definition changes? That's a problem as the bundle field definition is probably there for a reason -> setting to needs work for this :-/
I think we have to improve BaseFieldOverride to fall-back to a general field definition object, which then can be the base field defintiion - or if existing - the bundle field defintion. That means, we'd have to respect that when creating BaseFieldOverride in getConfig() and inject existing bundle field definitions when loading overrides when building bundle field definitions in the EM. Thoughts?
Comment #143
fagoAlso, I'm not sure it's feasible to duplicate the information of base fields here? Wouldn't it be better to only keep overridden values?
What if the entity type providing module wants to change a description of a base field later on, it would not take any effect once content translation module has started adding overrides for a bundle? But that doesn't seem to be intuitive to me as the entity type providing module cannot know whether another module has started doing overrides or not. Thus, imho we have to keep overridden properties only?
Comment #144
Gábor Hojtsy@fago: on the overrides/code change discussion and why it was discarded see #39 to #45 (and maybe onwards a bit). Was raised a month ago :)
Comment #145
fagoI know that discussions touched this topic on overrides/code change discussion already, but the current patch does not implement either approach in a reasonable way: There are code based bundle definitions and config based definitions, but when there is no safe way to use code-based definitions (see #143) there is no point in having them any more. They either need to be usable or should go away in the first place.
Comment #146
fagook, gave this some more thought:
- I agree the general override issue of code base-fields in #143 is addressed, I mean it's not nice, but by thinking through multiple scenarious I was not able to come up with a really problematic issue. So it seems there is no point to re-iterating on the shallow override discussion - sry for that.
- But what we've not discussed yet imo, is how this works with code-based overrides:
There is no way of using this, without changes being dropped by content translation (once enabled). So we should either drop support for it, or fix it?
The approach for fixing it would be:
Seems doable. It has the same update problem as code based field definitions, but that's fine - it's just the same.
When we'd go with the removal option, I see only this problem:
It seems to me that this would be a very likely use-case for overridding, e.g. change the default widget per bundle. But it's not possible right now with the config based approach, so when we'd remove the code-based override approach we'd have to make that possible I think.
On removal vs fix: Personally I'd tend to prefer the fixing way as it seems a bit arbitrary if we'd support code-based fields for base fields only and for bundle fields we only do config based ones.
#2319821: Make EntityType::bundleFieldDefinitions(), hook_entity_bundle_field_info[_alter]() return FieldConfigInterface objects touches the whole area as well, not sure how yched's idea would work in regard to saving them or not. However returning config from there does not seem to solve the problem of whatever you return there might be ignored?
Comment #147
fagook, looking at the code again I actually think it does already work (good work!). It's just that
is kind of confusingly named as it might be called from a base field override already. But we can improve its name + add test coverage for it in a follow-up. Thus, setting back to RTBC - sry for the noise :-)
Comment #148
effulgentsia CreditAttribution: effulgentsia commented@fago: while that line of code might not be a problem, I think you brought up some good points on the complications that arise when you try to have both code-based-overrides and config-based-overrides operating on the same base field. Let's think through whether we want to remove support for that explicitly or else clarify the use cases and make them work in follow ups, such as #2321071: BaseFieldOverride fails to take into account ContentEntityInterface::bundleFieldDefinitions() when invoking onFieldDefinitionUpdate().
Comment #149
effulgentsia CreditAttribution: effulgentsia commentedOne more followup related to fago's recent points: #2321443: Check if there's sufficient test coverage for base fields with simultaneous code-based and config-based overrides.
Comment #150
yched CreditAttribution: yched commented@fago:
No, because its param is typehinted as BaseFieldDefinition ?
Comment #151
catchJust a note I probably won't be able to review this in depth until Monday/Tuesday. The follow-ups look OK.
Comment #152
fagoThat's not a problem right now, as bundle overrise are (confusingly) based upon the same class right now. If we'd change the class it means we'd have to add a general createFromFieldDefinition().
I've done a small test case to proof current code is actually working right now, setting back to needs review for that part.
So, actually the implemenation could be easily improved to handle all fields by using getStorageFieldDefinition() instead of getBaseFieldDefinitions() to fetch the storage field. Given that, I'd actually agree with effulgentsia that the config (+ entity type) should be
core.field_override.*.yml
then. I don't think the possible confusion around overriding field instances with config is not an issue - technically, you could do it, but there is no point in overriding a config field with config, so that's why we don't ;-)Howsowever, I think we should defer further discussion around that to #2321443: Check if there's sufficient test coverage for base fields with simultaneous code-based and config-based overrides and re-evaluate it depending on what we want to do with code based bundle fields.
Comment #155
alexpott@fago nice extra text coverage - I'd been meaning to add a test for that. I'm comfortable with rtbc'ing the patch based on the changes in #152.
Comment #158
swentel CreditAttribution: swentel commentedProblems with bot, not the patch.
Comment #164
alexpottYet more "too many connections" fails on testbot - the tests pass locally just fine.
Comment #166
catchOK sorry it took me a while to get to this.
This whole issue feels like we're running into the limitations of trying to keep base fields and configurable fields separate. Trying to resolve the limitations of configurable fields (schema location, lack of reliability with the locked status etc.) might end up working out better in the long run, although hard to tell without a lot of work.
However if we're going to stick with the split, then the patch here (with the follow-ups) is fine I think. So, committed/pushed to 8.0.x, thanks!
Comment #167
nod_Comment #168
yched CreditAttribution: yched commented@_nod: are you sure ? This issue has no JS implications...
Comment #169
nod_it touches a js file so I'd like to have the tag. however insignificant it may seem. In this case there is an Id selector that should be replaced (in follow-up) by a data attribute. Problem is with drupal_HTML_id causing our fat ajax requests. tagging help me see what ppl run into (and why) so I can have a feel for refactoring priorities.
Comment #170
yched CreditAttribution: yched commented@_nod: oh, ok. Note that the patch merely changed the id used in an existing selector, as a result of a form structure change (this targets an id auto-generated by Form API on form elements).