Lithium models are very flexible, schema can be lazy loaded by the first call to Model::schema(), unless it has been manually defined in the model subclass. Below there is an example of a model with predefined schema 

class UserGroups extends \lithium\data\Model
{
	protected $_schema = array(
		'id' => array('type' => 'id', 'length' => 10, 'null' => false, 'default' => null),
		'title' => array('type' => 'string', 'length' => 64, 'null' => false, 'default' => null),
		'description' => array('type' => 'string', 'length' => 255, 'null' => false, 'default' => null),
		'admin' => array('type' => 'integer', 'length' => 1, 'null' => false, 'default' => 0),
		'resources' => array('type' => 'string', 'length' => null, 'null' => false, 'default' => null),
	);

	protected $_meta = array(
		'key' => 'id',
		'locked' => true,
		'source' => 'user_groups'
	);
}

If you leave the schema configuration empty,lithium will retrieve the information directly from the data source. Which is nice until you understand that this extra step will be taken every time the model is initialized, which is a no no. That's why I am going to show you how to cache the model's schema. Firstly we need to set up a connection and the cache storage, here is some basic configuration:

use lithium\data\Connections;
use lithium\storage\Cache;

Cache::config(array(
	'default' => array(
		'adapter' => 'File',
		'strategies' => array('Serializer')))
);

Connections::add('default', array(
	'type' => 'database',
	'adapter' => 'MySql',
	'host' => 'localhost',
	'login' => 'root',
	'password' => '',
	'database' => 'database',
	'encoding' => 'UTF-8'
));

You probably have those two already in your application's bootstrap files, here is the piece of code that does the schema caching

Connections::get('default')->applyFilter('describe', function($self, $params, $chain) {
	if(!Environment::is('production')) {
		return $chain->next($self, $params, $chain);
	}

	$key = 'schema_' . md5(serialize($params['meta']));
	if(!$result = Cache::read('default', $key)) {
		$result = $chain->next($self, $params, $chain);
		Cache::write('default', $key, $result, '+1 month');
	}
	return $result;
});

By using Lithium's filters we can hook into the data source describe method to intercept default behavior. Firstly there is a check to skip caching if we are not in production environment. Then the system checks if schema has  already been in cache by using the model's meta as a unique key. If not, we allow the default procedure to run and we write the result to cache. 

Some notes
Recently Lithium's model and pretty much all data classes have been heavily updated, in many cases breaking backward compatibility. One of them is the model schema, when fully initialized is now an object instead of a simple arrray. The above snippet was written for the latest version in the dev branch but it will probably work for previous versions as well.

The best practice when writing a model is to manually define the schema. If you follow this principle I am not sure the above snippet will improve  much your app's performance. Initialize object vs retrieve object from cache. Maybe with a more advance cache adapter like APC???

Let me know how this worked for you!


Comments

  1. Chris #4   Chris | Jul 12, 2013 at 11:27

    Lithium model uses lithium\data\Schema class for schema management instead of a plain array (as it used to). Initialization of the schema class happens in connection()->describe() method. The difference is how this class is populated. if you haven't manually defined your schema it will send a query to your data source.

    This is where schema caching comes into play. You can avoid running that extra query in every page.

    Note: i am not sure there is much to gain from caching when you manually define your model schema. I have only tested it with file caching and it was actually a little slower.

  2. hellomaya #3   hellomaya | Jul 12, 2013 at 10:41

    "Lithium models are very flexible, schema can be lazy loaded by the first call to Model::schema(), unless it has been manually defined in the model subclass. Below there is an example of a model with predefined schema " -

    I have a question here, I checked the source of Model class of Lithium PHP framework later, I found in save function, it did called $self->schema(), and in schema function, it will call describe function whatever $self->_schema has value or not, so the question arise, even you have defined _schema, the framework still call describe, it's not helpful on performance?

  3. hellomaya #2   hellomaya | Jun 13, 2013 at 00:15

    That's very impressive and helpful. Thank you.

  4. Chris #1   Chris | Jan 10, 2013 at 22:33

    My first lithium tutorial!

Leave a Comment
It will not be published.