For some time we used RedisCache Yii extension to cache db scheme. But doing one performance optimization we come to idea that keep all db scheme in a single php-file will be much faster. We wouldn’t need to process ~20 (each for one table) read operations to redis and save certain amount on critical ms. All you need is just include a single file.

How to implement custom cache adaptor

Yii provides simple interface for cache implementation. All you need is extend your component from CCache and implement couple methods:

class YourSuperCache extends CCache
{
    public function init()
    {

    }

    public function set($id,$value,$expire=0,$dependency=null)
    {
        // save data to cache
        return true;
    }
   
    public function get($id)
    {
        // get data from cache
        return $value; // or false if not found
    }
   
    public function delete($id)
    {
        // delete data from cache
        return true;
    }
}

Then simply add your component into main.php:

return array(
    ...
    'components'=>array(
        ...
        'cache'=>array(
            'class'=>'ext.supercachem.YourSuperCache',
        )
    ),
);

“cache” is default key for caching component.

DB scheme cache

To turn on db scheme you will need to change db config:

    'connectionString' => 'mysql:host=localhost;dbname=mydb',
    'username' => 'user',
    'password' => 'pass',
    ...
    'schemaCachingDuration' => 3600,
    'schemaCacheID' => 'cache',

schemaCachingDuration – cache expiration interval in seconds. Put 0 if about to disable cache. schemaCacheID – cache component key. By default Yii use “cache”.

DB scheme file cache extension

<?php

class DBSchemeCache extends CCache
{
    private $_sets = array();
   
    private $_cacheValues = array();
   
    public $file = 'protected/runtime/db_scheme.php';

    public function init()
    {
        parent::init();
        Yii::app()->attachEventHandler('onEndRequest', array($this, 'endRequest'));
        $this->_loadCacheFile();
    }


    public function set($id,$value,$expire=0,$dependency=null)
    {
        $this->_sets[$id] = $value;
        return true;
    }
   
    public function get($id)
    {
        if (!empty($this->_cacheValues[$id])) {
            return $this->_cacheValues[$id];
        }
        return false;
    }
   
    public function delete($id)
    {
        return true;
    }
   
    public function endRequest()
    {
        $this->_saveSets();
    }
   
    private function _saveSets()
    {
        if (!empty($this->_sets)) {
            foreach ($this->_cacheValues as $key=>$value) {
                if (!isset($this->_sets[$key])) {
                    $this->_sets[$key] = $value;
                }
            }
           
            $cacheFileContent = '<?php $cache = array();' . PHP_EOL . PHP_EOL;
            $cacheFileContent .= 'function o($class, $props) { $object = new $class(); foreach($props as $k=>$v){if (property_exists($object, $k)) $object->$k = $v;} return $object;};' . PHP_EOL . PHP_EOL;
            foreach ($this->_sets as $key => $value) {
                $cacheFileContent .= '$cache["' . addslashes($key) . '"] = ' . var_export($value, true) . ';' . PHP_EOL;
            }
            $cacheFileContent .= 'return $cache;';
           
            $cacheFileContent = preg_replace('/(\w+?)::__set_state\(/is', 'o("\\1",', $cacheFileContent);
           
            $fp = fopen($this->file, 'w');
            fwrite($fp, $cacheFileContent);
            fclose($fp);
        }
    }
   
    private function _loadCacheFile()
    {
        if (is_file($this->file))
            $this->_cacheValues = include($this->file);
    }
}

As you can see caching db scheme for php file is quite simple. Just note that extension doesn’t support cache expire interval and for cache renew you just need to delete cache file (protected/runtime/db_scheme.php).

To separate db scheme cache from system cache, we’ll use special cache key – “dbschemecache”:

plug in component into main.php

return array(
    ...
    'components'=>array(
        ...
        'dbschemecache'=>array(
            'class'=>'ext.dbschemecache.DBSchemeCache',
            'file' => 'protected/runtime/db_scheme.php', // cache file
        )
    ),
);

database connection config

    'connectionString' => 'mysql:host=localhost;dbname=mydb',
    'username' => 'user',
    'password' => 'pass',
    ...
    'schemaCachingDuration' => 3600,
    'schemaCacheID' => 'dbschemecache',

Thanks for reading. Hope you’ll find this article useful.