- Lunar version: 2.0.0-alpha.4
- Laravel Version: 13.19.0
- PHP Version: 8.5.7
- Database Driver & Version: 11.8.6
What I found
I found that the catalog invalidation contract describes its captured scalar identity as authoritative for deleted targets and queued listeners. However, the model-bearing invalidation events useSerializesModels and expose the affected Eloquent model as a required property.
After a hard delete commits, a queued listener deserializing the event asks Laravel to restore that model with firstOrFail(). Because the row no longer exists, deserialization can throw ModelNotFoundException before the listener can read morphType(), cacheKey(), or cacheTags(). Retrying cannot restore a row that has been deleted.
The same required-model pattern is present in the Product, Collection, Brand, and ProductOption invalidation events.
How to reproduce
- Register a queued listener for a catalog invalidation event.
- Hard-delete the corresponding catalog model and commit.
- Process the queued listener.
- Observe model restoration fail before the handler reads the captured scalar identity.
Suggested resolution
The supported queued-listener surface should be scalar-first and must not require model rehydration. One backward-compatible direction is an additive scalar-only event or entity-reference DTO dispatched alongside the existing model-bearing events. Synchronous consumers that require a live model could continue using the existing events while the scalar companion becomes the documented queued contract.
This is not a safe one-line change: removing SerializesModels can serialize a larger, stale model graph, while removing or making cacheModel() nullable changes the existing public contract.
Regression coverage
Please add real queue-serialization tests after committed hard deletes for Product, Collection, Brand, and ProductOption invalidation events. The queued handler should be able to read the captured scalar identity without restoring the deleted row.
Pull request
I can provide a pull request implementing the agreed backward-compatible queue-safe surface and the deletion/serialization regression tests above. I would first align the implementation with the maintainers' preferred compatibility direction for model-based listeners.
Relevant source:
packages/core/src/Contracts/CacheInvalidationEvent.php,
packages/core/src/Events/Catalog/, and Laravel's
Illuminate/Queue/SerializesAndRestoresModelIdentifiers.php.
What I found
I found that the catalog invalidation contract describes its captured scalar identity as authoritative for deleted targets and queued listeners. However, the model-bearing invalidation events use
SerializesModelsand expose the affected Eloquent model as a required property.After a hard delete commits, a queued listener deserializing the event asks Laravel to restore that model with
firstOrFail(). Because the row no longer exists, deserialization can throwModelNotFoundExceptionbefore the listener can readmorphType(),cacheKey(), orcacheTags(). Retrying cannot restore a row that has been deleted.The same required-model pattern is present in the Product, Collection, Brand, and ProductOption invalidation events.
How to reproduce
Suggested resolution
The supported queued-listener surface should be scalar-first and must not require model rehydration. One backward-compatible direction is an additive scalar-only event or entity-reference DTO dispatched alongside the existing model-bearing events. Synchronous consumers that require a live model could continue using the existing events while the scalar companion becomes the documented queued contract.
This is not a safe one-line change: removing
SerializesModelscan serialize a larger, stale model graph, while removing or makingcacheModel()nullable changes the existing public contract.Regression coverage
Please add real queue-serialization tests after committed hard deletes for Product, Collection, Brand, and ProductOption invalidation events. The queued handler should be able to read the captured scalar identity without restoring the deleted row.
Pull request
I can provide a pull request implementing the agreed backward-compatible queue-safe surface and the deletion/serialization regression tests above. I would first align the implementation with the maintainers' preferred compatibility direction for model-based listeners.
Relevant source:
packages/core/src/Contracts/CacheInvalidationEvent.php,packages/core/src/Events/Catalog/, and Laravel'sIlluminate/Queue/SerializesAndRestoresModelIdentifiers.php.