Cache / Cache

And now that you know everything about Jet MVC, we have one last topic left, the cache. We've stumbled on this topic here and there, but it's clearly important. So we'll repeat everything we've already said and discuss the topic in more detail.

What is stored in the cache?

Jet MVC stores the following data in the cache:

  • Base Map
    This is an asicoated field that allows you to quickly identify which base and location it is and avoid constant searching of base definitions.
  • Site maps
    These are associated data arrays stored separately for each base and locale. Exactly what is in the maps is a matter of internal implementation (but nothing prevents you from looking at the data and the sources, of course). The goal is to avoid repeated searching of site definitions and to minimize the amount of I/O operations and time required.
  • Static (cacheable) page content
    As you already know, content of pages can define that it is cacheable. Such content is generated once and then logged to the cache (of course, if the cache is active), and on the next pass there is no need for dispatching at all - i.e. calling a controller action.

The validity of cache entries is determined only by when the MVC cache is devalidated / reset.

What I can highly recommend is not to rely only on MVC cache and to solve the next level of cache at the level of controllers (and modules), always according to the situation, with thought about the whole architecture of your application. And it is also possible to implement a cache that records the entire generated static pages. These are things that in practice are closely related to the requirements of a particular project, and so it's up to you and your inventiveness. However, don't be afraid to use the cache that Jet MVC already has. It can solve a lot of things. But at the same time, please don't assume that it's a panacea. The profiler, the stress tests and your experience always have the last word.

Cache context

This has already been mentioned here. But it is not at all inappropriate to repeat them here and describe it in more detail.

Let's use a specific situation to describe it, and that's the chapter of the documentation you're reading right now.

The Web.Doc.Browser module took care of displaying this text and found this chapter based on a part of the URL. It then replaced the meta information in the article text with normal links to other chapters, formatted the sample code pieces, set up breadcrumb navigation and context menu. He just did a lot of operations that would have to be done over and over again, and quite unnecessarily, because if no one modifies the documentation, the result will still be the same.

But all positions for which the module has generated content are marked as cacheable. This means that the module will only do this work once (i.e. until someone in the administration changes the documentation and the cache is devalued).

It's all clear. But there's a trap. There is one page for all the documentation chapters in terms of Jet MVC in this site. And the static content stored in the cache needs to be uniquely identified somehow. For identification, there is a base ID, a locale code, a page ID, and also a key identifying the specific content of the page. However, this information is common and identical for all documentation chapters. So it wouldn't work that simply, because one cache entry would be valid for the whole documentation and you could look at any URL of any chapter, but the content would still be the same ...

For this reason, the corresponding Web.Doc.Browser application controller must do one key thing during the resolv process. Tell the page what the cache context is. In this particular case you are looking at, it does this: MVC::page()->setCacheContext( static::$article_id );

And from now on, the context (here the ID of the documentation article, but it can be anything else) becomes part of the key for loading and saving data to and from the cache.

WARNING! I mentioned that the context is set during resolv. This information must not come off as peripheral. On the contrary, it is very important. Resolving is always done precisely to set the cache context correctly. Otherwise it would logically not be possible to load the cache correctly. Therefore, it is important to have a well-optimized resolving process (resolv() method) in the controller.

As I have already given this documentation as an example, I will add that I solve this situation by storing the map with the URLs of the articles and their IDs separately. Such a simple map doesn't even need to be in the database, but just store it in the ~/application/data/ directory and then there is no need to execute even one SQL query in the final step (when the cache is warm - of course)

How you do it is of course up to you ;-)

Initializing a cache

Initialize the MVC cache in the script ~/application/Init/Cache/MVC.php. To illustrate, we will show its form:

namespace JetApplication;

use 
Jet\MVC_Cache;
use 
Jet\SysConf_Path;

use 
Jet\MVC_Cache_Backend_Files;

require_once 
SysConf_Path::getLibrary() . 'Jet/MVC/Cache/Backend/Files.php';
$backend = new MVC_Cache_Backend_Files();


/*
use Jet\MVC_Cache_Backend_Redis;

require_once SysConf_Path::getLibrary().'Jet/MVC/Cache/Backend/Redis.php';
$backend = new MVC_Cache_Backend_Redis();
*/

MVC_Cache::init$backend );

As is typical for Jet, the strategy via dependency insertion is used again. You create an instance of the desired backend and pass that to the facade, which takes care of the cache and thus acts as a container. Note that here again, Autoloader is not used yet, but conventional require is used.

Cache on/off

In the Jet system configuration, the Jet\SysConf_Jet_MVC class and the setCacheEnabled and getCacheEnabled methods are used to enable and disable it.

Setting is done in the script ~/application/config/Jet.php.

Backend - interface Jet\MVC_Cache_Backend and class Jet\MVC_Cache

Let's see what the backend interface should be. Of course you can develop your own backends. Implementing this interface is the only requirement.

The facade and container class Jet\MVC_Cache has an identical interface (in the sense of the same classes - only static). This is the class through which Jet works with the MVC cache.

Method Meaning of
public isActive(
): bool
Indicates whether the cache is active.
Must take into account the system configuration.
In addition to the configuration, it must take into account technical considerations whether the cache is technically available and usable.
public reset(
): void
Devalidate the cache. Warning! It should work even if the cache is disabled by system configuration.
public loadBaseMaps(
): array|null
Retrieves a map of bases.

If the cache is not active or does not contain the necessary data, then it returns null.
public saveBaseMaps(
array $map
): void
Saves the map of bases.

If the cache is not active, then it does nothing.
public loadPageMaps(
MVC_Base_Interface $base,
Locale $locale
): array|null
Fetches site maps for the given base and localization.

If the cache is not active or does not contain the necessary data, then it returns null.
public savePageMaps(
MVC_Base_Interface $base,
Locale $locale,
array $map
): void
Saves site maps for a given base and location

If the cache is not active, then it does nothing.
public loadContentOutput(
MVC_Page_Content_Interface $content
): string|null
If the cache is active, it loads the previously generated output (a piece of HTML, text, XML, ...) for the content and context.

If the cache is not active or does not contain the necessary data, then it returns null.
public saveContentOutput(
MVC_Page_Content_Interface $content,
string $output
): void
If the cache is active, it saves its output (a piece of HTML, text, XML, ...) for the given content and context.

If the cache is not active, then it does nothing.

Prepared backends

Backend Description
Jet\MVC_Cache_Backend_Files A basic backend that stores data in like PHP files in the ~/cache/ directory.

Sufficient for common and basic use.

Uses a low-level backend Jet\Cache_Files.
Jet\MVC_Cache_Backend_Redis In particular, if you need to run your application on multiple servers, or for some other reason saving to files is just not enough, you have the option to use Redis.

It uses a low-level backend Jet\Cache_Redis.
Previous chapter
Jet\MVC_Layout_OutputPostprocessor
Next chapter
Other (simplified) approaches to MVC