How Magento manages store-wise cache
-
15-04-2021 - |
سؤال
I am currently working on an architecture where I'd like to maintain separate caches (block cache, collection cache, FPC) for each zipcode. I am making the user select a zipcode at the beginning of the journey, and I wrote plugins/observers for modifying various parts of Magento altogether (like fetching product price, which is different for each zipcode).
Everything seems to be working fine when I have cache disabled. But as I enable the cache, the data is cached for the first user and his/her zipcode, and it shows the same data to all users.
Now what I want is to maintain separate cache copies for each zipcode. I know that Magento keeps a separate cache copy for each store view. I did a lot of digging but couldn't find how Magento manages to do it. If someone could guide me to the classes/function which are responsible for the "store-view-based caching", then I could probably write plugins for those functions to maintain a zipcode based caching system.
المحلول
I finally solved it by writing a plugin for the Magento\Framework\App\PageCache\Identifier
class
app/code/Vendor/Module/etc/frontend/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Framework\App\PageCache\Identifier">
<plugin name="append_zipcode_to_page_cache_identifier" type="Vendor\Module\Plugin\App\PageCache\Identifier"/>
</type>
</config>
And the plugin class, app/code/Vendor/Module/Plugin/App/PageCache/Indentifier.php
<?php
namespace Vendor\Module\Plugin\App\PageCache;
use Magento\Framework\App\Http\Context;
use Magento\Framework\App\PageCache\Identifier as Subject;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Serialize\Serializer\Json;
class Identifier
{
/**
* @var Http
*/
private $request;
/**
* @var Context
*/
private $context;
/**
* @var Json
*/
private $serializer;
/**
* Identifier constructor.
* @param Http $request
* @param Context $context
* @param Json $serializer
*/
public function __construct(
Http $request,
Context $context,
Json $serializer
)
{
$this->request = $request;
$this->context = $context;
$this->serializer = $serializer;
}
/**
* @param Subject $subject
* @param string $identifier
* @return string
*/
public function aroundGetValue(Subject $subject, $identifier) {
$data = [
$this->request->isSecure(),
$this->request->getUriString(),
$this->request->get(\Magento\Framework\App\Response\Http::COOKIE_VARY_STRING)
?: $this->context->getVaryString(),
$this->getZipcode() // append zipcode to cache identifier
];
return sha1($this->serializer->serialize($data));
}
protected function getZipcode() {
return "123456"; // send the actual zipcode here
}
}
For modifying the Block Cache and Model Cache, we can write an after plugin for the Magento\Framework\DataObject\IdentityInterface::getIdentities()
method
Like So,
app/code/Vendor/Module/etc/frontend/di.xml
<type name="Magento\Framework\DataObject\IdentityInterface">
<plugin name="block_and_model_cache_modification" type="Vendor\Module\Plugin\Identity" />
</type>
app/code/Vendor/Module/Plugin/Identity.php
<?php
namespace Vendor\Module\Plugin;
use Magento\Framework\DataObject\IdentityInterface as Subject;
class Identity
{
/**
* @param Subject $subject
* @param array $identities
* @return array
*/
public function afterGetIdentities(Subject $subject, $identities)
{
$identities[] = "My custom identity"; // append whatever identity you want your cache based on
return $identities;
}
}
Hope that helps.