I have completely rebaked my models, and now I get an Only an array or \Traversable is allowed for Collection.
if I add the ->toArray() to the end of the $this->Users->findById…then I getCall to a member function hasRight() on array`
i never experienced this error but it looks its because (https://github.com/cakephp/cakephp/blob/19f168f0cdbd1aef71b613a5caf396bd5b4abb49/src/ORM/Association/BelongsTo.php#L164) you are trying to use compound keys as primary key of users_roles, try to use user_id just for the tests. change it in database and UsersRolesTable
I think my previous comment must have slipped under the radar, but after fully rebaking my models, I now get an Only an array or \Traversable is allowed for Collection:
$user = $this->Users->findById($this->Auth->user('id'))->contain(['Roles' => ['Permissions']])->first();
When I add the ->toArray(), I get the Call to a member function hasRight() on array error:
$user = $this->Users->findById($this->Auth->user('id'))->contain(['Roles' => ['Permissions']])->first()->toArray();
yeah sorry i wrote it in a bad way what i ment ->first() OR ->toArray() so just use ->first() and you should end up with Entity object with all your methods accessible, if you use ->toArray() at the end you end up with well… generic array
ah ye.
But now I get the Only an array or \Traversable is allowed for Collection error :\
I changed the hasRight method to this (the use of the $data variable is only for testing/debugging purposes only, so is the pr() call):
public function hasRight(string $right){
$data = $this->toArray();
pr($data);
return collection($data)->firstMatch([
'{*}.roles.{*}.permissions.' . $right => 1
]) !== null;
}
It doesn’t give me the big fat red CakePHP error anymore, but now gives:
Notice (8): Object of class Cake\Collection\Collection could not be converted to int [CORE/src/Collection/ExtractTrait.php, line 133]
$this->users_roles should be an array, can you add dd($this->users_roles); in hasRight?
Adding that returned null, and after fiddling a bit, I noticed for some reason, I had to use roles not users_roles (looking at the git commits, this was changed in the last re-bake? dunno why, but it happened).
adding dd($this->roles); shows me a huge array:
[
(int) 0 => object(App\Model\Entity\Role) {
'id' => (int) 1,
'name' => 'Administrator',
'_joinData' => object(App\Model\Entity\UsersRole) {
'user_id' => (int) 1,
'role_id' => (int) 1,
'[new]' => false,
'[accessible]' => [
'user' => true,
'role' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'UsersRoles'
},
'permissions' => [
(int) 0 => object(App\Model\Entity\Permission) {
'role_id' => (int) 1,
'access_cms' => (int) 1,
'show_users' => (int) 1,
'add_users' => (int) 1,
'edit_users' => (int) 1,
'remove_users' => (int) 1,
'show_posts' => (int) 1,
'add_posts' => (int) 1,
'edit_posts' => (int) 1,
'remove_posts' => (int) 1,
'[new]' => false,
'[accessible]' => [
'access_cms' => true,
'show_users' => true,
'add_users' => true,
'edit_users' => true,
'remove_users' => true,
'show_posts' => true,
'add_posts' => true,
'edit_posts' => true,
'remove_posts' => true,
'role' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Permissions'
}
],
'[new]' => false,
'[accessible]' => [
'name' => true,
'permissions' => true,
'users' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Roles'
},
(int) 1 => object(App\Model\Entity\Role) {
'id' => (int) 2,
'name' => 'Member',
'_joinData' => object(App\Model\Entity\UsersRole) {
'user_id' => (int) 1,
'role_id' => (int) 2,
'[new]' => false,
'[accessible]' => [
'user' => true,
'role' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'UsersRoles'
},
'permissions' => [
(int) 0 => object(App\Model\Entity\Permission) {
'role_id' => (int) 2,
'access_cms' => (int) 0,
'show_users' => (int) 0,
'add_users' => (int) 0,
'edit_users' => (int) 0,
'remove_users' => (int) 0,
'show_posts' => (int) 0,
'add_posts' => (int) 0,
'edit_posts' => (int) 0,
'remove_posts' => (int) 0,
'[new]' => false,
'[accessible]' => [
'access_cms' => true,
'show_users' => true,
'add_users' => true,
'edit_users' => true,
'remove_users' => true,
'show_posts' => true,
'add_posts' => true,
'edit_posts' => true,
'remove_posts' => true,
'role' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Permissions'
}
],
'[new]' => false,
'[accessible]' => [
'name' => true,
'permissions' => true,
'users' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Roles'
}
]
The error is gone, but adding var_dump($user->hasRight("access_cms")); in the AdminController gives bool(false) (even though one of the roles the user is part of has the access_cms column on 1, as seen in the 'name' => Administrator object).
We’re getting close, I can feel it 
looks like rebaking switched association to use ‘through’ option thats why you now have roles, now your homework is to get to know path from roles to access_cms using collection :), you have the whole structure in what you have pasted.
this path should be {*}.permissions.0.access_cms am I right?
However, something seems to be wrong in this, since that pattern always returns null (even though it should return 1 or 0 depending on that’s in the database)…
using var_dump($this->roles[0]['permissions'][0]['access_cms']); does return int(1) (or int(0) whatever is in the database for the role on index 0) indicating that my path should be correct…
So this means that the condition is not correct, but I can’t see what’s wrong…
EDIT: adding var_dump(collection($this->roles)); gives me: object(Cake\Collection\Collection)#653 (1) { ["count"]=> int(2) } indicating there is information missing in my collection… which is strange since it is there when I use the array as seen in the example above…
looks like i kind of lied to you, i dont see any info that ->firstMatch supports wildcards matching, but you should be still able to do
->extract('permissions.{*}')->firstMatch([$right => 1]);
YOU SON OF A ![]()
jkjk
Thanks, now it seems to work perfectly <3
I can now finally rest in peace <3