I think i figured it out.
First of all i created a new Interface, called AclChildEntityInterface.
Pretty simple:
interface AclChildEntityInterface{
public function getAclChildren();
}
Every entity i want to check for child ACL / ACE implements it and returns an array of the functions to get the child entites.
class Gallery implements AclChildEntityInterface
{
public function getAclChildren(){
return array(
'mediacategories' => 'getMediacategories',
'medialanguages' => 'getMedialanguages',
);
}
}
NOTE: the array values must exist as function in the current Entity Class.
After that i created a new AclVoter that extends the Symfony\Component\Security\Acl\Voter\AclVoter
:
The Class is almost the same, i juste changed the behavior in the vote function of the
catch (AclNotFoundException $noAcl)
use Symfony\Component\Security\Acl\Voter\AclVoter as BaseVoter;
...
use Develth\Prodcut\GalleryBundle\Entity\AclChildEntityInterface;
class MediaAclVoter extends BaseVoter
{
...
public function vote(TokenInterface $token, $object, array $attributes)
{
...
} catch (AclNotFoundException $noAcl) {
if (null !== $this->logger) {
$this->logger->debug('No ACL found for the object identity. Voting to deny access.');
}
// Check if entity has childs to check
if($object instanceof AclChildEntityInterface){
$entityChilds = $object->getAclChildren();
foreach ($entityChilds as $child) {
$childEntites = call_user_func( array($object,$child) );
foreach ($childEntites as $childEntity) {
$mapping = $childEntity->getName();
$oid = $this->objectIdentityRetrievalStrategy->getObjectIdentity($childEntity);
try{
$acl = $this->aclProvider->findAcl($oid, $sids);
if($acl->isGranted($masks, $sids, false)){
// Has permission to view. show it.
return self::ACCESS_GRANTED;
}
}catch(AclNotFoundException $noAcl){
// No ACL for this entity. Ignore
}catch(NoAceFoundException $noAce){
// No ACE for this entity. Ignore because other could have.
}
}
}
}
return self::ACCESS_DENIED;
} catch (NoAceFoundException $noAce) {
...
}
What happens here?
If there is no ACL found for the current entity, it checks if its an instance of the previous created AclChildEntityInterface. It gets every childAcl to check and returns an ACCESS_GRANTED
if an ACE is found.
But there are still some things i don´t like and i think it could be improved.
In the Entity class that implements AclChildEntityInterface
i want to do something like that:
public function getAclChildren(){
return array(
'mediacategories' => $this->mediacategories,
'medialanguages' => $this->medialanguages,
);
}
or the regarding get Methods.
But if i want to access those in the Voter i always get the PersistentCollection with the main entity media as owner, so i cannot access those directly. Thats why i use the call_user_funk
.
I´m thankful for improvements!