hasyirin / laravel-actor
A polymorphic action log for Eloquent models — track who did what, when.
Fund package maintenance!
Requires
- php: ^8.4
- illuminate/contracts: ^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1
- orchestra/testbench: ^10.0.0||^11.0.0
- pestphp/pest: ^3.0||^4.0
- pestphp/pest-plugin-arch: ^3.0||^4.0
- pestphp/pest-plugin-laravel: ^3.0||^4.0
- phpstan/extension-installer: ^1.3||^2.0
- phpstan/phpstan-deprecation-rules: ^1.1||^2.0
- phpstan/phpstan-phpunit: ^1.3||^2.0
- spatie/laravel-ray: ^1.35
This package is auto-updated.
Last update: 2026-05-14 21:42:18 UTC
README
A small polymorphic action log for Eloquent models. Record that an actor (any model — typically a User) performed a named action on a resource (any model), with the time it happened. Each (resource, name) pair holds a single latest-state row.
Installation
composer require hasyirin/laravel-actor
Publish and run the migration:
php artisan vendor:publish --tag="laravel-actor-migrations"
php artisan migrate
Optionally publish the config:
php artisan vendor:publish --tag="laravel-actor-config"
Published config:
return [ 'tables' => [ 'actions' => 'actions', ], 'models' => [ 'action' => \Hasyirin\Actor\Models\Action::class, ], 'guard' => null, ];
Usage
Add the trait to any model that should be a resource (the thing being acted on):
use Hasyirin\Actor\Concerns\InteractsWithActions; class Post extends Model { use InteractsWithActions; }
Record an action. The current authenticated user is used as the actor unless you pass one explicitly:
$post->act('approved'); // actor = auth()->user() $post->act('approved', $editor); // explicit actor $post->act('approved', $editor, now()->subDay()); // explicit time
Check whether an action has been recorded:
$post->acted('approved'); // bool — anyone approved? $post->acted('approved', $user); // bool — is $user the current approver?
Fetch the action record (or null):
$action = $post->action('approved'); $action?->actor; // the user who acted $action?->acted_at; $mine = $post->action('approved', $user); // only if $user is the current approver
Get all actions on the resource (eager-loadable):
$post->load('actions'); $post->actions; // Collection<Action>
You can also use the facade directly when you don't have a trait-equipped model:
use Hasyirin\Actor\Facades\Actor; Actor::act($post, 'approved', $editor); Actor::acted($post, 'approved'); // anyone? Actor::acted($post, 'approved', $editor); // is $editor the current actor? Actor::findAction($post, 'approved'); Actor::findAction($post, 'approved', $editor); // only if $editor is the current actor
Latest-state semantics
act() is an upsert keyed on (resource_type, resource_id, name). Re-acting the same action on the same resource overwrites the actor and timestamp — there is only ever one row per (resource, name). If you need a full event history, this package is not the right choice.
Authentication guard
If the actor is resolved from auth(), the package uses Laravel's default guard. Override via config:
// config/actor.php 'guard' => 'sanctum',
A missing actor (no parameter, no authenticated user) throws Hasyirin\Actor\Exceptions\MissingActorException.
Testing
composer test
Changelog
See CHANGELOG.
Credits
License
The MIT License (MIT). See License File.