Working on one project (social network), I had the task of “making friends” a data model with memcache. As you already understood from the title, the project is written in the symfony framework, and Propel is used as the ORM.
Why cache a model, you ask, if you can just use the View cache?
As practice has shown (it was the cache view that was first used), this was not advisable. Each time the user changed the data, it was necessary to reset the cache of several cached blocks at once. The number of these blocks with the development of the project is growing, the logic is complicated. To relieve the brain and avoid errors, and it was decided to cache the model.
As it turned out, Propel is not intended for caching at all, and when the cache is disabled, the view generates a VERY large number of requests.
My record is 250 !!! Why you ask? Because Propel in an interesting way implements the connection between objects. Instead of taking an object from a single point (for example, using the method of retriveByPk), it makes a request to the database !!! And this means that if we have user objects, his photos, his blog entries, then from each object we get a request to the database. We have, for example, in a sample of 20 photos - get 20 requests to the database to find out the login author of the photo. And if the pictures have an album? That 40. And if this is the main page, on which there are pictures, blog entries and whatnot? All 250 :)
')
What is interesting in Propel'e warn about this :)
Here is an example:
public function getsfGuardUser(PropelPDO $con = null )
{
if ($ this ->asfGuardUser === null && ($ this ->user_id !== null )) {
$c = new Criteria(sfGuardUserPeer::DATABASE_NAME);
$c->add(sfGuardUserPeer::ID, $ this ->user_id);
$ this ->asfGuardUser = sfGuardUserPeer::doSelectOne($c, $con);
/* The following can be used additionally to
guarantee the related object contains a reference
to this object. This level of coupling may, however, be
undesirable since it could result in an only partially populated collection
in the referenced object.
$this->asfGuardUser->addPhotos($this);
*/
}
return $ this ->asfGuardUser;
}
* This source code was highlighted with Source Code Highlighter .
And you can only:
public function getsfGuardUser(PropelPDO $con = null )
{
return sfGuardUserPeer::retrieveByPK($ this ->getUserId(), $con);
}
* This source code was highlighted with Source Code Highlighter .
This simple redefinition can get rid of "extra" requests .
However, if there are a lot of connections, you will have to dig a lot in the code.
Now let's go directly to caching. I wanted that after calling the retrieveByPK method, an object was returned from the cache, if it is there, and if not, it was taken from the database and saved to the cache. What is most interesting, in propel there is a pool of loaded objects. This pool is only a temporary storage.
Here is an example of the generated methods for the user model.
public static function addInstanceToPool(sfGuardUser $obj, $key = null );
public static function removeInstanceFromPool($ value );
public static function getInstanceFromPool($key);
public static function clearInstancePool();
* This source code was highlighted with Source Code Highlighter .
And if you redefine these methods in such a way that the objects that fall into the pool at the same time are cached in memcache, then the problem of caching model objects will be solved. True, this is not an elegant solution, but in Propel the model objects are isolated from each other. And if you can do something, then at a lower level, the level of frameworka. This means that such changes must be taken into account when updating symfony, which is very inconvenient.
Propel should not be used to build large and complex web projects.
UPD
Join'y do not fit, because It is not recommended to use many join's, this is an additional load on the base, because the query is more complicated. With a large load, this is significant. But if you do everything by simple queries and pulling connections on the primary keys, then everything falls into place. Example. A selection of 20 photos, they have albums, authors, avatars of authors, avatars of albums. With join, there will be a query with a connection of 5 tables !!! And if there are 5 of them on the page !? And in my case, just like that!
UPD2
Read the article carefully))
UPD3
Continuation of a story
How I made friends with memcache and propel in symfony