Problem/Motivation
When node type machine name is changed only {node} table updated.
Table {node_field_data} is not updated.
This is also true for other places like views, entity reference field settings etc. which might reference entity bundles.
Proposed resolution
Prevent entity bundle config entities from being renamed.
From #2575039-15: Prevent users from editing a content type's machine name once it has been set by @dawehner:
- Something like
BundleConfigEntityFormBase(Adds validation + the #disabled flag by default) - Maybe also add a similar base class for config entities itself and validate the renaming of the entity KEY there.
The current patch should at least document for the #disabled flags, why they are setup in this particular way.
We can drop the failing BookTest tests that try to change machine name as per #2575039-17: Prevent users from editing a content type's machine name once it has been set
API changes
| Comment | File | Size | Author |
|---|---|---|---|
| #97 | interdiff.txt | 1.64 KB | pfrenssen |
| #97 | 2172843-97.patch | 56.03 KB | pfrenssen |
| #84 | 2172843-84.patch | 43.5 KB | amateescu |
| #71 | 2172843-rename_bundle_removed-71.patch | 40.41 KB | fgm |
| #69 | 2172843-rename_bundle_removed-68.patch | 40.2 KB | fgm |
Comments
Comment #1
andypostProbably better to implement this in base controller.
This will simplify DX for contrib provided enities with bundles.
Let's see how many tests are broken.
PS: suppose loosing update message is not a big deal...
Comment #2
damien tournoud commentedI would actually recommend to kill this feature completely. The bundle name is an ID that is not supposed to change. Changing it requires a migration process of a potentially unbounded number of entities.
I suggest we make this form field disabled and remove the broken supporting code.
Comment #3
andypostMakes sense, so let's fix the bug (patch #0) and file new issue to discus proper way to solve this
Comment #6
marthinal commentedMissing node_field_data table.
Comment #7
yched commentedSounds reasonable - but also sounds like we should have tests for this ?
Comment #8
marthinal commentedComment #9
marthinal commentedComment #10
marthinal commentedHere we go. :) Let's try this.
Comment #13
marthinal commented10: 2172843-10-only-test-should-fail.patch queued for re-testing.
Comment #16
marthinal commentedIt seems that there were new commits.
Comment #17
catchI agree with Damien here - we should disable the feature entirely when there are any nodes of the type, or possibly altogether - we already do similar for fields.
There's plenty of other places that would have to respond to a bundle rename, for example Views filters and any other kind of configuration entity that might reference a bundle. Don't think the complexity of checking all those places is worth trying to maintain the feature.
Comment #18
yched commentedAs far as field storage is involved, the specific case of nodes doesn't really matter. Are we saying we're removing support for bundle machine names changing, for all entity types ? vocabularies, whatever formulation some contrib entity type has for its own bundles ?
If some entity types have "renamable" bundles, then field storage has to support it.
Comment #19
catchI think we should remove it yes. Could leave the option to rename if there's no content possibly, but then delete/re-create is available then anyway.
Comment #20
andypostI think the
onBundleRename()should stay in core but have a sane comment about what the purpose it for.Check for no-content makes no sense because except views field and instance settings should be updated as well (for ER field types)
Comment #22
catchFor views/entity reference instances we could possibly use #2080823: Create API to discover config entities' soft dependencies and use this to present a confirm form on module uninstall.
Comment #23
andypostso let's wait, the related issue is green now
Comment #24
xjmBetter status then?
Comment #25
alexpottRenaming is not just about the current site - it is also about deploying the configuration changes - see #1740378: Implement renames in the import cycle. I agree with @catch and @damien we should consider removing this feature - it introduce complexities for configuration deployment that are seriously complex and might be insurmountable. For example once #2080823: Create API to discover config entities' soft dependencies and use this to present a confirm form on module uninstall lands changing a machine namewill trigger updates to all of the entities that depend on it.
Comment #26
alexpottEdit: removing duplicate comment
Comment #27
andypostHistorically this was added in taxonomy vocabulary or image style conversion to config, both entities supports renames to update related data (terms and reset image cache).
So removing ability to rename better to encapsulate into machine name element and spread for all core this regression with change notice
Comment #28
swentel commentedComment #29
andypostComment #30
jhedstromPatch above no longer applies (but it has tests).
Comment #31
marthinal commentedComment #32
pwieck commentedRe-roll. Haven't done one in a long time. Hope it's right.
These two below had been deleted from head:
core/modules/node/lib/Drupal/node/Entity/NodeType.php
core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php
Comment #33
pwieck commentedComment #34
pwieck commentedComment #38
andypostComment #39
deepak_123 commentedpatch rerolled.
Comment #41
catch#2575039: Prevent users from editing a content type's machine name once it has been set was opened as a new critical, but this is the older issue, with more background, and a more comprehensive (albeit stale) patch.
Comment #44
catchComment #45
fgmFor reference/comparison, here is the latest patch on the other issue.
Comment #46
yched commentedFWIW, #1978714: Entity reference doesn't update its field settings when referenced entity bundles are deleted is trying to update the 'target_bundles' field setting on ER fields to account for bundle renames. And the amount of non-trivial code needed is a bit insane, and would theoretically need to be duplicated by any config that holds a list of bundles, which seems like a *very* common pattern - we have lots of things that talk about bundles, or are enabled/disabled by bundle...
We need to account for bundles being removed anyway, but that's simpler, and in some cases having a list with old bundles that don't exist anymore is less problematic)
Comment #47
catchJust reviewed the patch here, it's not relevant to the current state of this issue at all, was trying to fix renaming, so we should start from #45.
Comment #48
catchRunning #45 past the bot since the fails are useful to see.
Comment #51
jhedstromUpdating the IS to reflect the latest thinking in #2575039: Prevent users from editing a content type's machine name once it has been set.
Comment #52
fgmPreparing a patch combining:
as suggested by @dawehner on the other issue. I'll remove the now-unapplicable booktest test regarding content type renamings.
Comment #53
dave reid+1 for removing this ability. Typically the reason I would need to rename a bundle is I made a mistake in the name on creation, which I usually can resolve before I've gone though and created lots of integration (Views, pathauto, etc). Would be good to know from contrib that we can rely on these not ever changing.
Comment #54
fgmSince I'm not finishing it tonight, here is the first part: the form-level protection. Some notes about it:
BlockContentTypeForm::form()andShortcutSetForm::form()should probably be removed, as redundant with the shared one inBundleEntityFormBaseparent::form()call inVocabularyForm::formis useless : none of the parents appears to expect being passed a third parameter. If it actually serves some purpose, it will need to be commentedSetting to CNR to get an idea of the current errors : not expected to pass yet.
Comment #56
fgmAnd here is a version with the data-level protection. Some other changes:
Unassigning for now in case someone wants to work on it during the day.
Comment #57
fgmSorry, slight error in the previously uploaded patch. Here is the proper version.
Comment #59
wim leersReviewed, and fixed all my remarks myself: all minor stuff.
I think: s/id/ID/
Should be quoted.
And here it says "name", not "ID".
It should actually be "machine name", per the issue title?
Internally, it is "entity bundle ID", in human-facing text, it is "entity bundle machine name".
Nit: needs FQCN.
Nit: 2 blank lines instead of 1.
Docblock needs to be updated.
"id element" is misleading/vague.
Incomplete docblock.
Comment #62
fgmA few more in the same vein:
Just noticed that coding standards say {@inheritdoc} must only be used for unchanged docblocks https://www.drupal.org/coding-standards/docs#inheritdoc so we need a complete docblock
We can use $this->entityManager() here. And since we're using it twice in the function, we should refactor its reference to a local $entity_manager.
Comment #63
yched commentedShouldn't we then also remove our "bundle has been renamed" notification stack ?
- EntityBundleListenerInterface::onBundleRename() and its implementations (EntityManager, SqlContentEntityStorage)
- hook_entity_bundle_rename() and its implementations (field, field_ui, language)
Comment #64
catchYes I think we should remove them, then if we ever add this back and the existing API turns out not to be sufficient, we're adding APIs rather than breaking them at that point. Also removes dead code when we ditch the implementations/invocations that will never run.
Comment #65
andypostLooking at #2467293: Warning when changing vocabulary machine name we need to fix
Vocabulary::postSave()as wellComment #66
stefan.r commentedJust some drive-by code removal (62/63/65)
Comment #68
stefan.r commentedthis assertion is now failing?
Comment #69
fgmI guess that's because in the eval() performed by the quoted assert, the namespace is no longer there, so it now needs the FQCN.
Comment #71
fgmThere is a logic error in the data-level check : it prevents creation of a bundle if one already exists, instead of just preventing renaming. Rerolling should remove a good number of fails.
Comment #72
catchLet's open a follow-up for the assert, we haven't sorted out how we're using them in core properly yet.
I don't think we can only prevent this when the bundle has data - you could easily set up views filters, reference fields etc. that depend on the bundle without any actual data being added, and we're removing the mechanism for those things to update themselves in this patch. We should just prevent renames altogether.
Comment #74
fgm@catch : regarding the second point, this is the point I addressed in the #71 patch vs the #69 version : it now checks getOriginalId() vs id(). Maybe your comment only applied to version 69 ?
Comment #75
catchIt's still doing a hasData() check though?
Comment #76
yched commentedI realized only recently that an issue with hasData() checks is that they can allow some config changes on your dev setup that uses a smaller / fresh db, and then break when deploying the config on prod on the actual full db.
And yeah, Field UI's FieldStorageConfigEditForm is also guilty of that :-/
(when the hasData() check is only done in the UI, the problem becomes : change was approved on dev, and deploys successfully on prod where the UI would have forbidden the change)
Comment #84
amateescu commentedFixes #72 and a few tests.
Comment #86
amateescu commentedThe rest of the failing tests can just be deleted.
Comment #87
dawehnerThat sounds like incredible optimization which sacrifes code simplicity. I don't see a point why this additional functional call would be bad in any way
I'm curious whether the wrapping code:
\Drupal\Core\Controller\FormController::getContentResultwould additionally call it as well, just to be sure? Contrib/custom code might have not the call in there yet.Comment #88
catchIf the element was disabled, but the entity wasn't new, wouldn't it undo whatever had previously disabled it if we didn't do that additional check? I don't think it's a micro-optimization, it's preventing setting #disabled to FALSE.
Comment #89
fgm@amateescu : this is (mostly) not an optimization. This check is because there is one case where the #disabled property is already set to true (that's on nodetypeform depending on locked status), in which case we do not want (I think) to reset it to false if the entiry is new.
In
NodeTypeForm::form():@catch : I think that's what you are saying too ?
Comment #90
dawehnerAh gotcha, so this is about enabling to disable it even in other cases.
Comment #91
dawehnerA bit more reviews.
core/lib/Drupal/Core/Config/Entity/ConfigEntityBundleBase.php:20unused use statement:
use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;IMHO we should simply not use t() for exceptions, its not a message intended to be shown for users.
I'm curious whether we should document somewhere in entity.api.php that you cannot rename bundles?
There is a couple of code in
\Drupal\field_ui\Tests\EntityDisplayTest::testDeleteBundlewhich refer to the node.type.article_rename, which no longer exists.I'm curious whether we want to drop that entire test coverage, given that just the second part is about renaming bundles.
Comment #92
wim leersSo this simply forbids renaming always, which handily avoids the problem @yched describes in #76.
Since @catch suggested this in #72.2
This is very strict, but also very simple to understand, and therefore very predictable. It completely removes a whole area of unpredictability. The negative impact is very limited (how often do people actually need to rename bundles?).
Therefore, once #91 is addressed, I think this is RTBC.
Comment #93
pfrenssenWill address remarks from #91.
Comment #94
pfrenssenAddressed remarks from #91.
Comment #95
catchSo there is not really a use-case for changing the bundle in presave, but should we consider calling parent::presave() at the top of the method instead of the bottom just in case to also protect against that? Or is that not possible for some other reason?
It might be worth changing the comment to clarify it's not an optimization - I'm not surprised dawehner read it like that.
Or possibly instead:
Otherwise looks great.
Comment #96
pfrenssenOn it!
Comment #97
pfrenssenComment #98
plachSo this is rtbc now :)
Comment #99
catchOK so for a second I thought this comment was no longer true, but then realised it still is:
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21...
That's not for this patch to fix.
Committed/pushed to 8.0.x, thanks!
Comment #101
yched commentedYEEEEHAAAAAH ! @all++
Comment #102
darol100 commentedFinally... woowwwww
Comment #103
dawehnerSeriously, !!!!!!!!!!!!!!!!!!!!!!!!!!!!!YES!!!!!!!!!!!!!!!!!!!!!!!!!!
Comment #105
plachhttps://www.youtube.com/watch?v=pmGNo8RL5kM !!!
Comment #107
mustanggb commentedGratz everyone!
Comment #110
johnalbinWoo-hoo!
Setting this back to "fixed" because https://www.drupal.org/project/issues/drupal?priorities=400&version=8.x needs to be ALL GREEN.