Problem/Motivation
In order to intercept an entity after it has saved, both hook_entity_insert and hook_entity_update must be implemented.
Proposed resolution
Add hook_entity_postsave. Detect if entity is new or being updated using entity API: $entity->isNew()
Remaining tasks
User interface changes
None
API changes
Deprecate hook_entity_[type_]insert and hook_entity_[type_]update.
Data model changes
Original report by ivanjaros
We already have a hook_entity_presave hook so why don't we also have hook_entity_postsave?
In current state if I want to run some logic after the entity hase been saved, and I don't care if it is/was new or already existing entity, I have to implement TWO hooks instead of just one: hook_entity_insert AND hook_entity_update.
| Comment | File | Size | Author |
|---|---|---|---|
| #45 | 2221347-45.patch | 7.12 KB | piotrsmykaj |
| #39 | 2221347-39.patch | 9.69 KB | peter_serfozo |
| #26 | 2221347-26.patch | 9.24 KB | ravi.shankar |
| #6 | add_hook_entity_post_save_hook-2221347-6.patch | 9.28 KB | drikc |
Issue fork drupal-2221347
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 #1
dpiI was thinking the same today.
Comment #2
swentel commentedI think the rational at some point was to not have any $op parameters anymore in hooks, which in the days of hook_nodeapi() made sense, because everything passed through that hook. Ironically, if you take the rational strict, there should have been an presave_insert and presave_update :-)
If we'd introduce post_save, then _insert and _update in a way don't make any sense anymore and those should be removed because you can all isNew() to figure out if it's a new or existing (although we can't for BC reasons). I agree, if you don't care about it, it's kind of tedious having to implement those two hooks, I actually could have used it as well.
Features are 8.1 though.
Comment #3
Anonymous (not verified) commentedTo me, this would make more sense to me
hook_entity_presave($entity, $is_new)andhook_entity_postsave($entity, $was_new)than ofhook_entity_presave($entity)andhook_entity_insert($entity)/hook_entity_update($entity).Sure, if we have isNew() then no $op is not needed as mentioned.
Comment #4
dpiSounds reasonable to me. Added standard template.
Comment #5
dpiextra words
Comment #6
drikc commentedThe attached patch add the hook_entity_postsave() call right after the hook_entity_insert()/update() call. I may also remove the hook_entity_insert()/update() tests since they will be deprecated!?...
Remaining things I'm thinking off:
- Update core/lib/Drupal/Core/Entity/entity.api.php
- ...
Comment #7
swentel commentedHmm no, we shouldn't remove tests as long it's there.
Comment #11
tstoecklerMarked #2848894: new hook to cover both entity insert and update - hook_entity_postsave as duplicate.
Comment #12
dpi#2798783: hook_entity_insert() and hook_entity_update() are confusing is also a dupe.
Comment #13
tim.plunkettClosing my issue. Please copy over the api.php changes as well as the @todo/deprecation comments.
Comment #14
dpi#2798783: hook_entity_insert() and hook_entity_update() are confusing, for reference.
Comment #15
berdirI don't think that isNew() works, would definitely need more specific tests than just checking that it is called.
At this point, the entity is no longer new as it has been saved already. That's why we pass the additional flag to postSave().
Also agreed that if we do this, we should deprecate the other two hooks.
Comment #16
aaronbaumanAdding related events-dispatching discussion, which will require a re-roll here if it lands first.
Comment #24
carlitus commented¿This will be added to core?
Comment #25
hchonovRe #15:
Well this actually has the answer in it :). The post save hook should be consistent with the postSave method and have a second parameter indicating whether this is an insert or update operation.
Comment #26
ravi.shankar commentedAdded reroll of patch #6 on Drupal-9.2.x.
Comment #32
megakeegman commentedThis seems like people participating in this thread have been in agreement that this change would be a good thing. I am also in a situation right now where I am needing to implement both insert and update, and dreaming of a hook_entity_postsave. Is there anything that can be done to keep this issue moving? I would be happy to assist with reviewing patches on D10 if that will help.
Comment #33
dpiHad a thought, what if we call this hook
hook_entity_upsert?Since thats what DB's etc use. Our terminology cleanly already matches it with insert/update.
Comment #34
megakeegman commentedI don't have particularly strong feelings about this, and would be okay with this direction. But I think I prefer postsave. For one, it will be clearer that this occurs later than presave. Additionally, insert, update, upsert, are all database language. Maybe my expectations are off, but I did not find this hook naming to be the most intuitive. I expect this will change between people, but as a Drupal developer I was looking for something closer to Drupal language, and not database language. I understand why insert is called insert, but it did not stand out to me as what I was looking for immediately. I think my prior point is the more important one for me. Though I am stating these preferences, I can appreciate the idea, and ultimately I really just want to see this feature in core, whatever the hook gets called.
Comment #35
jrockowitz commentedMy immediate use case for a postsave hook is for a hook triggered after all insert or update hooks to an entity are executed. The immediate goal of this ticket is to simplify the entity API. My use case might be an edge case.
Comment #36
cosmicdreams commentedI found this issue as a result of an issue I reported to the estimated_read_time module https://www.drupal.org/project/estimated_read_time/issues/3427894
The logic of that module currently executes presave, but can possibly run into trouble when it uses data that only exists after the content is saved.
Without a postsave hook, we could use the Event Dispatcher to hook into entity.post_save. But it's weird there isn't a hook that fires AFTER all the entity saving.
I would appreciate having that today.
Comment #37
peter_serfozo commentedPatch for D11Made a mistake, do not use this patch.
Comment #38
peter_serfozo commentedComment #39
peter_serfozo commentedThe correct patch for D11
Comment #42
donquixote commentedArguably this is no longer needed now that we have hook attribute.
Comment #43
berdirAgreed, it's one extra line now, that's pretty minimal overhead. I'm suggesting we close this. 3 hooks will add confusion as to what the difference is and deprecating insert/update seems like a _lot_ of work with limited benefit.
There's another issue where hooks that happen after the transaction are being discussed, I thought at first it's this one, but this just adds it directly after insert/update.
Comment #45
piotrsmykaj commentedNevertheless, I will add the reroll for D11.3, as the suggestion in #42 at the end doesn't give the same guarantee that the patch provides.
The patch runs hook_entity_postsave() AFTER the hook_entity_insert() and hook_entity_update() are finished.
The suggestion in #42 may run the code BEFORE hook_entity_insert() and hook_entity_update() are completed.
Comment #46
berdir> The suggestion in #42 may run the code BEFORE hook_entity_insert() and hook_entity_update() are completed.
No, it doesn't run BEFORE. It is a part of those hooks, it is neither before nor after. just like your postsave hook implementation could be before or after other implementations.
OOP hooks provide convenient definitions to specify if your hook should run last if that's what you want: https://www.drupal.org/node/3493962
postsave is still within the transaction, so when it runs then then the changes are not yet available to other processes. hook-as-services make it reasonable simple to run something then delayed in a terminable service, that is then outside of the transaction.