Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I specify query result caching in a symfony2 repository?

I have a repository where I'm trying to set up result caching. I've only been able to find a single example online for how to do this... but when I implement the example in one of my repositories I get an error. I am using APC for my caching and have enabled query caching to use APC in my config.yml file. I've allocated 512M to APC and its only using 50M currently (23M of this is for this single failed cache entry)

Here's the repository code I have:

class AchievementRepository extends EntityRepository
{
    function findAchievementsByCategory($categoryObj)
    {
        $em=$this->getEntityManager()->createQuery("SELECT a FROM FTWGuildBundle:Achievement a where a.category=:category order by a.title")
            ->setParameter('category',$categoryObj);
        $em->useResultCache(true,3600,'findAchievementsByCategory');
        $result=$em->getResult();
        return $result;
    }
}

And when this is executed I get the following error

Notice: apc_store() [<a href='function.apc-store'>function.apc-store</a>]: &quot;type&quot; returned as member variable from __sleep() but does not exist in /data/www/ftw2/Symfony/vendor/doctrine-common/lib/Doctrine/Common/Cache/ApcCache.php line 80 

When I look in my apc.php file to see what is cached, I find my cache entry in the user cache section with a stored value of

Fatal error:  Nesting level too deep - recursive dependency? in /data/www/localhost/apc.php on line 1000

Can anyone provide me with some direction as to where I have gone wrong?

There are a couple columns in this entity which are ManyToOne, do I need to disable lazy load on this query for this to work? If so... how? EDIT: I enabled eager load by adding ,fetch="EAGER" to my ManyToOne mapping... no apples :(

EDIT #2: ANSWERED - Working class code (note, all properties of the entity class (Achievement) have been changed to protected)

class AchievementRepository extends EntityRepository
{
    function findAchievementsByCategory($categoryObj)
    {
        $em=$this->getEntityManager()->createQuery("SELECT a FROM FTWGuildBundle:Achievement a where a.category=:category order by a.title")
            ->setParameter('category',$categoryObj);
        $em->useResultCache(true,3600,'findAchievementsByCategory');
        $result=$em->getArrayResult();
        return $result;
    }
}
like image 237
Chris Avatar asked Nov 04 '22 02:11

Chris


1 Answers

When Doctrine caches an entity, it saves the serialized state of it. The problem is, private properties (the default visibility when generated by Doctrine) cannot be serialized. To fix this, you have to make your entity properties protected. More info: http://doctrine-orm.readthedocs.org/en/2.0.x/reference/working-with-objects.html#merging-entities

The other thing is a know issue that is (finally) fixed in Doctrine version 2.2, which will be in Symfony 2.1. If you can't upgrade for some reason, the only way to cache associations is to use getArrayResult instead of populating entities.

like image 161
Peter Kruithof Avatar answered Nov 09 '22 10:11

Peter Kruithof