D
D
Dmitry T.2012-09-01 23:36:20
Programming
Dmitry T., 2012-09-01 23:36:20

Data caching is "more correct" describe in model or controller?

In any modern project, it is worth immediately providing for data caching, be it a file, memcached or redis.
I would like to know how you cache, i.e. in what place, what is responsible for caching?
I will give examples, for example, caching in the controller is often found in simple examples on many sites.
Every time when it is necessary to get some information from the model, it is checked whether the data that the method returns is in the cache, if not, then we “pull” the model and save the cache. Below is an example code.

class Users extends ApplicationModel {

    function __construct()
    {
    }

    function getName($id) {
        $result = $this->db->execute("SELECT user_name FROM user WHERE id = {$id}");
        return $result;
    }
}

class UserSettings extends ApplicationController {

    function __construct()
    {
        $user = new Users();
    }
    
    function showMainSettings() 
    {
        $key = "UserName_{$id}";
        $username = $this->cache->load($key);
        if ($username === false) {
            $username = $user->getName($id);
            $this->cache->save($username, $key);
        }
        /*
            another code and render view
        */
    }

}

class UserHome extends ApplicationController {

    function __construct()
    {
        $user = new Users();
    }
    
    function showHome() 
    {
        $key = "UserName_{$id}";
        $username = $this->cache->load($key);
        if ($username === false) {
            $username = $user->getName($id);
            $this->cache->save($username, $key);
        }
        /*
            another code and render view
        */
    }
}

You can describe caching in the methods of the model. Then in the controller all methods of models can be called transparently.
Approximately the same code will look like this:
class Users extends ApplicationModel {

    function __construct()
    {
        $this->cache = new Cache();
    }

    function getName($id) {
        $key = "Users_getName_{$id}";
        $result = $this->cache->load($key);
        if ($result === false) {
            $result = $this->db->execute("SELECT user_name FROM user WHERE id = {$id}");
            $this->cache->save($result, $key);
        }
        return $result;
    }
}

class UserSettings extends ApplicationController {

    function __construct()
    {
        $user = new Users();
    }
    
    function showMainSettings() 
    {
        $username = $user->getName($id);
        /*
            another code and render view
        */
    }
}

class UserHome extends ApplicationController {

    function __construct()
    {
        $user = new Users();
    }
    
    function showHome() 
    {
        $username = $user->getName($id);
        /*
            another code and render view
        */
    }
}

And another example that I came across is the use of the magic __call() method. In this case, all methods are written as if caching is not used. In the controller, either a direct call to the $object->method() method can be used to ensure that information is retrieved from the database. It will also be possible to use a prefix, something like $object->cache_method(), in which case the execution of the method is "wrapped" in the cache. Below is some more code that demonstrates this approach.
class Users extends ApplicationModel {

    function __construct()
    {
        $this->cache = new Cache();
    }

    function getName($id) {
        $result = $this->db->execute("SELECT user_name FROM user WHERE id = {$id}");
        return $result;
    }

    function __call($name,$arguments)
    {
    $parts = explode('__', $name);

    if ('cache'==$parts[0] && method_exists($this,$parts[1]) ) {
        $model = get_class($this);
        $method = $parts[1];
        $arguments_str = md5(serialize($arguments));
        $key = "{$model}_{$method}_{$arguments_str}";
        $result = $this->cache->load($key);
        if($result === false)
        {
            $result = call_user_func_array(array($this,"{$method}"), $arguments);
            $this->cache->save($result,$key);
            return $result;
        }
        else 
            return $result;
    }
    else
    {
        echo "Sorry method not found {$model}::{$method}";
        exit(1);
    }
    }    
}

class UserSettings extends ApplicationController {

    function __construct()
    {
        $user = new Users();
    }
    
    function showMainSettings() 
    {
        $username = $user->getName($id); // get data from DB
        $username_cached = $user->cache__getName($id); // get cached data if exist
        /*
            another code and render view
        */
    }
}

class UserHome extends ApplicationController {

    function __construct()
    {
        $user = new Users();
    }
    
    function showHome() 
    {
        $username = $user->getName($id); // get data from DB
        $username_cached = $user->cache__getName($id); // get cached data if exist
        /*
            another code and render view
        */
    }
}

He gave the three most common methods that were found on the net. I would be grateful for links to others and indeed a more advanced description of caching in / for MVC.
So actually the question. Do you use any of these methods or their modifications and why? Perhaps you are using something more rational in terms of MVC, please share.
Which of these methods, or any of the others, has more to do with the MVC ideology?
Thanks in advance to all those who share their experience with the public!

Answer the question

In order to leave comments, you need to log in

6 answer(s)
L
LeoCcoder, 2012-09-02
@LeoCcoder

I usually cache in the model, the controller should only have the model->getData function, and where this data comes from is no longer the concern of the controller, and here's why: only the model knows what data can / cannot be cached, how long the cache remains valid and when and how data needs to be updated. It is bad when information about the nature of the data is blurred both on the model and on the controller. IMHO.

V
Vladimir Chernyshev, 2012-09-02
@VolCh

In the repository. A simple POPO model, knows nothing about the database at all, its only area of ​​​​responsibility is to model the subject area. The responsibility of the repository is to store the entities of the model where and as soon as it knows. Alternatively, yes, a proxy that implements the same interface as the "clean" repository. Another option is to cache query results even lower, somewhere at the DBAL/DAL level. But in practice, I only implemented directly in the repository, something like

class UserRepository {
  public function getById($id) {
    if ($this->cache->hasKey('user' . $id)) {
      $user = $this->cache->getByKey('user' . $id);
    } else {
      $user = $this->db->getUserById($id);
      $this->cache->set('user' . $id, $user);
    }
}

W
wscms, 2012-09-02
@wscms

In the model
The model selects data from the database, saves it to the cache
The model saves the data to the database - updates / clears the cache
The model can be called from many controllers. It is irrational to write cache saving/updating in each of the controllers.

E
egorinsk, 2012-09-02
@egorinsk

Magic methods are evil. The person who has to debug your code will then bury you alive in a graveyard.
Whether it is worth caching simple selections (by id) is a moot point, for unloaded projects it is not worth it. It is worth caching complex selections, and in some cases, chunks of HTML.

D
delmot, 2012-09-02
@delmot

I never liked the cumbersome constructions of checking for the presence of cached data. Therefore, I am happy to use the approach implemented in Laravel: laravel.com/docs/cache/usage
Achieved getting rid of the cumbersome construction shown in your examples, while maintaining brevity and clarity of the actions performed.
Your question is rather ideological, rooted in the issue of "thick/thin controllers/models". Here is a post on the topic from Makarov: rmcreative.ru/blog/post/tonkie-i-tolstye-modeli

A
Alexander, 2012-09-02
@akalend

IMHO it depends heavily on logic, I cache:
- data (Output in the Model), as a rule, the main content, for example, a large request that breaks pages
- I cache the HTML block (In the controller), usually tops, or thematic banners for thematic sections or other offers , not the main content, but often requested ) As a rule, such content is calculated by krone.
- a fully HTML page (usually index.htm or frequently-requested pages). I have this caching configured using WEB server tools.
If desired, block caching can also be configured using WEB server tools using ssi. I wrote about this on Habré habrahabr.ru/post/109050/
But in this case, the framework becomes much more complicated

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question