{"id":13396106,"url":"https://github.com/VentureCraft/revisionable","last_synced_at":"2025-03-13T22:31:41.527Z","repository":{"id":7288207,"uuid":"8603408","full_name":"VentureCraft/revisionable","owner":"VentureCraft","description":"Easily create a revision history for any laravel model","archived":false,"fork":false,"pushed_at":"2025-02-16T23:56:25.000Z","size":299,"stargazers_count":2578,"open_issues_count":123,"forks_count":351,"subscribers_count":64,"default_branch":"master","last_synced_at":"2025-03-13T17:01:45.432Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://twitter.com/duellsy","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/VentureCraft.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-03-06T12:59:11.000Z","updated_at":"2025-03-13T16:15:26.000Z","dependencies_parsed_at":"2023-01-13T14:19:45.512Z","dependency_job_id":"18555acd-d484-4fcd-947c-83b64f54ee1f","html_url":"https://github.com/VentureCraft/revisionable","commit_stats":{"total_commits":215,"total_committers":63,"mean_commits":"3.4126984126984126","dds":0.5255813953488372,"last_synced_commit":"40b122b7ad2eb42316e1e0a6674d96a6f8295f2d"},"previous_names":[],"tags_count":61,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VentureCraft%2Frevisionable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VentureCraft%2Frevisionable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VentureCraft%2Frevisionable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/VentureCraft%2Frevisionable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/VentureCraft","download_url":"https://codeload.github.com/VentureCraft/revisionable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243493853,"owners_count":20299726,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T18:00:40.256Z","updated_at":"2025-03-13T22:31:41.500Z","avatar_url":"https://github.com/VentureCraft.png","language":"PHP","readme":"\u003cimg src=\"https://cdn1.wwe.com/static/ossimg/revisionableghbanner.png\" style=\"width: 100%\" alt=\"Revisionable for Laravel\" /\u003e\n\n[![Latest Version](https://img.shields.io/github/release/venturecraft/revisionable.svg?style=flat-square)](https://packagist.org/packages/venturecraft/revisionable)\n[![Downloads](https://img.shields.io/packagist/dt/venturecraft/revisionable.svg?style=flat-square)](https://packagist.org/packages/venturecraft/revisionable)\n[![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://tldrlegal.com/license/mit-license)\n\nWouldn't it be nice to have a revision history for any model in your project, without having to do any work for it. By simply adding the `RevisionableTrait` Trait to your model, you can instantly have just that, and be able to display a history similar to this:\n\n* Chris changed title from 'Something' to 'Something else'\n* Chris changed category from 'News' to 'Breaking news'\n* Matt changed category from 'Breaking news' to 'News'\n\nSo not only can you see a history of what happened, but who did what, so there's accountability.\n\nRevisionable is a laravel package that allows you to keep a revision history for your models without thinking. For some background and info, [see this article](http://www.chrisduell.com/blog/development/keeping-revisions-of-your-laravel-model-data/)\n\n## Working with 3rd party Auth / Eloquent extensions\n\nRevisionable has support for Auth powered by\n* [**Sentry by Cartalyst**](https://cartalyst.com/manual/sentry).\n* [**Sentinel by Cartalyst**](https://cartalyst.com/manual/sentinel).\n\n*(Recommended)* Revisionable can also now be used [as a Trait](#the-new-trait-based-implementation), so your models can continue to extend Eloquent, or any other class that extends Eloquent (like [Ardent](https://github.com/laravelbook/ardent)).\n\n## Installation\n\nRevisionable is installable via [composer](https://getcomposer.org/doc/00-intro.md), the details are on [packagist, here.](https://packagist.org/packages/venturecraft/revisionable)\n\nAdd the following to the `require` section of your projects composer.json file:\n\n```php\n\"venturecraft/revisionable\": \"1.*\",\n```\n\nRun composer update to download the package\n\n```\nphp composer.phar update\n```\n\nOpen config/app.php and register the required service provider  (Laravel 5.x)\n\n```\n'providers' =\u003e [\n\tVenturecraft\\Revisionable\\RevisionableServiceProvider::class,\n]\n```\n\nPublish the configuration and migrations (Laravel 5.x)\n\n```\nphp artisan vendor:publish --provider=\"Venturecraft\\Revisionable\\RevisionableServiceProvider\"\n```\n\nFinally, you'll also need to run migration on the package (Laravel 5.x)\n\n```\nphp artisan migrate\n```\n\nFor Laravel 4.x users:\n```\nphp artisan migrate --package=venturecraft/revisionable\n```\n\n\u003e If you're going to be migrating up and down completely a lot (using `migrate:refresh`), one thing you can do instead is to copy the migration file from the package to your `app/database` folder, and change the classname from `CreateRevisionsTable` to something like `CreateRevisionTable` (without the 's', otherwise you'll get an error saying there's a duplicate class)\n\n\u003e `cp vendor/venturecraft/revisionable/src/migrations/2013_04_09_062329_create_revisions_table.php database/migrations/`\n\n## Docs\n\n* [Implementation](#intro)\n* [More control](#control)\n* [Format output](#formatoutput)\n* [Load revision history](#loadhistory)\n* [Display history](#display)\n* [Contributing](#contributing)\n* [Having troubles?](#faq)\n\n\u003ca name=\"intro\"\u003e\u003c/a\u003e\n## Implementation\n\n### The new, Trait based implementation (recommended)\n\u003e Traits require PHP \u003e= 5.4\n\nFor any model that you want to keep a revision history for, include the `VentureCraft\\Revisionable` namespace and use the `RevisionableTrait` in your model, e.g.,\n\n```php\nnamespace App;\n\nuse \\Venturecraft\\Revisionable\\RevisionableTrait;\n\nclass Article extends \\Illuminate\\Database\\Eloquent\\Model {\n    use RevisionableTrait;\n}\n```\n\n\u003e Being a trait, Revisionable can now be used with the standard Eloquent model, or any class that extends Eloquent, such as [Ardent](https://github.com/laravelbook/ardent).\n\n### Legacy class based implementation\n\n\u003e The new trait based approach is backwards compatible with existing installations of Revisionable. You can still use the below installation instructions, which essentially is extending a wrapper for the trait.\n\nFor any model that you want to keep a revision history for, include the `VentureCraft\\Revisionable` namespace and use the `RevisionableTrait` in your model, e.g.,\n\n```php\nuse Venturecraft\\Revisionable\\Revisionable;\n\nnamespace App;\n\nclass Article extends Revisionable { }\n```\n\n\u003e Note: This also works with namespaced models.\n\n### Implementation notes\n\nIf needed, you can disable the revisioning by setting `$revisionEnabled` to false in your Model. This can be handy if you want to temporarily disable revisioning, or if you want to create your own base Model that extends Revisionable, which all of your models extend, but you want to turn Revisionable off for certain models.\n\n```php\nnamespace App;\n\nuse \\Venturecraft\\Revisionable\\RevisionableTrait;\n\nclass Article extends \\Illuminate\\Database\\Eloquent\\Model {\n    protected $revisionEnabled = false;\n}\n```\n\nYou can also disable revisioning after X many revisions have been made by setting `$historyLimit` to the number of revisions you want to keep before stopping revisions.\n\n```php\nnamespace App;\n\nuse \\Venturecraft\\Revisionable\\RevisionableTrait;\n\nclass Article extends \\Illuminate\\Database\\Eloquent\\Model {\n    protected $revisionEnabled = true;\n    protected $historyLimit = 500; //Stop tracking revisions after 500 changes have been made.\n}\n```\nIn order to maintain a limit on history, but instead of stopping tracking revisions if you want to remove old revisions, you can accommodate that feature by setting `$revisionCleanup`.\n\n```php\nnamespace App;\n\nuse \\Venturecraft\\Revisionable\\RevisionableTrait;\n\nclass Article extends \\Illuminate\\Database\\Eloquent\\Model {\n    protected $revisionEnabled = true;\n    protected $revisionCleanup = true; //Remove old revisions (works only when used with $historyLimit)\n    protected $historyLimit = 500; //Maintain a maximum of 500 changes at any point of time, while cleaning up old revisions.\n}\n```\n\n### Storing Soft Deletes\nBy default, if your model supports soft deletes, Revisionable will store this and any restores as updates on the model.\n\nYou can choose to ignore deletes and restores by adding `deleted_at` to your `$dontKeepRevisionOf` array.\n\nTo better format the output for `deleted_at` entries, you can use the `isEmpty` formatter (see \u003ca href=\"#format-output\"\u003eFormat output\u003c/a\u003e for an example of this.)\n\n\u003ca name=\"control\"\u003e\u003c/a\u003e\n\n### Storing Force Delete\nBy default the Force Delete of a model is not stored as a revision.\n\nIf you want to store the Force Delete as a revision you can override this behavior by setting `revisionForceDeleteEnabled ` to `true` by adding the following to your model:\n```php\nprotected $revisionForceDeleteEnabled = true;\n```\n\nIn which case, the `created_at` field will be stored as a key with the `oldValue()` value equal to the model creation date and the `newValue()` value equal to `null`.\n\n**Attention!** Turn on this setting carefully! Since the model saved in the revision, now does not exist, so you will not be able to get its object or its relations. \n\n### Storing Creations\nBy default the creation of a new model is not stored as a revision.\nOnly subsequent changes to a model is stored.\n\nIf you want to store the creation as a revision you can override this behavior by setting `revisionCreationsEnabled` to `true` by adding the following to your model:\n```php\nprotected $revisionCreationsEnabled = true;\n```\n\n## More Control\n\nNo doubt, there'll be cases where you don't want to store a revision history only for certain fields of the model, this is supported in two different ways. In your model you can either specifiy which fields you explicitly want to track and all other fields are ignored:\n\n```php\nprotected $keepRevisionOf = ['title'];\n```\n\nOr, you can specify which fields you explicitly don't want to track. All other fields will be tracked.\n\n```php\nprotected $dontKeepRevisionOf = ['category_id'];\n```\n\n\u003e The `$keepRevisionOf` setting takes precedence over `$dontKeepRevisionOf`\n\n### Storing additional fields in revisions\n\nIn some cases, you'll want additional metadata from the models in each revision. An example of this might be if you \nhave to keep track of accounts as well as users. Simply create your own new migration to add the fields you'd like to your revision model,\nadd them to your config/revisionable.php in an array like so:\n\n```php \n'additional_fields' =\u003e ['account_id', 'permissions_id', 'other_id'], \n```\n\nIf the column exists in the model, it will be included in the revision. \n\nMake sure that if you can't guarantee the column in every model, you make that column ```nullable()``` in your migrations.  \n\n\n### Events\n\nEvery time a model revision is created an event is fired. You can listen for `revisionable.created`,  \n`revisionable.saved` or `revisionable.deleted`.\n\n```php\n// app/Providers/EventServiceProvider.php\n\npublic function boot()\n{\n    parent::boot();\n\n    $events-\u003elisten('revisionable.*', function($model, $revisions) {\n        // Do something with the revisions or the changed model. \n        dd($model, $revisions);\n    });\n}\n\n```\n\n\u003ca name=\"formatoutput\"\u003e\u003c/a\u003e\n## Format output\n\n\u003e You can continue (and are encouraged to) use `Eloquent accessors` in your model to set the\noutput of your values, see the [Laravel Documentation for more information on accessors](https://laravel.com/docs/eloquent-mutators#accessors-and-mutators)\n\u003e The below documentation is therefor deprecated\n\nIn cases where you want to have control over the format of the output of the values, for example a boolean field, you can set them in the `$revisionFormattedFields` array in your model. e.g.,\n\n```php\nprotected $revisionFormattedFields = [\n    'title'      =\u003e 'string:\u003cstrong\u003e%s\u003c/strong\u003e',\n    'public'     =\u003e 'boolean:No|Yes',\n    'modified'   =\u003e 'datetime:m/d/Y g:i A',\n    'deleted_at' =\u003e 'isEmpty:Active|Deleted'\n];\n```\n\nYou can also override the field name output using the `$revisionFormattedFieldNames` array in your model, e.g.,\n\n```php\nprotected $revisionFormattedFieldNames = [\n    'title'      =\u003e 'Title',\n    'small_name' =\u003e 'Nickname',\n    'deleted_at' =\u003e 'Deleted At'\n];\n```\n\nThis comes into play when you output the revision field name using `$revision-\u003efieldName()`\n\n### String\nTo format a string, simply prefix the value with `string:` and be sure to include `%s` (this is where the actual value will appear in the formatted response), e.g.,\n\n```\nstring:\u003cstrong\u003e%s\u003c/strong\u003e\n```\n\n### Boolean\nBooleans by default will display as a 0 or a 1, which is pretty bland and won't mean much to the end user, so this formatter can be used to output something a bit nicer. Prefix the value with `boolean:` and then add your false and true options separated by a pipe, e.g.,\n\n```\nboolean:No|Yes\n```\n\n### Options\nAnalogous to \"boolean\", only any text or numeric values can act as a source value (often flags are stored in the database). The format allows you to specify different outputs depending on the value.\nLook at this as an associative array in which the key is separated from the value by a dot. Array elements are separated by a vertical line.\n\n```\noptions:search.On the search|network.In networks\n```\n\n### DateTime\nDateTime by default will display as Y-m-d H:i:s. Prefix the value with `datetime:` and then add your datetime format, e.g.,\n\n```\ndatetime:m/d/Y g:i A\n```\n\n### Is Empty\nThis piggy backs off boolean, but instead of testing for a true or false value, it checks if the value is either null or an empty string.\n\n```\nisEmpty:No|Yes\n```\n\nThis can also accept `%s` if you'd like to output the value, something like the following will display 'Nothing' if the value is empty, or the actual value if something exists:\n\n```\nisEmpty:Nothing|%s\n```\n\n\u003ca name=\"loadhistory\"\u003e\u003c/a\u003e\n## Load revision history\n\nTo load the revision history for a given model, simply call the `revisionHistory` method on that model, e.g.,\n\n```php\n$article = Article::find($id);\n$history = $article-\u003erevisionHistory;\n```\n\n\u003ca name=\"display\"\u003e\u003c/a\u003e\n## Displaying history\n\nFor the most part, the revision history will hold enough information to directly output a change history, however in the cases where a foreign key is updated we need to be able to do some mapping and display something nicer than `plan_id changed from 3 to 1`.\n\nTo help with this, there's a few helper methods to display more insightful information, so you can display something like `Chris changed plan from bronze to gold`.\n\nThe above would be the result from this:\n\n```php\n@foreach($account-\u003erevisionHistory as $history )\n    \u003cli\u003e{{ $history-\u003euserResponsible()-\u003efirst_name }} changed {{ $history-\u003efieldName() }} from {{ $history-\u003eoldValue() }} to {{ $history-\u003enewValue() }}\u003c/li\u003e\n@endforeach\n```\n\nIf you have enabled revisions of creations as well you can display it like this:\n```php\n@foreach($resource-\u003erevisionHistory as $history)\n  @if($history-\u003ekey == 'created_at' \u0026\u0026 !$history-\u003eold_value)\n    \u003cli\u003e{{ $history-\u003euserResponsible()-\u003efirst_name }} created this resource at {{ $history-\u003enewValue() }}\u003c/li\u003e\n  @else\n    \u003cli\u003e{{ $history-\u003euserResponsible()-\u003efirst_name }} changed {{ $history-\u003efieldName() }} from {{ $history-\u003eoldValue() }} to {{ $history-\u003enewValue() }}\u003c/li\u003e\n  @endif\n@endforeach\n```\n\n### userResponsible()\n\nReturns the User that was responsible for making the revision. A user model is returned, or false if there was no user recorded.\n\nThe user model that is loaded depends on what you have set in your `config/auth.php` file for the `model` variable.\n\n### fieldName()\n\nReturns the name of the field that was updated, if the field that was updated was a foreign key (at this stage, it simply looks to see if the field has the suffix of `_id`) then the text before `_id` is returned. e.g., if the field was `plan_id`, then `plan` would be returned.\n\n\u003e Remember from above, that you can override the output of a field name with the `$revisionFormattedFieldNames` array in your model.\n\n### identifiableName()\n\nThis is used when the value (old or new) is the id of a foreign key relationship.\n\nBy default, it simply returns the ID of the model that was updated. It is up to you to override this method in your own models to return something meaningful. e.g.,\n\n```php\nuse Venturecraft\\Revisionable\\Revisionable;\n\nclass Article extends Revisionable\n{\n    public function identifiableName()\n    {\n        return $this-\u003etitle;\n    }\n}\n```\n\n### oldValue() and newValue()\n\nGet the value of the model before or after the update. If it was a foreign key, identifiableName() is called.\n\n### Unknown or invalid foreign keys as revisions\nIn cases where the old or new version of a value is a foreign key that no longer exists, or indeed was null, there are two variables that you can set in your model to control the output in these situations:\n\n```php\nprotected $revisionNullString = 'nothing';\nprotected $revisionUnknownString = 'unknown';\n```\n\n### disableRevisionField()\nSometimes temporarily disabling a revisionable field can come in handy, if you want to be able to save an update however don't need to keep a record of the changes.\n\n```php\n$object-\u003edisableRevisionField('title'); // Disables title\n```\n\nor:\n\n```php\n$object-\u003edisableRevisionField(['title', 'content']); // Disables title and content\n```\n\n\u003ca name=\"contributing\"\u003e\u003c/a\u003e\n## Contributing\n\nContributions are encouraged and welcome; to keep things organised, all bugs and requests should be\nopened in the GitHub issues tab for the main project, at [venturecraft/revisionable/issues](https://github.com/venturecraft/revisionable/issues)\n\nAll pull requests should be made to the develop branch, so they can be tested before being merged into the master branch.\n\n\u003ca name=\"faq\"\u003e\u003c/a\u003e\n## Having troubles?\n\nIf you're having troubles with using this package, odds on someone else has already had the same problem. Two places you can look for common answers to your problems are:\n\n* [StackOverflow revisionable tag](https://stackoverflow.com/questions/tagged/revisionable?sort=newest\u0026pageSize=50)\n* [GitHub Issues](https://github.com/VentureCraft/revisionable/issues)\n\n\u003e If you do prefer posting your questions to the public on StackOverflow, please use the 'revisionable' tag.\n","funding_links":[],"categories":["Popular Packages","PHP","Packages","数据库( Database )"],"sub_categories":["Database/Eloquent/Models"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FVentureCraft%2Frevisionable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FVentureCraft%2Frevisionable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FVentureCraft%2Frevisionable/lists"}