Spin-off from #2577963: Let entity_ref Selection handlers be in charge of the field validation
Problem/Motivation
EntityReferenceItem does:
public static function defaultFieldSettings() {
return array(
'handler' => 'default:' . (\Drupal::moduleHandler()->moduleExists('node') ? 'node' : 'user'),
So, for base fields :
base e_r fieds that don't bother specifying a 'handler' setting, get a handler for a completely unrelated entity type (user or node, depending on what modules are enabled). That looks potentially very problematic.
SelectionPluginManager::getInstance() already handles "if 'default' then 'default:$target_entity_type", so it seems the default value for 'handler' setting should just be 'default', without trying to guess an arbitrary derivative ?
For configurable fields :
entity_reference_field_config_presave() takes care of saving the correct derivative for the target_type (that is required for config schema, as was discussed in #2436835: Unable to create config schema for entity type specific entity reference selection plugin.), but it only acts on entity_ref' field type, and omits child types (image, file)
Also, a couple of field definitions shipped in standard.profile have the wrong derivative.
Using the wrong derivative for your target type can lead to improper / inconsistent validation, and possibly fatal errors, since the wrong Selection can try to execute EntityQueries with conditions on unknown fields (see #2577963-6: Let entity_ref Selection handlers be in charge of the field validation)
Proposed resolution
Patch :
- Changes the default value for the 'handler' setting to be just 'default', without trying to guess an arbitrary derivative.
- As a proof that this works, lets the node.uid base field use the default value
- Changes entity_reference_field_config_presave() / and entity_reference_field_storage_config_presave() to take care of entity_ref + subtypes, and moves them to field.module since they affect fields that cn be created without entity_ref module
- Adds a hook_post_update() (with a test) to fix existing fields
API changes
None, but base e_r fields that just want to use the default selection plugin for their target type can now omit to specify the 'handler' setting.
Data model changes
None
Beta phase evaluation
| Issue category | Bug : some e_r/file/image fields can use the wrong Selection handler for their "set of allowed references" |
|---|---|
| Issue priority | Major: This leads to improper validation, and possibly fatal errors |
| Comment | File | Size | Author |
|---|---|---|---|
| #52 | 2578249_ER_default_handler-52.patch | 15.97 KB | yched |
| #49 | 2578249_ER_default_handler-49.patch | 15.98 KB | yched |
| #48 | 2578249_ER_default_handler-48.patch | 69.34 KB | yched |
| #47 | 2578249_ER_default_handler-47.patch | 15.96 KB | yched |
| #40 | interdiff.txt | 4.29 KB | yched |
Comments
Comment #2
yched commentedPatch, let's see what the bot says.
Comment #4
yched commentedMigrate test needs adjustment
Comment #5
amateescu commentedDamn, the aspect of base fields was overlooked in #2436835: Unable to create config schema for entity type specific entity reference selection plugin. :(
Since
entity_reference_field_config_presave()already handles configurable fields properly and puts the full selection plugin ID (e.g. 'default:taxonomy_term') in config, the patch looks correct.Comment #6
yched commentedOoh, right, tough one, #2436835: Unable to create config schema for entity type specific entity reference selection plugin. :-/
Comment #7
yched commentedHm - looks like a few configurable fields shipped in standard.profile have wonky selection plugins :
field.field.node.article.field_image.yml : default:node
field.field.user.user.user_picture.yml : default:node
@amateescu : we should change those to default:file, right ?
I guess that means an update function as well :-/
Comment #8
yched commentedtagging accordingly then
Comment #9
amateescu commentedUgh, yes, we should update them. Basically just copy the code from
entity_reference_field_config_presave()into an update function.Comment #11
yched commented@amateescu : Hm - but we're not supposed to call APIs in update funcs, so we can't really rely on $selection_manager->getPluginId() as entity_reference_field_config_presave() does ?
Not sure what the logic should be in that update, actually :-)
Comment #12
yched commentedAlso, entity_reference_field_config_presave() :
- is actually not doing enough, since it only cares about fields of type 'entity_reference', while the handler needs to be adjusted for "child" field types as well (file, image...)
- should be in field_module rather than entity_ref.module, since this affects fields that can be created without e_r.module
- entity_reference_field_storage_config_presave() should have the same treatment, for consistency
Updated patch moves them to field.module, and makes them handle child types.
Haven't really figured out the question of the update for currently faulty fields.
Comment #13
yched commentedActually, for the update, a hook_post_update() that just resaves the field definitions should work. Added a test as well.
Hopefully this should be committable.
Comment #14
yched commentedUpdated the IS and added a beta evaluation
Comment #15
yched commentedComment #16
yched commentedComment #18
yched commentedOf course it would help if I actually fixed the broken yamls in standard.module...
This should be green.
Comment #20
yched commented[edit : removed uninteresting debug rambling, fail was just me being über-silly]
Comment #22
yched commentedOh gee. I had left two copies of the logic in that resets 'handler_settings' in field_field_storage_config_update().
/me slams his head against the wall, and goes out for a walk
This should really be green now...
Comment #23
jibranIt is in the wrong file.
Comment #24
yched commentedIndeed, I wasn't aware of the [module].post_update.php convention. Thanks !
Comment #27
yched commentedYeah, not my day.
Comment #29
yched commentedOh, and UpdatePostUpdateTest, you suck.
Comment #31
yched commentedNot sure what to believe between https://qa.drupal.org/pifr/test/1169638 reporting fails and https://dispatcher.drupalci.org/job/default/19890/testReport/Installer/D... reporting passes.
Passes locally, so, retest ?
Comment #33
yched commentedComment #35
jibranI think we should add some custom fields in update test to check that it is working for custom fields(not defined by config files) as well and some asserts in EntityUnitTest after saving the ER field config instance so that we can make sure it'll never happen again as in set default handler and assert that it stores default:reference_entity_type . What do you think about it?
+1 to this.
I know this is c/p of existing code but can we please add comments to explain this.
:(
:)
Comment #40
yched commented@jibran #35 :
I don't see the point. Fields shipped in config are just regular configurable fields, no different from the ones created in the UI. The test tests a configurable field that's present in drupal-8.bare.standard.php.gz, whether it came from the install profile or was added later on makes no difference.
That is actually already tested in EntityReferenceItemTest::testSelectionHandlerSettings(), because entity_reference_field_config_presave() took care of it.
The thing that was broken was that entity_reference_field_config_presave() didn't take care of sub field types (file, image), and field_field_config_presave() now does. Added a test for that in FileItemTest (fails on HEAD)
Also, added a comment for the correct but non-explicit flow for "reassign the correct handler plugin in the fields when the target_type changes in the field storage". Added more explicit tests in EntityReferenceItemTest::testSelectionHandlerSettings() (they pass on HEAD)
#35.1 :-)
#35.2 Added a comment
#35.3 .4 :-)
Comment #41
xjmSee https://groups.drupal.org/node/484788 for more information on the rc target tag. This issue should possibly be retagged as rc deadline instead?
Comment #42
yched commented@xjm : I think rc target is fine. This breaks no APIs and can happen after RC1, but would be really best to get in before RC1 because the current behavior (e.g. field_image using the NodeSelection plugin) is very weird and can lead to nasty consequences.
Comment #44
yched commentedTest-only patch fails, patch passes...
RTBC anyone ? ;-)
Comment #46
jibranHere we go thanks for the explanation and fixes.
Comment #47
yched commentedReroll
Comment #48
yched commentedReroll after #2571533: Allow setting custom storage on FieldStorageConfig, that also added a field_post_update
Comment #49
yched commentedAs mentioned by @alexpott on IRC, #48 was too big, diffed against the wrong HEAD, I guess.
Re-rebased, sizes match.
Comment #50
yched commentedReroll needed after #2520540: Enforced configuration dependencies shouldn't have to be repeated in the calculated dependencies, that had to adjust the list of post_updates in UpdatePostUpdateTest as well.
Not where I can do this atm, anyone up for it ? ;-)
Comment #51
fabianx commentedComment #52
yched commentedReroll
Comment #55
yched commentedBot fluke, back to green
Comment #56
alexpottThis issue has test coverage and a test upgrade path. Committed 60b75a2 and pushed to 8.0.x. Thanks!
Yeah this is super confusing and wrong.
Unused use fixed on commit.
Comment #58
larowlanThis causes major issues for DER, because there is no 'handler' setting - but field_field_config_pre_save expects it to be.
We should be checking default settings to see if such a key exists or checking schema. Feels dirty that field.module blindly expects there to be a handler setting.
Will get around it with adding a fake value and then removing it in a presave of our own.
Comment #59
yched commented@larowlan : Yes, there's kind of an expectation that if a field type extends another one, it has all the settings of the parent. Otherwise things might break any time the parent class adds some code using $settings['the_setting'] in a point release ?
Comment #60
larowlanWe got around it with #2581609: field_field_config_presave expects there to be a 'handler' setting but there isn't - hook_module_implements_alter to nix the field.module one in the case of DER