We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

How to make an effective model query cache

Hi all,

I'm trying to implement a query cache in my base model. I have a page that runs 442 queries, and I've been able to cut that down to 298 with my existing cache. However, I'm still seeing duplicate queries being executed on the database. Is there any way to improve my caching find() ?

The basic premise is it makes a key out of the model name, and the params. Any incoming find() calls should look in the cache first, and return that result before re-querying.

Edit: Turns out findFirst() doesn't go use find() like I thought it did, so all my calls to findFirst() weren't being cached. Caching those queries really helped. My final solution is pasted below - I'm still interested in any optimizations if any are found.

/**
     * Extending default find() to add a caching option.  Caching option can be overridden with
     * cache directives (below) or by setting the class static "caching" with doCache()
     *
     * @param  array $params Same params as default find() except it also also accepts cache directive keys
     *                       that take effect regardless of their value (ie: fresh=>FALSE will still apply)
     *                       * fresh - will force a re-query.  New result will be cached.
     *                       * ninja - will force a re-query.  New result will not be cached.
     *
     * @return mixed Whatever default find() returns.  May return NULL if my if conditions are broken
     */
    public static function find($params = NULL){
        return self::findBody($params,'all');
    }

    /**
     * Just like find() above, but for findFirst()
     */
    public static function findFirst($params = NULL){
        return self::findBody($params,'one');
    }

    /**
     * Does the caching work for find() and findFirst()
     * @see self::find()
     */
    public static function findBody($params,$mode='all'){
        self::$queryCount++;

        // the DI gets passed sometimes, but it's not serializable
        $serializable_params = ($params == NULL) ? NULL : array_filter($params,function($key){
            return $key != 'di';
        }, \ARRAY_FILTER_USE_KEY);

        $key = static::class.serialize($serializable_params);
        $result = NULL;
        $cache =& self::$_find_query_cache;
        if($mode == 'one'){
            $cache =& self::$_findFirst_query_cache;
        }

        // Return a cached copy if possible
        if(!isset($params['fresh']) && !isset($params['ninja']) && self::$caching && isset($cache[$key])){
            return $cache[$key];
        }
        else{
            $result = ($mode == 'all') ? parent::find($params) : parent::findFirst($params);
        }

        // Store the result if possible
        if(self::$caching && !isset($params['ninja'])){
            $cache[$key] = $result;
        }

        return $result;
    }


8.4k

i wrote a class that should auto cache your models check it out hope this helps