Problem/Motivation
Since EntityOwnerTrait can be used as a default implementation of EntityOwnerInterface the owner can't be NULL anymore for media entities.
Therefore if you cancel a user you can't edit a media entity that was own by this user. The following error is thrown:
Drupal\Core\Entity\EntityStorageException: SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column "uid" violates not-null constraint DETAIL: Failing row contains (188, 241, image, nl, 1, building-buildings-busy-297743_0.jpg, 442, car, null, 1000, 667, null, 1558535344, 1563353147, 1, 1).: INSERT INTO drupal_webshop_nl.media_field_data (mid, vid, bundle, langcode, status, name, thumbnail__target_id, thumbnail__alt, thumbnail__title, thumbnail__width, thumbnail__height, uid, created, changed, default_langcode, revision_translation_affected) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9, :db_insert_placeholder_10, :db_insert_placeholder_11, :db_insert_placeholder_12, :db_insert_placeholder_13, :db_insert_placeholder_14, :db_insert_placeholder_15); Array ( ) in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 847 of /var/www/html/src/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).
(Captain Obvious Note: When updating the media entity if you add an owner no errors are thrown.)
I open this issue for people who need a temporary solution.
The issue #3043725: Provide a Entity Handler for user cancelation try to find a generic solution and could take a while.
Proposed resolution
The first proposed solution is a no-brainer: copy/paste what is done for node.
Remaining tasks
Find a quick win better than copy/paste while waiting for #3043725: Provide a Entity Handler for user cancelation.
User interface changes
None
API changes
None
Data model changes
Media entities updated correctly on user cancel.
| Comment | File | Size | Author |
|---|---|---|---|
| #41 | media_user_cancel-3069291-41-D11.3.3.patch | 1.68 KB | fernly |
| #40 | media_user_cancel-3069291-40-D11.1.7.patch | 1.68 KB | fernly |
| #39 | media_user_cancel-3069291-39-11.x.patch | 1.65 KB | fernly |
| #38 | interdiff-35-38.patch | 1.05 KB | redzeuf |
| #38 | media_user_cancel-3069291-38-9.4.x.patch | 1.69 KB | redzeuf |
Issue fork drupal-3069291
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
beram commentedHere's a temporary solution: big copy/paste what is done for node.
(adding the 8.7.x patch because we need it for our sites)
Comment #3
beram commentedComment #4
chris matthews commentedComment #5
ducktape commentedTested this in my project with 8.7.5, works like a charm.
Thanks a lot!
Comment #6
phenaproximaAdding #3057004: Not having an author when editing/creating a Media Entity results in an EntityStorageException as a related issue. +1 for this idea, overall; I'm not sure we necessarily want to copy all that code from the Node module, though. I'd prefer a smaller workaround as in the issue I just linked, to be honest.
Thanks for writing the tests, though -- that's really useful!
Comment #7
phenaproximaThis might be a duplicate of #3043725: Provide a Entity Handler for user cancelation.
Comment #8
spokjeI separated the test only from #2 to see if the (much) smaller patch in this issue 3057004#2 already would suffice.
Let's try the test only first.
Comment #9
spokjeExcellent test by Beram there!
Let's see if (rather minimalistic) patch from olivier.bouwman in 3057004#2 does the trick
Comment #10
spokjeAnd a D8.8 test only patch derived from #2
Comment #11
spokjeSo patch #9 isn't enough to cover the issues in the test.
EDIT: After a nights sleep: Testing #9 like that isn't fair. It solves the problem differently, and never triggers any of the things that test #8 looks for.
#2: Solves the problem at the root: When a user is deleted, its content is either deleted or assigned to uid = 0.
Patch #9 is more like a Just In Time solution: Whenever a Media entity is saved and the owning user was deleted at some point, it sets the owner to uid = 0 in a presave hook, preventing Drupal go CLUNK on the actual save.
Whilst #9 has far less code, it only fixes the problem for Media entities that are being edited. That means it leaves Media entities without an existing owner untouched when they're not edited. In my humble opinion this leaves the database in an undesirable state, where Media entities claim to have an existing owner, but they haven't.
Also for Drupal-wide consistency, #2 seems the way to go.
Luckily I am in no position to make a ruling on this :)
Comment #12
spokjeSo now besides boring everybody with endless messages on this issue, I'm going to up the ante and now annoy everyone by putting it back to Needs Work.
Patch #2 works perfectly IMHO, but only for cases after it has been applied.
Which means that in the time between the launch of D8.7 and the landing of this patch, there will be (quite?) some cases out there in the wild, where a media entity owning user has already been deleted, leaving Media entities with invalid owners.
These Media entities aren't fixed by #2 and will cause fatal errors when trying to edit these entities.
I verified this by deleting a user that owned Media entities before applying patch #2, then applying patch #2, going to one of these Media entities and trying to save it.
That ended in tears and the "nice" combo of:
Drupal\Core\Database\IntegrityConstraintViolationException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'uid' cannot be null: INSERT INTO {media_field_data} (mid, vid, bundle, langcode, status, name, thumbnail__target_id, thumbnail__alt, thumbnail__title, thumbnail__width, thumbnail__height, uid, created, changed, default_langcode, revision_translation_affected, content_translation_source, content_translation_outdated) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9, :db_insert_placeholder_10, :db_insert_placeholder_11, :db_insert_placeholder_12, :db_insert_placeholder_13, :db_insert_placeholder_14, :db_insert_placeholder_15, :db_insert_placeholder_16, :db_insert_placeholder_17); Array ( [:db_insert_placeholder_0] => 2535 [:db_insert_placeholder_1] => 2535 [:db_insert_placeholder_2] => images [:db_insert_placeholder_3] => en [:db_insert_placeholder_4] => 1 [:db_insert_placeholder_5] => Bea-Orpen [:db_insert_placeholder_6] => 2650 [:db_insert_placeholder_7] => Black and white photo of a woman seated at a table with an open book in front of her. [:db_insert_placeholder_8] => [:db_insert_placeholder_9] => 780 [:db_insert_placeholder_10] => 1056 [:db_insert_placeholder_11] => [:db_insert_placeholder_12] => 1566569018 [:db_insert_placeholder_13] => 1566889711 [:db_insert_placeholder_14] => 1 [:db_insert_placeholder_15] => 1 [:db_insert_placeholder_16] => und [:db_insert_placeholder_17] => 0 ) in Drupal\Core\Database\Connection->handleQueryException() (line 689 of /app/web/core/lib/Drupal/Core/Database/Connection.php).and
Drupal\Core\Entity\EntityStorageException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'uid' cannot be null: INSERT INTO {media_field_data} (mid, vid, bundle, langcode, status, name, thumbnail__target_id, thumbnail__alt, thumbnail__title, thumbnail__width, thumbnail__height, uid, created, changed, default_langcode, revision_translation_affected, content_translation_source, content_translation_outdated) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9, :db_insert_placeholder_10, :db_insert_placeholder_11, :db_insert_placeholder_12, :db_insert_placeholder_13, :db_insert_placeholder_14, :db_insert_placeholder_15, :db_insert_placeholder_16, :db_insert_placeholder_17); Array ( [:db_insert_placeholder_0] => 2535 [:db_insert_placeholder_1] => 2535 [:db_insert_placeholder_2] => images [:db_insert_placeholder_3] => en [:db_insert_placeholder_4] => 1 [:db_insert_placeholder_5] => Bea-Orpen [:db_insert_placeholder_6] => 2650 [:db_insert_placeholder_7] => Black and white photo of a woman seated at a table with an open book in front of her. [:db_insert_placeholder_8] => [:db_insert_placeholder_9] => 780 [:db_insert_placeholder_10] => 1056 [:db_insert_placeholder_11] => [:db_insert_placeholder_12] => 1566569018 [:db_insert_placeholder_13] => 1566889711 [:db_insert_placeholder_14] => 1 [:db_insert_placeholder_15] => 1 [:db_insert_placeholder_16] => und [:db_insert_placeholder_17] => 0 ) in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 847 of /app/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).I think this patch needs to come with a
hook_update_Nthat identifies and "fixes" these Media entities.Since we have no (easy) way of knowing what the intentions for the content items owned by the deleted user were at the time of deletion, I think we should take the safest approach and set the owner of these Media entities to Anonymous (uid = 0).
To lower the annoyance level and since I now already have a database with a testcase, I will try to upload such a
hook_update_Nshortly.TLDR:
- Patch #2 works perfectly, but only for user-deletions after it has landed.
- Media Entity owning Users which were deleted before landing will lead to editing those Media entities causing a Back-end breaking Error even after the landing of #2.
-
hook_update_Nis needed to identify and "fix" those Media entities. Safest approach is to set their owner to uid = 0.- For that setting this issue to "Needs Work" and since the longer we wait. the bigger the amount of user deletions will be. setting the version of this issue to 8.7.x-dev
Comment #13
beram commentedThanks for the tests!
I opened this issue not to merge this dumb solution but just to provide a quick fix, a temporary solution fo people that needs to cancel users.
IMHO we should focus our effort in Some content entities are missing hook_user_cancel implementations:
Because we cannot copy/paste this and https://www.drupal.org/project/drupal/issues/3057004 for all entities that needs it and because canceling users is not the only point (for instance the owner is mandatory but the interface does not show it for a media).
About the
hook_update_Nhere the one I used on my sites. Should we add it to this patch? My first thought was people should add it to their own custom module to avoid issues with thehook_update_Nversions.Comment #14
spokjeThanks @beram (also for your patch and tests :).
I fully agree we need a generic solution and we need it fast. I've already encounter this problem with Media, File and Taxonomy having put "only" 11 of our sites on D8.7.6 in the last 2 weeks.
However, I also believe that the generic solution will take (some/a lot of?) time to get fully implemented tested and with back-end breaking consequences leading to sad/angry/slightly disappointed users/clients, I don't think we have that time.
Having said that, I'm heading over to the "Generic Solution" issue, change it to priority Major and version 8.7.x-dev and ask the Big Brains around there to come up with a verdict on focussing on the Generic Solution or going with your approach, plugging the current holes in File/Media/Taxonomy first and then refactoring into something nice and generic.
Comment #15
spokje@phenaproxima What's your position on Quick Win and Do-It-Generic later vs. Do-It-Generic in the first place?
It doesn't make much sense to put in effort on this issue if you and other Big Brains are not willing to go for the Quick Win first.
Comment #16
beram commentedThinking out loud: a better quick win for the user cancel issue could be to convert
node_mass_update()toentity_mass_update()?Comment #17
spokjeAdded a test to show the actual errors this issue is causing when trying to save a Media entity that has a deleted owner for #3043725: Provide a Entity Handler for user cancelation, might as well add it into this patch.
D8.7 Test-only first
Comment #18
spokjeCombining the excellent work of beram with new test.
Comment #19
spokjeThat's what you get when combining excellent with crappy work: crappy work... :/
This should be better.
Comment #20
ducktape commentedUpdated for 8.8 and 8.9
Comment #22
ducktape commentedFixed deprecations for 9.x.
Comment #24
aaronmchaleFixing issue link in IS.
Comment #25
aaronmchale#3043725: Provide a Entity Handler for user cancelation is coming along nicely and already has core committer buy-in for the proposed resolution, so at this rate it might make more sense to just postpone this issue and resume once that issue is committed.
Comment #26
aaronmchaleAnother link.
Comment #27
phenaproximaComment #28
phenaproximaI think that this problem would be solved by #3043725: Provide a Entity Handler for user cancelation, so I'm closing this issue as a duplicate.
Comment #29
fernly commentedFor the time being I rerolled this patch for 9.1.x based on 9.1.6.
Comment #30
fernly commentedRerolled patch for 9.1.10.
Comment #31
mpp commentedComment #33
mpp commentedComment #34
fernly commentedRerolled patch for latest 9.3.x
Comment #35
redzeufSimple hook patch to reassign to the anonymous user whatever we select the unpublish or reassign method.
I used a direct query to change the uid and revision_uid for performance reason (not loading and resaving medias).
I did not integrate the tests.
Comment #36
redzeufJust added a clear cache of the media entities, to the previous patch.
Without this clear cache we still have the error untill the media cache or rebuild.
Comment #37
redzeufError in last commit, I removed UserInterface class :(
Comment #38
redzeufAfter deploying on my dev/staging env. with Varnish I had an issue with the cache because my past patch was deleting directly the cache table. In this patch I with a drupal way function to clear full cache.
Comment #39
fernly commentedBecause #3043725: Provide a Entity Handler for user cancelation is not ready yet, I rerolled this quick fix against drupal 11.x-dev.
Comment #40
fernly commentedAnd another patch specifically for Drupal 11.1.7. Apparently the latest D11 dev version already differs from Drupal 11.1.7.
So when you are higher than Drupal 11.1.7, you might need the patch posted in #39.
Comment #41
fernly commentedIssue is closed (duplicate) but since there is no working solution yet, updating this patch.
Attached patch for use with Drupal 11.3.3.