Okay, I tried to implement it myself. Maybe it's not pretty, but it's the best solution I came up with myself. Is this the right direction? I would appreciate any feedback!
Solution:
Instead of strings as resources and roles i use my models (suggested here). I use PointResourceInterface
to mark resources that require a specific number of points and implement Zend\Permissions\Acl\Role\RoleInterface
in my user class. Now I create a new NeededPointsAssertion
:
class NeededPointsAssertion implements AssertionInterface
{
public function assert(Acl $acl, RoleInterface $role = null,
ResourceInterface $resource = null, $privilege = null) {
// Resource must have points, otherwise not applicable
if (!($resource instanceof PointResourceInterface)) {
throw new Exception('Resource is not an PointResourceInterface. NeededPointsAssertion is not applicable.');
}
//check if points are high enough, in my app only users have points
$hasEnoughPoints = false;
if ($role instanceof User) {
// role is User and resource is PointResourceInterface
$hasEnoughPoints = ($role->getPoints() >= $resource->getPoints());
}
return $hasEnoughPoints;
}
}
PointResourceInterface
looks like this:
use Zend\Permissions\Acl\Resource\ResourceInterface;
interface PointResourceInterface extends ResourceInterface {
public function getPoints();
}
Setup:
$acl->allow('user', $pointResource, null, new NeededPointsAssertion());
Users have access to resources that need points. But additionally the NeededPointsAssertion
is checked.
Access:
I'm checking whether access is allowed like this:
$acl->isAllowed($role, $someResource);
If there's a user $role = $user
otherwise it's guest
or something else.
Inspiration is from http://www.aviblock.com/blog/2009/03/19/acl-in-zend-framework/
Update: Looking back at it now, it would have also been possible to add the needed points via the constructor and store it as an attribute. Decide for yourself and what makes sense in your application...