Search code examples
cachingsymfonydoctrine-ormapc

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;
    }
}

Solution

  • 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.