cms
cms copied to clipboard
EntrySaved event is triggered twice
Bug description
I have developed a private addon for one of our websites and noticed that the EntrySaved event is triggered twice.
This means that listeners that listen to the event are also executed twice. But this should not happen! Especially if third-party systems etc. are still influenced by this.
How to reproduce
You can easily reproduce this: Just register a Laravel event listener on the event and then write a log to the handle() method.
Alternatively, you can also reproduce the duplicate event via Telescope.
Logs
No response
Environment
Environment
Application Name: Konkav & K16
Laravel Version: 10.39.0
PHP Version: 8.2.14
Composer Version: 2.5.5
Environment: local
Debug Mode: ENABLED
URL: k16-konkav-cms.test
Maintenance Mode: OFF
Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED
Drivers
Broadcasting: log
Cache: statamic
Database: mysql
Logs: stack / single
Mail: smtp
Queue: redis
Session: file
Statamic
Addons: 8
Antlers: runtime
Stache Watcher: Enabled
Static Caching: Disabled
Version: 4.42.0 PRO
Statamic Addons
aryehraber/statamic-uuid: 2.2.0
jonassiewertsen/statamic-documentation: 1.9.0
morethingsdigital/personio: dev-main
morethingsdigital/statamic-nextjs: dev-main
studio1902/statamic-peak-browser-appearance: 3.3.4
studio1902/statamic-peak-commands: 2.7.0
studio1902/statamic-peak-seo: 5.0
studio1902/statamic-peak-tools: 3.4.3
Installation
Fresh statamic/statamic site via CLI
Antlers Parser
None
Additional details
Possibly the reason: After initial research, I was able to trace it back to the CollectionTree being updated/saved after the entry was updated/saved. However, the CollectionTree then saves the entry again and this leads to the second event.
I think that saving the entry in the CollectionTree should take place unnoticed.
Is it possible that you are on a multi-site install and the extra event you're seeing is the entry descendant being saved? When I save an entry via the CP (one thats in a collection structure), I only see one EntrySaved event fired.
Is it possible that you are on a multi-site install and the extra event you're seeing is the entry descendant being saved? When I save an entry via the CP (one thats in a collection structure), I only see one EntrySaved event fired.
This sounds like the most likely reason this would be happening. You can use the $event->isInitial()
method to check if the event is the "true" save event for that entry. See https://github.com/statamic/cms/pull/8605.
If you're not using multi-site or that isInitial
fix doesn't work for you, please leave a comment and we can re-open the issue.
I wrote a listener in a custom private Add-On. Our project is a multisite one.
class EntrySaved extends AuditTrailListener
{
public function handle(\Statamic\Events\EntrySaved $event): void
{
/** @var Entry $entry */
$entry = $event->entry;
info('EntrySaved', [
'initial' => $event->isInitial(),
]);
}
}
I am getting the following error:
[2024-01-05 15:58:45] local.ERROR: Call to a member function id() on null {"userId":1,"exception":"[object] (Error(code: 0): Call to a member function id() on null at /[...]/vendor/statamic/cms/src/Events/EntrySaved.php:26)
[stacktrace]
Am I doing something wrong?
I used the $event->initiator property. I don't know if I am doing well.
Is the initiator
property null
?
@jasonvarga Yes, initiator
is null
Just trying to figure out why initiator
might be null
- because we can't reproduce it... 🤔
How are you saving the entry that triggers the EntrySaved
event? In the Control Panel or manually in some code?
Do you have any other event listeners?
Hi @duncanmcclean,
Thank you for your reply. We are using Statamic in a Laravel 10 installation. We wrote a custom private Add-On, and we are using 3 Listener with it:
- EntryCreated
- EntrySaved
- EntryDeleted
On each Listener we are going to store a record in the db, a simple audit log: "John Doe saved the post", for example.
The EventServiceProvider of the application is also Listen those three events:
EntryCreated::class => [
\Domain\OtherStuff\Listeners\EntryCreated::class,
SetSupportFieldsStuff::class,
CreateAnotherStuff::class,
],
EntrySaved::class => [
\Domain\OtherStuff\Listeners\EntrySaved::class,
],
EntryDeleted::class => [
\Domain\OtherStuff\Listeners\EntryDeleted::class,
],
In those Listener we are also saving Entries, using $entry->saveQuietly()
I doubt it'll fix it but could you try disabling the other listeners and keep just the EntrySaved
one to see if that helps at all?
I am pretty sure it won't fixes. Anyway I will try later and I'all came back to you with a response.
@encodiaweb Just following up on this... did disabling other listeners help?
@duncanmcclean my workmates @encodiaweb workaround that issue. Disabling other listener did't help.
Hmm, that's odd. Are you able to reproduce the issue in a fresh Statamic site?
This issue has not had recent activity and has been marked as stale — by me, a robot. Simply reply to keep it open and send me away. If you do nothing, I will close it in a week. I have no feelings, so whatever you do is fine by me.
I am getting this same issue. isInitial() works when I am saving an existing entry. But when i create a new entry and save it the initiator is null and throws Call to a member function id() on null error.
@sattyframework Are you able to provide access to your site or reproduce the issue on a fresh Statamic site?
I am not able to share the site unfortunately as the project is under NDA. For me the issue does not happen locally, it is only occurring on production build. I have managed to do a work around mean time though which has resolved the bug for me.
$entry = $event->entry;
$initiator = $event->initiator;
if($initiator && $initiator->id()) {
if($event->isInitial()) {
.....
}
}
Are you able to provide the output of php please support:details
?
Environment
Application Name: Statamic
Laravel Version: 11.15.0
PHP Version: 8.2.20
Composer Version: 2.7.7
Environment: local
Debug Mode: ENABLED
URL: peacenail.test
Maintenance Mode: OFF
Timezone: UTC
Locale: en
Cache
Config: NOT CACHED
Events: NOT CACHED
Routes: NOT CACHED
Views: CACHED
Drivers
Broadcasting: reverb
Cache: file
Database: mysql
Logs: stack / single
Mail: log
Queue: database
Session: file
Statamic
Addons: 7
Sites: 3 (UK, US, German)
Stache Watcher: Enabled
Static Caching: Disabled
Version: 5.14.0 PRO
Statamic Addons
jacksleight/statamic-bard-texstyle: 3.2.2
ncla/statamic-focal-point-fieldtype: 4.0.0
rias/statamic-link-it: 2.4.0
ryanmitchell/statamic-translation-manager: 2.0.0
spatie/statamic-responsive-images: 5.0.0
statamic/eloquent-driver: 4.9.0
statamic/seo-pro: 6.0.3
Statamic Eloquent Driver
Asset Containers: eloquent
Assets: eloquent
Blueprints: eloquent
Collection Trees: eloquent
Collections: eloquent
Entries: eloquent
Forms: eloquent
Global Sets: eloquent
Global Variables: eloquent
Navigation Trees: eloquent
Navigations: eloquent
Revisions: file
Taxonomies: eloquent
Terms: eloquent
Tokens: eloquent
I've just attempted to reproduce this again, but using the database
queue driver instead of sync
, but it's still working fine for me 🤔
Are you able to share your full event listener class?