Download the PHP package gazugafan/laravel-temporal without Composer
On this page you can find all versions of the php package gazugafan/laravel-temporal. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package laravel-temporal
Laravel Temporal Models
Temporal models and versioning for Laravel
You know what's crazy? Database updates. You update a record and BAM! The previous version of the record is overwritten. What was it like before you updated it? No one knows. The data has been lost forever. More like database overwrites, amirite?
If you're not in the business of losing data forever, you should give temporal models a try! It's like version control for your database records. Now when you update something, the previous version of it is kept intact, and a new revision is inserted instead.
Normally you're only going to care about the current versions of things, so by default that's all you'll get when querying. But the old versions are always there too if you want to get at them. Now when someone asks "what was this thing like before the latest change?" or "what did this thing dress as last Halloween?" or "did this thing always have a tail?", you'll have all the answers.
Requirements
- This has been unit tested, but only on Laravel 5.4 with PHP 7.1, Laravel 6.0 with PHP 7.2 and Laravel 8.0 with PHP 8.0.3. Let me know if you find it works on older versions!
- Also only tested with MySQL/MariaDB. Likely will not work with SQLite, but let me know if you find it works with other databases!
Installation
Install via Composer...
For Laravel 5 use the version 1.1
For Laravel 6.0 use the version 2.0
For Laravel 7.0 use the version 3.0
For Laravel 8.0 use the version 4.0
For Laravel 9.0 use the version 5.0.1
Overview
Temporal models get three new fields...
- represents the version number of a record (1 would be the original version, 2 would be the second version, etc.). Versions always start at 1, and will never have a gap.
- and represent the range of time a version is/was active. If a revision is currently active, temporal_end will automatically be set VERY far into the future.
Whenever you save or update a model, the previous version's is updated to mark the end of its lifespan, and a new version is inserted with an incremented .
When querying for temporal models, we automatically constrain the query so that only current versions are returned. Getting at old revisions is also possible using added methods.
When paired with laravel-changelog, this will give you the history of every change made to a record, including who made each change and exactly what was changed.
Schema Migration
You'll need to modify your table's schema a bit. The bad news is that Laravel doesn't really "support" the modifications we need to make, so we have to resort to some ugly workarounds. The good news is that I made a helper class that handles all the dirty work for you!
What's actually going on here...
The actual changes necessary are:
- Add an unsigned integer column as an additional primary key.
- Add datetime and columns.
- Add indexes to make sure queries stay just as fast. I'd recommend two additional indexes...
- for getting current revisions (which we do all the time)
- for getting revisions at a certain date/time
Laravel doesn't have an easy mechanism for specifying multiple primary keys along with an auto-increment key. To work around this, does some raw MySQL commands. This most likely will NOT work on non-MySQL databases like SQLite.
Model Setup
To make your model temporal, just add the trait to the model's class...
You can also customize the column names and maximum temporal timestamp, if you'd like to change them from the defaults...
Usage
Saving temporal models
When you first save a new record, it is inserted into the database with a of 1, a of the current date/time, and a of WAY in the future ('2999-01-01' by default). Thus, this first revision is currently active from now to forever.
The next time you save this record, the previous revision's is automatically updated to the current date/time--marking the end of that version's lifespan. The new revision is then inserted into the database with its incremented by 1, and its and updated as before. Thus, the previous version is now inactive, and the new version is currently active.
You can only save the newest version of a record. If you find an old version of something and try to modify it, an error will be thrown... you can't change the past.
If you want to overwrite the latest revision, use instead of . This will simply update the revision instead of inserting a new one. It totally defeats the purpose of using temporal models, but it can be useful for making frequent tiny changes. Like incrementing/decrementing something on a set schedule, or updating a cached calculation.
You can also automatically overwrite whenever you perform a if only columns you've defined as have been changed. Just add an array property to your model like this: and we'll automatically perform an overwrite (instead of inserting a new version) when only those columns are changing. If you notice lots of unnecessary versions in your table just because of one or two columns changing that you don't care about the history of, add those columns here!
Retrieving temporal models
By default, all temporal model queries will be constrained so that only current versions are returned.
If you want to get all versions for some reason, you can use the method to remove the global scope...
You can also get specific versions, and traverse through versions of a certain record...
And there are similar query builder methods...
Deleting temporal models
When you call on a temporal model, we don't actually DELETE anything. We just set its to now--thereby marking the end of that revision's lifespan. And, without a current revision inserted to follow it, the record is effectively non-existant in the present. So, querying for it like normal won't get you anything.
It's like you get SoftDelete functionality for free! You can even restore deleted records...
Keep in mind that you can only delete/restore the current/latest version of a record. If you really want to permanently remove a record from the database, you can use . This DELETEs every version of the record, and cannot be undone.
Reference
Check out the full documentation here
Pitfalls
- You cannot change the past. Attempting to save or delete anything but the current version of a record will result in an error. Attempting to restore anything but the latest version of a deleted record will result in an error.
-
Mass-updating will not respect the temporal model features, and unfortunately I don't know how to throw an error if you try. If you attempt something like the following, don't expect it to insert new revisions...
-
Saving changes to two copies of the same record will NOT cause the second save to update the first copy's record. However, because of our composite primary key (which includes , attempting this will simply throw an error...
- When a revision is overwritten, its field is automatically updated. This means it's possible to have an field that does not match the revision's . The field, however, is NOT updated (which ensures version numbers always start at 1 and never have gaps).
- We can't automatically add the temporal restriction to queries outside of the query builder specific to the temporal Eloquent model. If you need to do some manual (non-ORM) queries, remember to add a WHERE clause to only get the latest versions ().
- The validation method does NOT respect temporal models. So, it will consider ALL versions and fail even if old versions of a record have the same value. This should quickly become apparant if you make your User model temporal. If you want a tweaked validation method that works for temporal models, try something like this...
Credits
Inspired by navjobs/temporal-models and FuelPHP's temporal models
All versions of laravel-temporal with dependencies
illuminate/database Version ^9.0
illuminate/events Version ^9.0
doctrine/dbal Version ^2.5
laravel/helpers Version ^1.2