提问人:Filip Albert 提问时间:10/10/2023 更新时间:10/30/2023 访问量:50
在我的自定义PrestaShop 1.7模块中更新产品价格时,如何使Memcached值失效?
How to invalidate a Memcached value when updating a product's price in my custom PrestaShop 1.7 module?
问:
我正在使用 Prestashop 1.7 多商店。其中一家商店启用了增值税,而另一家商店则没有。我创建了一个挂在钩子上的自定义模块。在本模块中,我更新了产品的价格,但仅适用于没有增值税的商店。这确保了两家商店的最终价格相同。updateproduct
为了提高性能,我使用了 Memcached。但是我很难正确地使缓存失效。一旦缓存了非增值税商店的值(我在模块中更改的值),在尝试在产品管理中再次设置它后,它永远不会更改。它在数据库中正确更改,但 Memcached 检索旧值。如何使 Memcached 中的存储值失效或更新?我也不知道如何获得正确的 Memcached 密钥,因为它是像 ps_288e7d9f7adabca7ca488166fced130a 这样的哈希值。
目前,我发现刷新 Memcached 的唯一方法是使整个缓存失效,就性能而言,这似乎是一个次优解决方案。
Cache::getInstance()->delete('*');
这是我简化的钩子函数来更新价格:
private function updateProductPrice($params)
{
$id_product = $params['id_product'];
$price = $params['product']->price;
$id_tax_rules_group = $params['product']->id_tax_rules_group;
$shop_ids = $this->getShopIds();
$tax_rate = $this->getTaxRate($id_tax_rules_group);
foreach ($shop_ids as $shop_id) {
$is_tax = Configuration::get('PS_TAX', null, null, $shop_id);
$sql = 'SELECT `price`
FROM `' . _DB_PREFIX_ . 'product`
WHERE `id_product` = ' . (int) $id_product;
$base_price = (float)Db::getInstance()->getValue($sql);
if (!$is_tax) {
$new_price = $base_price * (100 + $tax_rate) / 100;
Db::getInstance()->update('product_shop', ['price' => $new_price], 'id_product = '.(int)$id_product . ' AND id_shop = '.(int)$shop_id);
}
}
}
如果没有启用 Memcached,一切正常。
答:
对象模型具有可在产品上使用的方法。clearCache()
调用更新查询后,使用以下代码
$params['product']->clearCache();
正如 OP 所评论的那样,上述内容不起作用,因为它仅清除 PHP 缓存。
尽管正确的方法是在产品对象上设置价格并调用其方法。直接修改数据库会跳过保存前后触发的所有钩子,并且根据您的问题,它也会跳过缓存失效。save()
上述操作也不起作用,因为 OP 正在更新产品钩子内更新产品。
在对核心进行一些挖掘后,缓存键似乎是根据 sql 查询计算的,因此您可以首先像在 Product 对象中一样构建价格查询。
构建前端价格查询:
$sql = new DbQuery();
$sql->select('product_shop.`price`, product_shop.`ecotax`');
$sql->from('product', 'p');
$sql->innerJoin('product_shop', 'product_shop', '(product_shop.id_product=p.id_product AND product_shop.id_shop = ' . (int) $id_shop . ')');
$sql->where('p.`id_product` = ' . (int) $id_product);
if (Combination::isFeatureActive()) {
$sql->select('IFNULL(product_attribute_shop.id_product_attribute,0) id_product_attribute, product_attribute_shop.`price` AS attribute_price, product_attribute_shop.default_on, product_attribute_shop.`ecotax` AS attribute_ecotax');
$sql->leftJoin('product_attribute_shop', 'product_attribute_shop', '(product_attribute_shop.id_product = p.id_product AND product_attribute_shop.id_shop = ' . (int) $id_shop . ')');
} else {
$sql->select('0 as id_product_attribute');
}
$sql = $sql->build();
构建管理产品查询:
$entity_defs = ObjectModel::getDefinition(Product::class);
$sql = new DbQuery();
$sql->from($entity_defs['table'], 'a');
$sql->where('a.`' . bqSQL($entity_defs['primary']) . '` = ' . (int) $id);
// Get lang informations
if ($id_lang && isset($entity_defs['multilang']) && $entity_defs['multilang']) {
$sql->leftJoin($entity_defs['table'] . '_lang', 'b', 'a.`' . bqSQL($entity_defs['primary']) . '` = b.`' . bqSQL($entity_defs['primary']) . '` AND b.`id_lang` = ' . (int) $id_lang);
if ($id_shop && !empty($entity_defs['multilang_shop'])) {
$sql->where('b.`id_shop` = ' . (int) $id_shop);
}
}
// Get shop informations
if (Shop::isTableAssociated($entity_defs['table'])) {
$sql->leftJoin($entity_defs['table'] . '_shop', 'c', 'a.`' . bqSQL($entity_defs['primary']) . '` = c.`' . bqSQL($entity_defs['primary']) . '` AND c.`id_shop` = ' . (int) $id_shop);
}
$adminSql = $sql->build();
从查询中计算缓存密钥。
$keyFrontend = Cache::getInstance()->getQueryHash($sql);
$keyAdmin = Cache::getInstance()->getQueryHash($adminSql);
删除密钥。
Cache::getInstance()->delete($keyFrontend);
Cache::getInstance()->delete($keyAdmin);
如果缓存处于活动状态,您应该首先进行一些检查,以便代码在有缓存和无缓存的情况下工作。
尽管所有这些都是/感觉很黑客,但我不知道这如何影响任何其他价格计算,例如特定价格、折扣等,因为他们的 sql 查询也可能需要缓存失效。我试图找出管理页面如何在保存时使产品缓存失效,以找到一种更简单的方法,但到目前为止还没有运气弄清楚。
评论
clearCache()
save()
updateproduct
评论