Download the PHP package dvarilek/laravel-snap without Composer
On this page you can find all versions of the php package dvarilek/laravel-snap. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download dvarilek/laravel-snap
More information about dvarilek/laravel-snap
Files in dvarilek/laravel-snap
Package laravel-snap
Short Description A Laravel package for capturing and persisting the state of Eloquent models along with their relationships.
License MIT
Informations about the package laravel-snap
Laravel Snap
Overview
Laravel Snap is a robust and easily configurable package for versioning your application's Eloquent Models by capturing their full context in a Snapshot - this even includes attributes from related Models.
Model versions are stored in Snapshots. A Snapshot is a copied state of a Model - state meaning its attributes alongside important metadata like their casts. Obviously, since the attributes are copied, no synchronization is done on updates, meaning the state gets truly persisted.
A Snapshot can not only store Model attributes from a single Model, but Laravel Snap even handles storing of related Model attributes relative to the origin Model. Related attributes are stored directly in the Snapshot - no 'related' Snapshot gets created and linked to. This means that the full context of a record gets captured and persisted in a single Snapshot. (useful for legislative requirements and auditing purposes)
Installation
1. Install the package:
2. Initialize the package
Additionally, you can publish the config:
Getting Started
- Firstly, we need to use Snapshotable trait inside our Model. The 'getSnapshotDefinition' method specifies, what should and shouldn't get captured in a Snapshot.
[!NOTE]\ To see all configuration options for SnapshotDefinition, see the Snapshot Configuration section.
- Then simply call the 'takeSnapshot' method on your Model:
[!NOTE]\ For more information and options, see the Snapshots section.
Snapshot Configuration
The configuration of what exactly gets and doesn't get captured in a Snapshot is done fluently through a SnapshotDefinition.
Capturing Model Attributes
Capture all model attributes. Hidden attributes are excluded unless specifically enabled:
\ Capture only specific attributes from the model:
\ By default, hidden attributes are excluded even when specified in the capture method. To enable capturing hidden attributes you can use:
\ Prevent specified attributes from being included in the Snapshot:
\ By default, attribute casting (like dates, enums, arrays, collections) is preserved in the Snapshot. To store attributes without their original casting types, you can specifically disable this feature:
\ Exclude Laravel's timestamp fields (created_at, updated_at, deleted_at) from the snapshot:
[!IMPORTANT]\ When timestamps are captured (not excluded), they are prefixed with 'origin_' to prevent conflicts with the Snapshot's own timestamps. For example, the model's 'created_at' becomes 'origin_createdat' in the Snapshot. The timestamp prefix ('origin' by default) can be modified in the package's config file.
Capturing Related Attributes
Capturing attributes from related models stores them in the same Snapshot. The captured attributes are prefixed by their relation path relative to the main model. This is done to avoid potential naming conflicts between attributes.
To capture related attributes you need to provide a RelationDefinition(s):
[!NOTE]\ RelationDefinition is a superset of SnapshotDefinition, meaning it has access to all its methods, meaning methods like captureAll(), exclude(), excludeTimestamps(), etc. are available.
[!IMPORTANT]\ Currently, only BelongsTo relationship is supported. Support for other relationships is planned for future releases.
Capturing Nested Related Attributes
You can capture deeply nested related attributes by capturing them like this: The same prefix rules apply.
Snapshots
Working With Snapshots
Taking Snapshots \ After using the Snapshotable trait in your Model, you can take Snapshots like this:
The 'takeSnapshot' method accepts an array of extra attributes that can be provided at runtime. These attributes are then stored in the created Snapshot:
[!TIP] The extra attributes can even bypass SnapshotDefinition constraints.
Retrieving\ For convenience, the Snapshotable trait adds two relationships for getting the latest and oldest Snapshots out of the box:
The Snapshot stores its captured attributes in a special JSON column structure. However, you are able to interact with them directly as if they were regular model attributes with property access:
[!NOTE]\ For more information about how these attributes are stored, see the Internal Implementation section.
Updating \ Snapshots support both mass assignment and individual property updates:
Querying \ Because Snapshot attributes are stored in a JSON column, they can't be queried directly as they need to be queried in the JSON column. For more information about JSON querying see the Official Laravel Documentation
Reverting & Versioning
Basic Reverting\ Reverting allows you to restore a Model's state to one of its previous snapshots:
The sync method on Snapshot model is a convenient shortcut to synchronize the Snapshot's state with its origin model. In other words, the code above can be replaced with this:
Currently, there is no way to configure what exactly gets and doesn't get reverted from a Snapshot like there is for taking Snapshots with SnapshotDefinition. However, you can optionally configure if related model attributes should be also restored from the Snapshot.
Versioning\ To enable full versioning capabilities, your Snapshotable model can optionally include a column that tracks the model's current version. This column is optional but required for version-based operations like 'rewind' and 'forward'.
If you don't want to manually create and migrate the migration, you can do so by running:
The command automatically generates a migration for your model and, if confirmed, migrates it.
[!NOTE]\ If you run this command without specifying a model, or if the specified model is invalid, the command will attempt to look for valid models and prompt you for selection.
Once versioning is enabled, you can navigate through the Model's history by steps. The 'rewind' method allows you to move backward through your model's history by a specified number of steps:
Similar to 'rewind', the 'forward' method allows you to move forward through your model's history:
Both 'forward' and 'rewind' methods call the 'revertTo' method internally and accept the following optional arguments:
- shouldDefaultToNearest:\ When set to true, this allows you to revert to the closest snapshot in the direction given by the operation type if no exact match is found. For example, if you're rewinding 3 steps but only snapshots for steps 2 and 4 exist, it will use the snapshot at step 2 (the nearest available in the rewind direction).
- shouldRestoreRelatedAttributes:\ When set to true, the operation will also restore attributes of related models - same as with 'revertTo' method.
Race Conditions
Concurrent snapshotting and reverting operations by different users can lead to inconsistent behavior. Laravel Snap prevents these race conditions by using Laravel's atomic locks feature. Once a lock is acquired, it waits until the operation finishes before allowing other processes to proceed.
The cache lock names and timeouts can be configured inside the package's config file under 'concurrency'.
Event Hooks
While working with snapshots, you can hook into the snapshotting and reverting processes:
[!IMPORTANT]\ Both 'rewind' and 'forward' methods dispatch the 'reverting' and 'reverted' events.
Advanced
Internal Implementation
Storage\
Snapshots are stored in a dedicated table (model_snapshots) and connected to their original models through a polymorphic
relationship. The captured attributes are kept in a special JSON 'storage' column with in a structured format,
preserving all of their necessary metadata.
-
Base Model Attribute Storage Format\ Regular model attributes are stored in the format below and represented using AttributeTransferObject DTO throughout the package.
- Related Model Attribute Storage Format \ Related model attributes are kept in the format below and represented using RelatedAttributeTransferObject DTO throughout the package.
[!NOTE]\ relationPath is an array of ordered relationship names relative to the base model.
Data Manipulation \ Working with JSON-encoded data directly through the Snapshot model is possible by hooking into the Model's event handling.
Attributes are decoded from the storage column and set as the model's attributes, subsequent updates to these attributes are then persisted by encoding them back into the storage column's JSON. The internal implementation of attributes encoding and decoding is partially derived from VirtualColumn Laravel package
Advanced Usage
DTO Usage\ Internally, all Snapshot attributes are set using the mentioned special DTO's. This is useful to know when you want to update Snapshots by appending them with extra attributes or by modifying their existing attributes if you for example wish to change their casts.
Additionally, extra attribute information can also be provided when creating a Snapshot with extra attributes.
Testing
Changelog
Please refer to Package Releases for more information about changes.
License
This package is under the MIT License. Please refer to License File for more information
All versions of laravel-snap with dependencies
illuminate/database Version ^10.0|^11.0
illuminate/support Version ^10.0|^11.0
illuminate/contracts Version ^10.0|^11.0
spatie/laravel-package-tools Version ^1.18