PHPackages                             tobento/service-acl - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. tobento/service-acl

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

tobento/service-acl
===================

A simple role and user-level access control system.

2.0(5mo ago)7117MITPHPPHP &gt;=8.4

Since Mar 14Pushed 5mo ago2 watchersCompare

[ Source](https://github.com/tobento-ch/service-acl)[ Packagist](https://packagist.org/packages/tobento/service-acl)[ Docs](https://www.tobento.ch)[ RSS](/packages/tobento-service-acl/feed)WikiDiscussions 2.x Synced today

READMEChangelog (10)Dependencies (4)Versions (14)Used By (0)

ACL Service
===========

[](#acl-service)

The ACL Service is a simple role and user-level access control system.

Table of Contents
-----------------

[](#table-of-contents)

- [Getting started](#getting-started)
    - [Requirements](#requirements)
    - [Highlights](#highlights)
    - [Simple Example](#simple-example)
- [Documentation](#documentation)
    - [Rules](#rules)
        - [Default Rule](#default-rule)
        - [Default Rule Custom](#default-rule-custom)
        - [Custom Rules](#custom-rules)
    - [Permissions](#permissions)
    - [Roles](#roles)
- [Credits](#credits)

---

Getting started
===============

[](#getting-started)

Add the latest version of the Acl service running this command.

```
composer require tobento/service-acl

```

Requirements
------------

[](#requirements)

- PHP 8.4 or greater

Highlights
----------

[](#highlights)

- Framework-agnostic, will work with any project
- Customize permission behaviour
- Decoupled design

Simple Example
--------------

[](#simple-example)

Here is a simple example of how to use the Acl service.

```
use Tobento\Service\Acl\Acl;
use Tobento\Service\Acl\Authorizable;
use Tobento\Service\Acl\AuthorizableAware;
use Tobento\Service\Acl\Role;

// User class example.
class User implements Authorizable
{
    use AuthorizableAware;

    public function __construct(
        protected string $name,
    ) {}
}

// Create Acl.
$acl = new Acl();

// Adding rules.
$acl->rule('articles.read')
    ->title('Article Read')
    ->description('If a user can read articles');

$acl->rule('articles.create');
$acl->rule('articles.update');

// Create role.
$guestRole = new Role('guest');

// Adding permissions on role.
$guestRole->addPermissions(['articles.read']);

// Create and set user role.
$user = new User('Nick')->setRole($guestRole);

// Adding permissions on user.
// If permissions are set on user, role permissions will not count anymore.
$user->addPermissions(['articles.read']);

// Set current user.
$acl->setCurrentUser($user);

// Adding additional permissions for the current user only.
$acl->addPermissions(['articles.create']);

// Check permissions for current user.
if ($acl->can('articles.read')) {
    // user has permission to read articles.
}

// check permission for specific user.
if ($acl->cant(key: 'articles.read', user: $user)) {
    // user has not permission to read articles.
}
```

Documentation
=============

[](#documentation)

Rules
-----

[](#rules)

Adding and getting rules.

```
use Tobento\Service\Acl\Acl;
use Tobento\Service\Acl\RuleInterface;

// Create Acl.
$acl = new Acl();

// Add default rule.
$acl->rule('articles.read');

// Add custom rule.
$acl->addRule(RuleInterface $rule);

// Get rules.
foreach($acl->getRules() as $rule)
{
    $key = $rule->getKey();
    $inputKey = $rule->getInputKey();
    $title = $rule->getTitle();
    $description = $rule->getDescription();
    $area = $rule->getArea();
}

// get specific rules
$rule = $acl->getRule('articles.read');
```

### Default Rule

[](#default-rule)

The default rule has the following permission behaviour:

```
use Tobento\Service\Acl\Acl;

// Create Acl.
$acl = new Acl();

$acl->rule('articles.read');
$acl->rule('articles.update');

// Create role.
$role = new Role('guest');

// Create and set user role.
$user = new User('Nick')->setRole($role);

// Adding permissions on acl, only for current user.
$acl->addPermissions(['articles.read']);

// Adding permissions on role.
$role->addPermissions(['articles.read']);

// Adding permissions on user.
// If permissions are set on user, role permissions will not count anymore.
// Only acl and user specific permissions.
$user->addPermissions(['articles.read']);
```

Areas bahviour:

```
use Tobento\Service\Acl\Acl;

// Create Acl.
$acl = new Acl();

$acl->rule('articles.read', 'frontend');
$acl->rule('articles.update', 'backend');

// Guest Role taking only frontend rules into account,
// ignoring any permission from backend rules even if permission is given.
$role = new Role('guest', ['frontend']);

// Editor can have frontend and backend rules.
$role = new Role('editor', ['frontend', 'backend']);
```

### Default Rule Custom

[](#default-rule-custom)

You can easily add a custom handler for extending a specific rule behaviour.

```
use Tobento\Service\Acl\Acl;
use Tobento\Service\Acl\Authorizable;
use Tobento\Service\Acl\AuthorizableAware;
use Tobento\Service\Acl\Role;

// User class example.
class User implements Authorizable
{
    use AuthorizableAware;

    public function __construct(
        protected string $name,
    ) {}
}

// Article class example
class Article
{
    public function __construct(
        protected string $name,
        protected array $roles = [],
        protected null|Authorizable $user = null
    ) {}

    public function getName(): string
    {
        return $this->name;
    }

    public function getUser(): null|Authorizable
    {
        return $this->user;
    }

    public function getRoles(): array
    {
        return $this->roles;
    }
}

// Create Acl.
$acl = new Acl();

// Rule to check if user is allowed to access a specific resource.
$acl->rule('resource')
    ->needsPermission(false)
    ->handler(function(Authorizable $user, null|Authorizable $resourceUser): bool {

        if (is_null($resourceUser)) {
            return false;
        }

        return $user === $resourceUser;
    });

// Rule to check if user has role for a specific resource.
$acl->rule('has_role')
    ->needsPermission(false)
    ->handler(function(Authorizable $user, array $roles = []) {

        if (empty($roles)) {
            return true;
        }

        return in_array($user->role()->key(), $roles);
    });

$user = (new User('Nick'))->setRole(new Role('editor'));

$acl->setCurrentUser($user);

$article = new Article('About us', ['editor'], $user);

// Check resource access.
if ($acl->can('resource', [$article->getUser()])) {
    // user can access about page.
}

// Check resource role access.
if ($acl->can('has_role', [$article->getRoles()])) {
    // user has the right role to access this resource.
}
```

### Custom Rules

[](#custom-rules)

You can easily add a custom rule for a different permission strategy.

Your Rule must implement the following RuleInterface.

```
/**
 * RuleInterface
 */
interface RuleInterface
{
    /**
     * Get the key.
     *
     * @return string The key such as 'user.create'.
     */
    public function getKey(): string;

    /**
     * Get the input key. May be used for form input.
     *
     * @return string The key such as 'user_create'.
     */
    public function getInputKey(): string;

    /**
     * Get the title.
     *
     * @return string The title
     */
    public function getTitle(): string;

    /**
     * Get the description.
     *
     * @return string The description
     */
    public function getDescription(): string;

    /**
     * Get the area.
     *
     * @return string
     */
    public function getArea(): string;

    /**
     * If the rule requires permissions to match the rule.
     *
     * @return bool
     */
    public function requiresPermission(): bool;

    /**
     * Return if the rule matches the criteria.
     *
     * @param AclInterface
     * @param string A permission key 'user.create'.
     * @param array Any parameters for custom handler
     * @param null|Authorizable
     * @return bool True if rule matches, otherwise false
     */
    public function matches(
        AclInterface $acl,
        string $key,
        array $parameters = [],
        ?Authorizable $user = null
    ): bool;
}
```

Lets make a custum rule for just letting user specific permissions have access ignoring acl and role permissions.

```
use Tobento\Service\Acl\Acl;
use Tobento\Service\Acl\AclInterface;
use Tobento\Service\Acl\RuleInterface;
use Tobento\Service\Acl\Authorizable;
use Tobento\Service\Acl\AuthorizableAware;
use Tobento\Service\Acl\Role;

// Custom rule
class CustomRule implements RuleInterface
{
    public function __construct(
        protected string $key,
        protected string $area,
    ) {}

    public function getKey(): string
    {
        return $this->key;
    }

    public function getInputKey(): string
    {
        return $this->key;
    }

    public function getTitle(): string
    {
        return $this->key;
    }

    public function getDescription(): string
    {
        return '';
    }

    public function getArea(): string
    {
        return $this->area;
    }

    public function requiresPermission(): bool
    {
        return true;
    }

    public function matches(
        AclInterface $acl,
        string $key,
        array $parameters = [],
        ?Authorizable $user = null
    ): bool {

        $user = $user ?: $acl->getCurrentUser();

        // not user at all
        if (is_null($user)) {
            return false;
        }

        // user needs a role.
        if (! $user->hasRole()) {
            return false;
        }

        // collect only user permissions.
        if (!$user->hasPermissions()) {
            return false;
        }

        $permissions = $user->getPermissions();

        // permission check
        if (!in_array($key, $permissions)) {
            return false;
        }

        // area check
        if (!in_array($this->getArea(), $user->role()->areas())) {
            return false;
        }

        return true;
    }
}

// User class example.
class User implements Authorizable
{
    use AuthorizableAware;

    public function __construct(
        protected string $name,
    ) {}
}

// Create Acl.
$acl = new Acl();

// Adding default rules.
$acl->addRule(new CustomRule('articles.read', 'frontend'));
$acl->addRule(new CustomRule('articles.create', 'frontend'));

// Create role.
$role = new Role('guest');

// Adding permissions on role does has no effect.
$role->addPermissions(['articles.read']);

// Create and set user role.
$user = new User('Nick')->setRole($role);
$user->addPermissions(['articles.create']);

// Set current user.
$acl->setCurrentUser($user);

if ($acl->can('articles.create')) {
    // user has permission to read articles.
}
```

Permissions
-----------

[](#permissions)

The following methods are available on objects implementing the Permissionable Interface or the Authorizable Interface.

- Tobento\\Service\\Acl\\Acl::class
- Tobento\\Service\\Acl\\Role::class

```
use Tobento\Service\Acl\Acl;
use Tobento\Service\Acl\Permissionable;
use Tobento\Service\Acl\Authorizable;

// Create Acl.
$acl = new Acl();

// Set all permissions.
$acl->setPermissions(['user.create', 'user.update']);

// Adding more permissions.
$acl->addPermissions(['user.delete']);

$permissions = $acl->getPermissions(); // ['user.create', 'user.update', 'user.delete']

// Has any permissions at all.
$hasPermissions = $acl->hasPermissions();

// Removing permissions.
$acl->removePermissions(['user.delete']);

// Has specific permission.
$hasPermission = $acl->hasPermission('user.update');
```

Available methods for checking permissions on acl:

```
use Tobento\Service\Acl\Acl;

// Create Acl.
$acl = new Acl();

// Check permissions for current user.
if ($acl->can('articles.read')) {
    // user has permission to read articles.
}

// Check permission for specific user.
if ($acl->cant(key: 'articles.read', user: $user)) {
    // user has not permission to read articles.
}

// You can check multiple permissions too.
if ($acl->can('articles.create|articles.update')) {
    // user has permission to create and update articles.
}

// Multiple permissions with parameters.
if ($acl->can('articles.create|resource', ['resource' => [$article->getUser()]])) {
    // user has permission to create and access the specific article.
}
```

Checking permissions on Authorizable object:

For more information on Helper Function visit [tobento/helper-function](https://github.com/tobento-ch/helper-function)

```
use Tobento\Service\HelperFunction\Functions;
use Psr\Container\ContainerInterface;
use Tobento\Service\Di\Container;
use Tobento\Service\Acl\Acl;
use Tobento\Service\Acl\AclInterface;
use Tobento\Service\Acl\Authorizable;
use Tobento\Service\Acl\AuthorizableAware;
use Tobento\Service\Acl\Role;

// create container.
$container = new Container();

// Set up Helper Function acl() for supporting
// checking permission directly on Authorizable objects.
$functions = new Functions();
$functions->set(ContainerInterface::class, $container);

// Register Acl functions.
$functions->register('dir/to/acl/functions.php');

// User class example.
class User implements Authorizable
{
    use AuthorizableAware;

    public function __construct(
        protected string $name,
    ) {}
}

// Create Acl.
$acl = new Acl();

// Add Acl to container.
$container->set(AclInterface::class, $acl);

// Adding rules.
$acl->rule('articles.read');

// Create role.
$guestRole = new Role('guest');

// Adding permissions on role.
$guestRole->addPermissions(['articles.read']);

// Create and set user role.
$user = new User('Nick')->setRole($guestRole);

// Check permissions on user.
if ($user->can('articles.read')) {
    // user has permission to read articles.
}

// check permission for specific user.
if ($user->cant('articles.read')) {
    // user has not permission to read articles.
}
```

Roles
-----

[](#roles)

Working with roles.

```
use Tobento\Service\Acl\Acl;
use Tobento\Service\Acl\Role;
use Tobento\Service\Acl\RoleInterface;
use Tobento\Service\Acl\Roles;
use Tobento\Service\Acl\RolesInterface;

// Create Acl.
$acl = new Acl();

// Set roles on acl for later reusage if needed.
$acl->setRoles([
    new Role('guest'),
    new Role('editor'),
]);
// or
$acl->setRoles(new Roles(
    new Role('guest'),
    new Role('editor'),
));

// Get roles:
$roles = $acl->roles();

var_dump($roles instanceof RolesInterface);
// bool(true)

// Iterate roles:
foreach($acl->roles() as $role) {
    $key = $role->key();
    $active = $role->active();
    $areas = $role->areas();
    $name = $role->name();
}

// Get Specific role:
$role = $roles->get('editor');
$role = $acl->getRole('editor'); // or
// null|RoleInterface

// Check if role exists:
var_dump($roles->has('editor'));
var_dump($acl->hasRole('editor')); // or
// bool(true)

// Sort roles returning a new instance:
$roles = $roles->sort(fn(RoleInterface $a, RoleInterface $b): int => $a->name()  $b->name());

// Filter roles returning a new instance:
$roles = $roles->filter(fn(RoleInterface $role): bool => $role->active());

// Filter by area roles returning a new instance:
$roles = $roles->area('frontend');

// Filter (in)active roles returning a new instance:
$roles = $roles->active();
$roles = $roles->active(false);

// Returns a new instance only the roles specified:
$roles = $roles->only(['editor']);

// Returns a new instance except the roles specified:
$roles = $roles->except(['editor']);

// Add a role returning a new instance:
$roles = $roles->add(new Role('admin'));

// Remove a role returning a new instance:
$roles = $roles->remove('editor');

// Get first role:
$role = $roles->first();
// null|RoleInterface

// Get column of roles:
$roleNames = $roles->column('name');
$roleNamesByKey = $roles->column('name', 'key');

// Get all roles:
$roles = $roles->all();
$roles = $acl->getRoles(); // or
// array
```

Credits
=======

[](#credits)

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)

###  Health Score

47

—

FairBetter than 94% of packages

Maintenance69

Regular maintenance activity

Popularity18

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity77

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~127 days

Recently: every ~46 days

Total

14

Last Release

179d ago

Major Versions

1.x-dev → 2.02025-09-24

PHP version history (2 changes)1.0.0PHP &gt;=8.0

2.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/055d6a1b5c2384bb179c75ab0b55914231d898fdc4dffeb30770f81200e52206?d=identicon)[TOBENTOch](/maintainers/TOBENTOch)

---

Top Contributors

[![tobento-ch](https://avatars.githubusercontent.com/u/16684832?v=4)](https://github.com/tobento-ch "tobento-ch (79 commits)")

---

Tags

aclpermissionsphprole-based-access-controlpackageacltobento

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tobento-service-acl/health.svg)

```
[![Health](https://phpackages.com/badges/tobento-service-acl/health.svg)](https://phpackages.com/packages/tobento-service-acl)
```

###  Alternatives

[spatie/laravel-permission

Permission handling for Laravel 12 and up

12.8k86.3M864](/packages/spatie-laravel-permission)[lab404/laravel-impersonate

Laravel Impersonate is a plugin that allows to you to authenticate as your users.

2.3k15.7M42](/packages/lab404-laravel-impersonate)[santigarcor/laratrust

This package provides a flexible way to add Role-based Permissions to Laravel

2.3k5.2M38](/packages/santigarcor-laratrust)[bezhansalleh/filament-shield

Filament support for `spatie/laravel-permission`.

2.7k2.6M73](/packages/bezhansalleh-filament-shield)[casbin/casbin

a powerful and efficient open-source access control library for php projects.

1.3k1.3M48](/packages/casbin-casbin)[nette/security

🔑 Nette Security: provides authentication, authorization and a role-based access control management via ACL (Access Control List)

3729.2M245](/packages/nette-security)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
