The import of new node types currently only works only because 'field.*' files are imported before 'node.*' files.
0) Dev & Prod environments, exact same state and config
1) Create a node type "foo' on Dev.
- This adds node.type.foo.yml.
- node_add_body_field() (called by NodeType::postSave($update = FALSE)) and _comment_body_field_create() (called by comment's hook_node_type_insert()) create instances of respectively 'body' and 'comment_body':
each with fresh UUIDs.
2) Import all of this to Prod:
What happens in HEAD is:
- thanks to alphabet ordering, the field.* files are imported first. The 'foo' node type doesn't exist yet, but FieldInstance doesn't check that the bundle actually exists (was done of purpose for similar cases in the upgrade path) --> the instances are created.
- node.type.foo.yml is imported. This triggers both NodeType::postSave() & hook_node_type_insert()
We're lucky, both node_add_body_field() & _comment_body_field_create() are wise enough to check and do nothing if the instances already exist (I'm not even sure why they do it). All is good.
If import happened the other way around:
- node.type.foo.yml is imported, node_add_body_field() & _comment_body_field_create() create *new* instances with their own UUIDs
- field.* files are imported - Import crashes because the instances already exist with different UUIDs than in the files (the UUIDs that were generated on Dev).
So, we're lucky now, but this feels really brittle. If another entity type wants to implement similar "autopopulate new bundles an inititial set of field instances", and is provided by a module that starts with [a-e], this explodes...
Conclusion from the "CMI hard issues" discussion in DC Prague:
- Add config_synching flag (like cron_running) -- ConfigEntityBase::isSynching(), plus a setter/getter, not exported
- It’s the responsibility of runtime code (MyConfigEntity::postSave(), hook_entity_save()...) to check the flag and not trigger separate config changes if the flag is present
- Also add a global state flag
- Check the state flag and throw an exception if a configuration entity is saved without the local sync flag when the global state flag is there.
|FAILED: [[SimpleTest]]: [MySQL] 59,371 pass(es), 1 fail(s), and 0 exception(s).|
|PASSED: [[SimpleTest]]: [MySQL] 59,714 pass(es).|
|PASSED: [[SimpleTest]]: [MySQL] 59,258 pass(es).|