cartalyst / sentinel

A framework agnostic authentication & authorization system.
BSD 3-Clause "New" or "Revised" License
1.51k stars 238 forks source link

array_key_exists() expects parameter 2 to be array, null given #505

Closed juanpscotto closed 4 years ago

juanpscotto commented 4 years ago

Your Environment

Expected behaviour

Please describe what you are expecting to see happening.

Add permissions to roles with the addPermission Method

Actual behaviour

Please describe what is actually happening.

It throws an error:

array_key_exists() expects parameter 2 to be array, null given.

In my table I have the role root with null permissions.

//This is the code that its not working:
 In EloquentRole.class. This method is failling.

 public function addPermission(string $permission, bool $value = true): PermissibleInterface
    {
        if (! array_key_exists($permission, $this->permissions)) {
            $this->permissions = array_merge($this->permissions, [$permission => $value]);
        }

        return $this;
    }

This only happens when roles.permissions = null. But if you update the field to '[]' instead of null it works.

Steps to reproduce

If your issue requires any specific steps to reproduce, please outline them here.

  1. Create a role with no permissions, permissions = null. $role = new Role();
  2. Add permissions to the role. $role->addPermission('update_sales');
suwardany commented 4 years ago

make sure to use the getPermissions() method which will ensure the return type is an array.

$this->getPermissions()
juanpscotto commented 4 years ago

The error is in the EloquentRole.class.

suwardany commented 4 years ago

Would you please provide us with more detail and the code you are using?

juanpscotto commented 4 years ago
class Role extends EloquentRole
{
    /**
     * {@inheritDoc}
     */
    protected $table = 'roles';

    /**
     * {@inheritDoc}
     */
    protected $fillable = [
        'name',
        'slug',
        'permissions',
        'description'
    ];

}

$role = new Role();
$role->slug = 'root';
$role->name = 'Super Admin';
$role->save();

$role->addPermission('update_sales');
$role->save();
suwardany commented 4 years ago

Just pushed out a new patch to address this bug. run composer update and everything should be working on your end.

juanpscotto commented 4 years ago

@suwardany

Thanks. I've notice the same happens with updatePermission() on PermissibleTrait.class.

Also. If throws the same error on this function:

class StrictPermissions implements PermissionsInterface
{
    use PermissionsTrait;

    /**
     * {@inheritdoc}
     */
    protected function createPreparedPermissions(): array
    {
        $prepared = [];

        if (! empty($this->secondaryPermissions)) {
            foreach ($this->secondaryPermissions as $permissions) {
                $this->preparePermissions($prepared, $permissions);
            }
        }

        if (! empty($this->permissions)) {
            $this->preparePermissions($prepared, $this->permissions);
        }

        return $prepared;
    }
}
suwardany commented 4 years ago

Thanks @juanpscotto .. i just pushed an update to the master branch (still untagged) .. can you give it a try?

juanpscotto commented 4 years ago

Don't forget the updatePermission and removePermission on PermissibleTrait.class

Getting the same error here:

protected function createPreparedPermissions(): array
    {
        $prepared = [];

        if (! empty($this->getSecondaryPermissions())) {
            foreach ($this->getSecondaryPermissions() as $permissions) {
                $this->preparePermissions($prepared, $permissions);
            }
        }

        if (! empty($this->getPermissions())) {
            $permissions = [];

            $this->preparePermissions($permissions, $this->getPermissions());

            $prepared = array_merge($prepared, $permissions);
        }

        return $prepared;
    }

I've solved this like this:

protected function createPreparedPermissions(): array
    {
        $prepared = [];

        if (! empty($this->getSecondaryPermissions())) {
            foreach ($this->getSecondaryPermissions() as $permissions) {
                if(!empty($permissions)) { // added this validation
                       $this->preparePermissions($prepared, $permissions);
                }
            }
        }

        if (! empty($this->getPermissions())) {
            $permissions = [];

            $this->preparePermissions($permissions, $this->getPermissions());

            $prepared = array_merge($prepared, $permissions);
        }

        return $prepared;
    }
suwardany commented 4 years ago

pushed to master as well!

juanpscotto commented 4 years ago

Thanks man! the updatePermission and removePermission methods are fixed now. It only remains the createPreparedPermissions, method:

Argument 2 passed to Cartalyst\Sentinel\Permissions\StandardPermissions::preparePermissions() must be of the type array, null given, called in /var/www/html/flux-erp/vendor/cartalyst/sentinel/src/Permissions/StandardPermissions.php on line 36
suwardany commented 4 years ago

aye aye .. give it another try now @juanpscotto

juanpscotto commented 4 years ago

Thanks man for your patience!. I've updated the dev-master branch.

image

Getting the same error when the roles.permissions is set to null. Only works when is an empty array '[]' or '{}' I've tried to use the StandardPermissions.php or the StrictPermissions.php with the same result.

Argument 2 passed to Cartalyst\Sentinel\Permissions\StandardPermissions::preparePermissions() must be of the type array, null given, called in /var/www/html/flux-erp/vendor/cartalyst/sentinel/src/Permissions/StandardPermissions.php on line 36
Argument 2 passed to Cartalyst\Sentinel\Permissions\StrictPermissions::preparePermissions() must be of the type array, null given, called in /var/www/html/flux-erp/vendor/cartalyst/sentinel/src/Permissions/StrictPermissions.php on line 36

Thanks man!

suwardany commented 4 years ago

hmm .. what exactly triggers that one?

juanpscotto commented 4 years ago

When I called:

    public function hasAccess($permissions): bool

    {

        if (is_string($permissions)) {

            $permissions = func_get_args();

        }

        $prepared = $this->getPreparedPermissions();

        foreach ($permissions as $permission) {

            if (! $this->checkPermission($prepared, $permission)) {

                return false;

            }

        }

        return true;

    }

$user = \Sentinel::getUser();
$user->hasAccess('permission');

The flow is like this $user->hasAccess (PermissionsTrait.php) --> $prepared = $this->getPreparedPermissions(); (PermissionsTrait.php)  --> createPreparedPermissions() (StandardPermissions.php or StrictPermissions.php) 
suwardany commented 4 years ago

I'm unable to reproduce that on my end, what are the exact user/roles and their permissions on your end? working with empty arrays or nulls as permissions works fine whether that is on a user, a role or on both.

juanpscotto commented 4 years ago

Sorry sorry. Yes you are right. All is working fine now. I was overriding createPermissions on my User.php model. Thanks a lot!!

suwardany commented 4 years ago

No worries @juanpscotto .. i've released a new patch tag.

juanpscotto commented 4 years ago

Awesome!