appsco/component-assertion-voter
Installation Add the package via Composer:
composer require appsco/component-assertion-voter
Register the service provider in config/app.php under providers:
Appsco\ComponentAssertionVoter\ComponentAssertionVoterServiceProvider::class,
Basic Usage
The package provides a AssertionVoter trait for authorization logic. Start by creating a voter class:
use Appsco\ComponentAssertionVoter\ComponentAssertionVoter;
class UserVoter implements CanVote
{
use ComponentAssertionVoter;
public function canVote($user, $ability, $model)
{
return $this->assert($user, $ability, $model);
}
}
First Use Case
Register the voter in AuthServiceProvider:
protected $voters = [
'user' => \App\UserVoter::class,
];
Define Assertions
Extend the ComponentAssertionVoter trait and override assert() to define custom logic:
protected function assert($user, $ability, $model)
{
switch ($ability) {
case 'edit':
return $user->isAdmin() || $user->owns($model);
case 'delete':
return $user->isAdmin();
default:
return false;
}
}
Reusable Components Break down assertions into smaller, testable components:
protected function canEditOwnContent($user, $model)
{
return $user->owns($model);
}
protected function canDeleteAdminOnly($user)
{
return $user->isAdmin();
}
Integration with Laravel Gates Use the voter with Laravel’s gate system:
Gate::resource('post', 'App\Post', function ($user, $post) {
return (new UserVoter)->canVote($user, 'edit', $post);
});
Policy Integration Combine with Laravel’s policies for modularity:
class PostPolicy implements Policy
{
public function edit(User $user, Post $post)
{
return (new UserVoter)->assert($user, 'edit', $post);
}
}
Deprecated Package
Trait Overhead
ComponentAssertionVoter trait is minimal but assumes a specific assert() method signature. Override carefully to avoid conflicts.No Built-in Logging
dd() debugging.Inspect Voter Calls
Override assert() to log inputs:
protected function assert($user, $ability, $model)
{
\Log::debug("Voter called for: {$ability}", [
'user' => $user->id,
'model' => get_class($model),
]);
// ... rest of logic
}
Test Assertions Isolated Unit test assertions separately from Laravel’s gate system:
public function testCanEditOwnPost()
{
$user = User::factory()->create();
$post = Post::factory()->create(['user_id' => $user->id]);
$this->assertTrue((new UserVoter)->assert($user, 'edit', $post));
}
Custom Assertion Logic Extend the trait to add helper methods:
trait CustomAssertions
{
protected function isActive($user)
{
return $user->active;
}
}
class UserVoter
{
use ComponentAssertionVoter, CustomAssertions;
}
Dynamic Ability Handling Use closures for dynamic abilities:
protected function assert($user, $ability, $model)
{
$rules = [
'edit' => fn($u, $m) => $u->isAdmin() || $u->owns($m),
'delete' => fn($u, $m) => $u->isAdmin(),
];
return $rules[$ability]($user, $model);
}
Cache Assertions Cache results for performance (if assertions are expensive):
protected $cache = [];
protected function assert($user, $ability, $model)
{
$key = "assertion:{$user->id}:{$ability}:{$model->id}";
if (isset($this->cache[$key])) {
return $this->cache[$key];
}
// ... logic
$this->cache[$key] = $result;
return $result;
}
How can I help you explore Laravel packages today?