Skip to main content

Extending Existing Policies

To customize authorization logic, extend or replace core policies.

1. Create the Contract

Define a policy contract interface:
namespace App\Contracts\Admin\Policies;

interface ProductPolicyContract
{
    public function view(AdminUser $user, Product $product): bool|null;
    public function create(AdminUser $user): bool|null;
    public function update(AdminUser $user, Product $product): bool|null;
    public function delete(AdminUser $user, Product $product): bool|null;
}

2. Create the Custom Policy

Implement your custom policy:
namespace App\Policies;

use App\Models\AdminUser;
use Esign\UnleashCommerce\Core\Models\Product;

class ProductPolicy
{
    public function view(AdminUser $user, Product $product): bool|null
    {
        // Allow admins to view all products
        if ($user->is_admin) {
            return true;
        }

        // Super admin check (return null to let gate decide)
        return null;
    }

    public function create(AdminUser $user): bool|null
    {
        // Only admins can create products
        return $user->is_admin ? true : null;
    }

    public function update(AdminUser $user, Product $product): bool|null
    {
        // Own products or admin
        if ($user->is_admin || $product->created_by === $user->getKey()) {
            return true;
        }

        return null;
    }

    public function delete(AdminUser $user, Product $product): bool|null
    {
        // Only admins can delete
        if ($user->is_admin) {
            return true;
        }

        // Deny for everyone else (even super admins)
        return false;
    }
}

Registering Custom Policies

Register your policies using the FilamentPolicyManifest:
use Esign\UnleashCommerce\Admin\Support\FilamentPolicyManifest;
use Esign\UnleashCommerce\Admin\Contracts\Filament\Policies\ProductPolicy as ProductPolicyContract;

public function boot()
{
    $manifest = $this->app->make(FilamentPolicyManifest::class);
    $manifest->replace(
        ProductPolicyContract::class,
        CustomProductPolicy::class
    );
}

Super Admin Support

Policies support super admin functionality:
  • Returning true grants permission
  • Returning null lets the super admin check decide
  • Returning false denies permission (even for super admins)
public function delete(AdminUser $user, Product $product): bool|null
{
    // Allow super admins
    if ($user->is_super_admin) {
        return true;
    }

    // Check custom logic
    if ($user->can_delete_products) {
        return true;
    }

    // Let super admin check take over or deny
    return null;
}

Using Policies in Filament

Filament automatically uses your policies to control visibility of actions:
// Actions are automatically hidden based on policies
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),

Testing Custom Policies

Test your policies:
public function test_admin_can_delete_product()
{
    // Arrange
    $admin = AdminUser::factory()->admin()->create();
    $product = Product::factory()->create();
    $policy = new ProductPolicy();

    // Act
    $result = $policy->delete($admin, $product);

    // Assert
    $this->assertTrue($result);
}

public function test_non_admin_cannot_delete()
{
    // Arrange
    $user = AdminUser::factory()->create();
    $product = Product::factory()->create();
    $policy = new ProductPolicy();

    // Act
    $result = $policy->delete($user, $product);

    // Assert
    $this->assertNull($result);
}
For more information, see the Policies guide.