Using Cache in model functions, still end with return?

I’m using Apc cache in my project, and is writing my model functions data to cache, and access the cache in the controller. Should I still end the model functions with a return although it doesn’t seem needed, and why if that’s the case?

function getData() {
$mydata = ''test";
Cache::write(‘data’, $mydata);
}

Is it better that the above model function looks like this:?

function getData() {
$mydata = ''test";
Cache::write(‘data’, $mydata);
return true;
}

Hey thornstrom,

I’m not really sure what your attempting to do from your examples. I see that your method is attempting to access data however your not retrieving any data only writing into the cache.

To better explain cacheing in cakephp let me give you an example. Let say I have a database with customer entries in a customers table. When searching for data within this table I would first want to look within the apc cache to avoid any performance cost having to search a database. If the cache does not exists or appears to be obsolete then we would request the data from the database using our finders and store the results within the cache.

/**
 *  CustomersTable
 */
public function getCustomers()
{
    //  First look within the cache to see if the data already exists
    $customers = Cache::read('customers');

    //  If the cache returns a value of false, that means the server has no clue if data exists or not so we run a find method to check
    if ($customers === false) {
        //  First we run our sql statement and obtain our results, note that the data is stored within the variable $customers
        $customers = $this->find('all');

        //  Then we store the contents of the $customers variable within the customers cache
        Cache::write('customers', $customers);
   }

    //  Now we can return the value of $customers
    return $customers;
}

The very first time that you call getCustomers() you will obtain the data directly from the database, but the next time you call it (as long as the cache hasn’t expired based on your settings) you will acquire the data from the cache.

Please keep in mind, the example I’ve given you is very simple! In practice there is a lot more to consider. You will need to track events on your site to determine when new data comes in so that the cache knows when to update. These configurations vary from app to app so take it slow as you first start to work with cakephp.

You can read more on cakephp 3 cacheing here

Thanks for the reply! I will read up on the caching in Cakephp. I should probably clarify my initial question a bit though. The main issue isn’t really how to use the cache. The server has reserved memory for the apc caching, and when returning for example long arrays of data from the model to the controller using cache, it’s super fast so I’m very happy with it. In those cases I’m writing the end result from the model method to the cache, and then read from the cache in the controller. So, I’m doing a Cache::write(‘data’, $ddata) in the model, and a Cache::read(‘data’) in the controller.

But is in still good practice to do a “return true” at the end of a model method, although it doesn’t seem needed (since it works anyway).

Never return a hard coded value how you did in the example above, unless your overriding a method which returns a value and nothing can go wrong. When you return a value you want it to be meaningful. In your case you essentially want to return a boolean value indicating if the app failed to write to the cache. So in your example you would want to return the value of Cache::write(‘data’, $myData) as in the example below:

function getData() {
$mydata = ''test";
return Cache::write(‘data’, $mydata);
}

If you read the API for Cache::write you will see that the write method returns false if the cache fails. In the example you had above your app might say “yea the data cached” even though the cache fails because you hard coded return true.

The only reason, off the top of my head, for returning a hard coded value is if your using some framework which expects a value to be returned but the logic is so simple that it can’t possibly fail. This is very rare and is seldom see outside of a tutorial though.

The post above directly answers your question. But, why exactly are you coding the app in such a way that the controller is directly accessing the Cache? This is actually very bad practice, you should pretend as though the Controller knows absolutely nothing about the data and acquires everything from the Model. This will allow you to more easily refactor (update) your code without breaking functionality and, more importantly, without driving yourself crazy lol.

Imagine that you successfully write the data to the cache using the model and then right after CakePHP decides to clear out the contents of the Cache because of a configuration setting. What happens when you call Cache::read(…) at this point?

Thanks again for the reply. I’ve implemented your tip about using return cache::write() now in model functions, like this:

return Cache::write('data', $data)

Which would return false if anything goes wrong with the writing to cache as in your explanation.

Also, I’m always reading the cache in the controller right after calling the model function. Like this (inside a controller):

$this->loadModel('test');
$this->test->getData();
$data = Cache::read('data');

I have no good explanation for why I’m doing this, other than testing it, noticing that it worked well and it really sped things up :slight_smile:

My loose theory was that the model function needs to write the result somewhere while going back to the controller, and that it’s much faster first writing the data (in the model) and later reading the data (in the controller) from server’s memory instead of its hard drive, hence the speed increase.

Your close, the model does need to write to the cache but only if the Cache fails to have the data in it already. Right now your app is writing to the cache and then reading the results. And every-time that you call the controllers actions it’s repeating the process and essentially making the cache unnecessary. I believe the performance benefit your seeing is from the web browser caching data and not really CakePHP itself. Also CakePHP provides other caching mechanisms that may be assisting you, can you show me your controller’s action method so I can be sure I’m understanding your setup correctly?

The basic process would be to read the cache and ask the question, did I get data? If you did great!! That means you don’t need to request data from the database and you’ve just sped up your request. But if no data could be read, then you want to run the finder to acquire the data and write it into the Cache.

Heres a little test setup you should create to try this. Create a table with two columns: id (auto-incremental) and name. Load this table with 5000 identical rows where the name field simply has the value ‘A’ or something silly like that. You’ll understand how to properly cache immediately with this little demo lol.

Ah, I see. So the speed-up wasn’t really coming from the writing/reading from the cache during switching between controller/model, but rather the db query returning identical rows/columns and made references in the cache instead of writing all the data to the drive?

Here is my controller/method code logic (slightly modified):

[controller]
private function getPublications() {
    $session = $this->request->session();
    $this->loadModel('Publications');
    $this->Publications->getPublications($session->read('UserID'));
    $this->set('publications', Cache::read('publications'));
    $this->render('publications');
}

[model]
function getPublications($UserID) {
    $q = "SELECT * FROM publications_rs($UserID) WHERE status = 1";
    return Cache::write('publications', ConnectionManager::get('default')->execute($q)->fetchAll('assoc'));
}

The writing to cache will speed things up where the result from the query returns similar values as has already been fetched, and is working on a column level then since your small task for me had unique id values but similar name values? But in any case it will be pointless to be writing to cache in my models where the query returns only 1 row?

Lol Ok so there are a lot of issues with this code that I can go over with you one-by-one later if you’d like. Don’t feel bad, we’ve all been there what matters is your coding. For now I’m only going to go over caching as to not overwhelm you with information.

Let me show you how the Computer is reading your controller method, think of what is happening each time the controllers action is called:

private function getPublications() {
    $session = $this->request->session();

    $this->loadModel('Publications');

    //  Remember conceptually a method call is simply a fancy way of copying and pasting pre-written code
    //  so your model call would read like this within the controller
    $q = "SELECT * FROM publications_rs($session->read('UserId')) WHERE status = 1";
    Cache::write('publications', ConnectionManager::get('default')->execute($q)->fetchAll('assoc'));

    $this->set('publications', Cache::read('publications'));
    $this->render('publications');
}

Here’s the question, if I call the controllers getPublication() method 20 times, how often is it running the SQL Query and reading from the Database? Is the cache really benefiting you in this code sample?

Compare your solution to mine.

[model]
function getPublications($UserId) {
    $publications = Cache::read('publications');
    if($publications === false) {
        $q = "SELECT * FROM publications_rs($UserId) WHERE status = 1";
        $publications = ConnectionManager::get('default')->execute($q)->fetchAll('assoc');

        Cache::write('publications', $publications);
    }

    return $publications;
}

[controller]
public function getPublications()
{
    $session = $this->request->session();
    $this->loadModel('Publications');

    $this->set('publications', $this->Publications->getPublications($session->read('UserId'));
    $this->render('publications');
}

Here are the questions, how many times does this code need to ask the database for information when the getPublications action is called? How is the cache being used to benefit the performance of the application?

Ah ok, your solution looks for a value in the cache first, and only runs the query if the cache is empty. But what if the in parameter is different the next time it’s called? Let’s say the UserID the first time was 1, the query was executed and the result is written to cache. The next time the UserID is 2, but since the cache is not empty, it won’t run the new query, but instead return the value for UserID 1.

Instead of publications, call the cache user_< userid >.publications. this will give each user there own cache while you experiment