PHPackages                             popphp/pop-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. popphp/pop-acl

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

popphp/pop-acl
==============

Pop ACL Component for Pop PHP Framework

4.1.3(6mo ago)517.3k↑106.3%3BSD-3-ClausePHPPHP &gt;=8.3.0CI passing

Since Jul 16Pushed 6mo ago1 watchersCompare

[ Source](https://github.com/popphp/pop-acl)[ Packagist](https://packagist.org/packages/popphp/pop-acl)[ Docs](https://github.com/popphp/pop-acl)[ RSS](/packages/popphp-pop-acl/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (2)Versions (26)Used By (3)

pop-acl
=======

[](#pop-acl)

[![Build Status](https://github.com/popphp/pop-acl/workflows/phpunit/badge.svg)](https://github.com/popphp/pop-acl/actions)[![Coverage Status](https://camo.githubusercontent.com/c90b641acdce8bdf24f074a642c4d23a63f79be4bcec3502cf3d8687f83db331/687474703a2f2f63632e706f707068702e6f72672f636f7665726167652e7068703f636f6d703d706f702d61636c)](http://cc.popphp.org/pop-acl/)

[![Join the chat at https://discord.gg/TZjgT74U7E](https://camo.githubusercontent.com/acad7b0eeb78b78d08ffd2b85681ab243436388b5f86f8bcb956a69246e53739/68747470733a2f2f6d656469612e706f707068702e6f72672f696d672f646973636f72642e737667)](https://discord.gg/TZjgT74U7E)

- [Overview](#overview)
- [Install](#install)
- [Quickstart](#quickstart)
- [Roles](#roles)
- [Resources](#resources)
- [Strict](#strict)
- [Multiple Roles](#multiple-roles)
    - [Multi-Strict](#multi-strict)
- [Inheritance](#inheritance)
- [Assertions](#assertions)
- [Policies](#policies)

Overview
--------

[](#overview)

`pop-acl` is a full-featured component that supports ACL/RBAC user access concepts. Beyond allowing or denying basic user access, it provides support for roles, resources, permissions as well as assertions and policies for fine-grain access-control.

`pop-acl` is a component of the [Pop PHP Framework](http://www.popphp.org/).

[Top](#pop-acl)

Install
-------

[](#install)

Install `pop-acl` using Composer.

```
composer require popphp/pop-acl

```

Or, require it in your composer.json file

```
"require": {
    "popphp/pop-acl" : "^4.1.3"
}

```

[Top](#pop-acl)

Quickstart
----------

[](#quickstart)

The basic concepts involve role and resource objects and then defining what permissions are allowed (or denied) between them. The main ACL object will determine if the requested action by a role on a resource is permitted or not.

```
use Pop\Acl\Acl;
use Pop\Acl\AclRole as Role;
use Pop\Acl\AclResource as Resource;

$acl = new Acl();

$admin  = new Role('admin');
$editor = new Role('editor');
$reader = new Role('reader');

$page = new Resource('page');

$acl->addRoles([$admin, $editor, $reader]);
$acl->addResource($page);

$acl->allow('admin', 'page')           // Admin can do anything to a page
    ->allow('editor', 'page', 'edit')  // Editor can only edit a page
    ->allow('reader', 'page', 'read'); // Reader can only read a page

var_dump($acl->isAllowed($admin, $page, 'add'));   // true
var_dump($acl->isAllowed($editor, $page, 'edit')); // true
var_dump($acl->isAllowed($editor, $page, 'add'));  // false
var_dump($acl->isAllowed($reader, $page, 'edit')); // false
var_dump($acl->isAllowed($reader, $page, 'read')); // true
```

The above also works with the string value names of the roles and resources:

```
var_dump($acl->isAllowed('admin', 'page', 'add'));   // true
var_dump($acl->isAllowed('editor', 'page', 'edit')); // true
var_dump($acl->isAllowed('editor', 'page', 'add'));  // false
var_dump($acl->isAllowed('reader', 'page', 'edit')); // false
var_dump($acl->isAllowed('reader', 'page', 'read')); // true
```

[Top](#pop-acl)

Roles
-----

[](#roles)

Besides being a store for a role name, a role object serves as a simple data object, should additional data need to be stored about the role or the user currently assigned to the role.

```
use Pop\Acl\AclRole as Role;

$admin = new Role('admin');

$admin->id      = 1; // Define the role ID
$admin->user_id = 2; // Define the current user ID
```

This is useful for deeper evaluations like [assertions](#assertions) and [policies](#policies).

[Top](#pop-acl)

Resources
---------

[](#resources)

Like roles, the resource object serves as a simple data object to store additional data that may be needed.

```
use Pop\Acl\AclResource as Resource;

$page = new Resource('page');

$page->id      = 1; // Define the role ID
$page->user_id = 2; // Define the page owner user ID
```

This is useful for deeper evaluations like [assertions](#assertions) and [policies](#policies).

[Top](#pop-acl)

Strict
------

[](#strict)

Setting the `strict` flag strictly enforces any permissions that have been set and requires permissions to be explicitly set. If the `strict` flag is set to `false`, then ACL checks may pass as `true` if a rule is not explicitly set. Consider the following examples:

```
use Pop\Acl\Acl;
use Pop\Acl\AclRole as Role;
use Pop\Acl\AclResource as Resource;

$acl = new Acl();

$admin  = new Role('admin');
$editor = new Role('editor');
$page   = new Resource('page');

$acl->addRoles([$admin, $editor]);
$acl->addResource($page);

$acl->allow($admin, $page)           // Admin can do anything to a page
    ->allow($editor, $page, 'edit'); // Editor can edit a page

var_dump($acl->isAllowed($admin, $page, 'add'));  // bool(true)
var_dump($acl->isAllowed($editor, $page, 'add')); // bool(true)
```

Both evaluations result in `true`, as there is no explicit rule preventing the editor from adding a page. In order to prevent the editor from adding a page, you would either have to set a deny rule:

```
use Pop\Acl\Acl;
use Pop\Acl\AclRole as Role;
use Pop\Acl\AclResource as Resource;

$acl = new Acl();

$admin  = new Role('admin');
$editor = new Role('editor');
$page   = new Resource('page');

$acl->addRoles([$admin, $editor]);
$acl->addResource($page);

$acl->allow($admin, $page)           // Admin can do anything to a page
    ->allow($editor, $page, 'edit'); // Editor can edit a page

$acl->deny($editor, $page, 'add');

var_dump($acl->isAllowed($admin, $page, 'add'));  // bool(true)
var_dump($acl->isAllowed($editor, $page, 'add')); // bool(false)
```

Or, set the ACL to strict:

```
use Pop\Acl\Acl;
use Pop\Acl\AclRole as Role;
use Pop\Acl\AclResource as Resource;

$acl = new Acl();
$acl->setStrict();

$admin  = new Role('admin');
$editor = new Role('editor');
$page   = new Resource('page');

$acl->addRoles([$admin, $editor]);
$acl->addResource($page);

$acl->allow($admin, $page)           // Admin can do anything to a page
    ->allow($editor, $page, 'edit'); // Editor can edit a page

var_dump($acl->isAllowed($admin, $page, 'add'));  // bool(true)
var_dump($acl->isAllowed($editor, $page, 'add')); // bool(false)
```

[Top](#pop-acl)

Multiple Roles
--------------

[](#multiple-roles)

If a user is assigned multiple roles at one time, those roles can all be evaluated at the same time. If we wire up a similar example from above:

```
use Pop\Acl\Acl;
use Pop\Acl\AclRole as Role;
use Pop\Acl\AclResource as Resource;

$acl = new Acl();

$admin  = new Role('admin');
$editor = new Role('editor');
$page   = new Resource('page');

$acl->addRoles([$admin, $editor])
    ->addResource($page);

$acl->allow('admin', 'page')           // Admin can do anything to a page
    ->allow('editor', 'page', 'edit')  // Editor can only edit a page
```

we can then call the `isAllowedMulti()` method to evaluate multiple roles at once:

```
var_dump($acl->isAllowedMulti([$admin, $editor], $page, 'add'));  // true
var_dump($acl->isAllowedMulti([$admin, $editor], $page, 'edit')); // true
```

If one of the roles is permitted to perform the requested action on the resource, it will pass as `true`.

### Multi-Strict

[](#multi-strict)

When evaluating multiple roles at once, if the requirement is such that all roles must be permitted to perform the requested action on the resource, using the `multi-strict` flag will ensure that.

```
$acl->setMultiStrict(true);

var_dump($acl->isAllowedMulti([$admin, $editor], $page, 'add'));  // false
var_dump($acl->isAllowedMulti([$admin, $editor], $page, 'edit')); // true
```

[Top](#pop-acl)

Inheritance
-----------

[](#inheritance)

Roles can be constructed to inherit rules from other roles.

```
use Pop\Acl\Acl;
use Pop\Acl\AclRole as Role;
use Pop\Acl\AclResource as Resource;

$acl = new Acl();

$editor = new Role('editor');
$reader = new Role('reader');

// Add the $reader role as a child role of $editor.
// The role $reader will now inherit the access rules
// of the role $editor, unless explicitly overridden.
$editor->addChild($reader);

$page = new Resource('page');

$acl->addRoles([$editor, $reader]);
$acl->addResource($page);

// Neither the editor or reader can add a page
$acl->deny('editor', 'page', 'add');

// The editor can edit a page
$acl->allow('editor', 'page', 'edit');

// Both the editor or reader can read a page
$acl->allow('editor', 'page', 'read');

// Over-riding deny rule so that a reader cannot edit a page
$acl->deny('reader', 'page', 'edit');

var_dump($acl->isAllowed('editor', 'page', 'add'));  // false
var_dump($acl->isAllowed('reader', 'page', 'add'));  // false
var_dump($acl->isAllowed('editor', 'page', 'edit')); // true
var_dump($acl->isAllowed('reader', 'page', 'edit')); // false
var_dump($acl->isAllowed('editor', 'page', 'read')); // true
var_dump($acl->isAllowed('reader', 'page', 'read')); // true
```

[Top](#pop-acl)

Assertions
----------

[](#assertions)

If you want more fine-grain control over permissions and who is allowed to do what, you can use assertions. First, define the assertion class, which implements the `Pop\Acl\Assertion\AssertionInterface`. In this example, we want to check that the user "owns" the resource via a matching user ID.

```
use Pop\Acl\Acl;
use Pop\Acl\AclRole;
use Pop\Acl\AclResource;
use Pop\Acl\Assertion\AssertionInterface;

class UserCanEditPage implements AssertionInterface
{

    public function assert(
        Acl $acl, AclRole $role,
        AclResource $resource = null,
        $permission = null
    )
    {
        // Check that the resource owner (user_id) is the same as the current role user (user_id)
        return ((null !== $resource) && ($resource->user_id == $role->user_id));
    }

}
```

Then, within the application, you can use assertions like this:

```
use Pop\Acl\Acl;
use Pop\Acl\AclRole as Role;
use Pop\Acl\AclResource as Resource;

$acl = new Acl();

$admin  = new Role('admin');
$editor = new Role('editor');

$page = new Resource('page');

$admin->id     = 1001;
$editor->id    = 1002;
$page->user_id = 1001;

$acl->addRoles([$admin, $editor]);
$acl->addResource($page);

// Define the assertion(s) to use in the 4th parameter of the allow/deny method
$acl->allow('admin', 'page', 'add')
    ->allow('admin', 'page', 'edit', new UserCanEditPage())
    ->allow('editor', 'page', 'edit', new UserCanEditPage())

// Returns true because the assertion passes,
// the admin's ID matches the page's user ID
if ($acl->isAllowed('admin', 'page', 'edit')) { }

// Although editors can edit pages, this returns false
// because the assertion fails, as this editor's ID
// does not match the page's user ID
if ($acl->isAllowed('editor', 'page', 'edit')) { }
```

[Top](#pop-acl)

Policies
--------

[](#policies)

An alternate way to achieve even more specific fine-grain control is to use policies. Similar to assertions, you have to write the policy class and it needs to use the `Pop\Acl\Policy\PolicyTrait`. Unlike assertions that are centered around the single `assert()` method, policies allow you to write separate methods that will be called and evaluated via the `can()` method in the `PolicyTrait`. Consider the following example policy class:

```
use Pop\Acl\Acl;
use Pop\Acl\AclRole;
use Pop\Acl\AclResource;

class User extends AclRole
{

    use Pop\Acl\Policy\PolicyTrait;

    public function __construct($name, $id, $isAdmin)
    {
        parent::__construct($name, ['id' => $id, 'isAdmin' => $isAdmin]);
    }

    public function create(User $user, AclResource $page)
    {
        return (($user->isAdmin) && ($page->getName() == 'page'));
    }

    public function update(User $user, AclResource $page)
    {
        return ($user->id === $page->user_id);
    }

    public function delete(User $user, AclResource $page)
    {
        return (($user->isAdmin) || ($user->id === $page->user_id));
    }

}
```

It defines specific evaluations that are required for three different actions `create()`, `update()` and `delete()`. Then the user role and policy can be added to the main ACL object:

```
$page   = new AclResource('page', ['id' => 2001, 'user_id' => 1002]);
$admin  = new User('admin', 1001, true);
$editor = new User('editor', 1002, false);

$acl = new Acl();
$acl->addRoles([$admin, $editor]);
$acl->addResource($page);
$acl->addPolicy('create', $admin, $page);
$acl->addPolicy('create', $editor, $page);
$acl->addPolicy('update', $admin, $page);
$acl->addPolicy('update', $editor, $page);
```

Once the polices are added to the ACL object, they will be automatically evaluated on the `isAllowed()` or `isDenied()` method calls:

```
// Returns true, because the user is an admin
var_dump($acl->isAllowed('admin', 'page', 'create'));

// Returns false, because the user is an editor (not an admin)
var_dump($acl->isAllowed('editor', 'page', 'create'));

// Returns false, because the admin doesn't "own" the page
var_dump($acl->isAllowed('admin', 'page', 'update'));

// Returns true, because the editor does "own" the page
var_dump($acl->isAllowed('editor', 'page', 'update'));
```

A deeper look into what is happening under the hood, the ACL object is calling the method `evaluatePolicy()` to determine if the requested action is allowed:

```
// Returns true, because the user is an admin
var_dump($acl->evaluatePolicy('create', 'admin', 'page'));

// Returns false, because the user is an editor (not an admin)
var_dump($acl->evaluatePolicy('create', 'editor', 'page'));

// Returns false, because the admin doesn't "own" the page
var_dump($acl->evaluatePolicy('update', 'admin', 'page'));

// Returns true, because the editor does "own" the page
var_dump($acl->evaluatePolicy('update', 'editor', 'page'));
```

Which, in turn, the `evaluatePolicy()` method calls are calling the `can()` method on the actual policy objects themselves:

```
var_dump($admin->can('create', $page));  // true, because the user is an admin
var_dump($editor->can('create', $page)); // false, because the user is an editor (not an admin)
var_dump($admin->can('update', $page));  // false, because the admin doesn't "own" the page
var_dump($editor->can('update', $page)); // true, because the editor does "own" the page
```

[Top](#pop-acl)

###  Health Score

54

—

FairBetter than 97% of packages

Maintenance66

Regular maintenance activity

Popularity31

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity88

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 99.1% 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 ~188 days

Recently: every ~144 days

Total

21

Last Release

200d ago

Major Versions

2.1.1 → 3.0.02017-02-22

v2.x-dev → 3.2.02019-01-10

3.4.2 → 4.0.02023-11-30

PHP version history (8 changes)2.0.0PHP &gt;=5.4.0

3.0.0PHP &gt;=5.6.0

3.2.0PHP &gt;=7.1.0

3.4.0PHP &gt;=7.3.0

3.4.1PHP &gt;=7.4.0

4.0.0PHP &gt;=8.1.0

4.1.1PHP &gt;=8.2.0

4.1.3PHP &gt;=8.3.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/c19dee900e9e20039c723cc403f76b5c22ac2dddb3f86773ae64fb082d4949e2?d=identicon)[nicksagona](/maintainers/nicksagona)

---

Top Contributors

[![nicksagona](https://avatars.githubusercontent.com/u/898670?v=4)](https://github.com/nicksagona "nicksagona (108 commits)")[![ralphschindler](https://avatars.githubusercontent.com/u/76674?v=4)](https://github.com/ralphschindler "ralphschindler (1 commits)")

---

Tags

phpaclpoppop phpaccess control list

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/popphp-pop-acl/health.svg)

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

###  Alternatives

[santigarcor/laratrust

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

2.3k5.4M43](/packages/santigarcor-laratrust)[shanmuga/laravel-entrust

This package provides a flexible solution to add ACL to Laravel

68312.9k2](/packages/shanmuga-laravel-entrust)[popphp/pop-db

Pop Db Component for Pop PHP Framework

1814.6k11](/packages/popphp-pop-db)[popphp/pop-pdf

PHP PDF library for generating and importing PDF documents. A component of the Pop PHP Framework

207.8k1](/packages/popphp-pop-pdf)[popphp/pop-http

Pop Http Component for Pop PHP Framework

1018.5k13](/packages/popphp-pop-http)

PHPackages © 2026

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