Blog Posts

How to preload ACL in order to get good performances

Symfony2 comes with an ACL mechanism that can help you whenever you need to add some permissions in your system. Some typical use cases could be to determine if a user has the permission to edit a blog post, if he can add a comment to it or if he can delete it or simply view it. In such cases ACL system seem to be the way to go in order to implement all these rules and future existing ones in a flexible manner.

Unfortunately we came across a situation where we had to do this kind of permission check on a very long list of items. Think of a page listing all your blog posts for instance. If you have a couple of it them all is fine. As soon as you start having hundreds or more of them on one simple page, then you will sooner or later hit the wall. Performance will go bad (or very bad in our case) and as the system keep storing more and more of the same kind of data it become slower and slower.

The normal way an ACL check is performed is to issue a sql statement to the database and them observe the return value to figure out if the permission is granted or not. When you start doing this kind of verification on large amount of objects you will inevitably generate a large amount of query to your database. Even worse than that. You will at the same time generate as many round-trips between your application and the database. Just in case you wanted to add insult to injury.

Luckily for us Sf2  ACL system provides a way out of this. You can in a small amount of query load all the ACLs that are related to some given objects. Once this ACL data are loaded the system keeps them (for the time of the request) and use (or reuse them) whenever it needs them. Here is how to implement it.


private function loadBlogPostsAcls($blogPostRepository)
{
    $oids = array();

    foreach ($blogPostRepository->findBy(array(), array('date' => 'asc')) as $blogPost) {
        $oids[] = ObjectIdentity::fromDomainObject($blogPost);
    }

    $this->aclProvider->findAcls($oids);
}

This function is quite trivial to understand. It builds an array of object identities($oids) by looping over all the blog posts found in the database. Once we have this [potentially long] list of object identities we just have to call the method findAcls from the ACL provider. This one will batch load all ACL relative to these objects.

The findAcls is quite smart in its way to fetch the ACL data. It doesn't build just one gigantic query to load everything in one go but rather walk its way through the $oids fetching data by packet (for example, 50 items at a time).

When this is done you will have all ACL data about those blog posts loaded in the system and you can later on perform any kind of check you fancy. It will be fast and it won't go to the database any more to figure out if your user has permission to edit/view/delete your object.

Related Entries:
- Discussions and Pizza at PHPDay Italy
- HHVM with Symfony 2 looks amazing
- RESTing with Symfony2
- Playtime with OroCRM
- Symfony CMF: what is left todo?

About the author

Comments [5]

Hector Hurtarte, 14.10.2013 23:47 CET

I think it should be 'quite' instead of 'quiet' both times.

jean-christophe.zulian, 15.10.2013 07:51 CET

Thanks Hector for pointing out this mistake. It is now corrected.

etoileweb, 28.10.2013 12:25 CET

I'd like to have a similar but different use case example. Suppose I want to list all but only blog posts on which a user (authenticated) has MASK_OWNER permission on. How is it possible? Thanks.

jean-christophe.zulian, 30.10.2013 09:13 CET

Hi etoileweb,

I think your question is not related at all to the blog post.

However I have done a quick search and found an example that might get you on track with what you are trying to do:

$ownids = $this->aclProvider->getAllowedEntitiesIds(
'XXX\BlogBundle\Entity\Post',
$sids,
(MaskBuilder::MASK_OWNER | MaskBuilder::MASK_LIST),
false
);

This piece of code return the entity ids of the blog posts that one have created. So I guess starting from that it shouldn't be to hard to obtain the counter part of it (the users you haven't created).

I hope it will help you.

AceNet Solutions, 16.05.2014 14:06 CET

Good disperse Definitely. Thanks connected with speaking about.

Add a comment

Your email adress will never be published. Comment spam will be deleted!