I would like to set a user cache context to a Views, but I don't know where to do this (in what hook ?). In the configuration of the View, the cache is set "Tag based"
Each user have a specific property, and I want the Views to deal with it, without totally disable the cache of the Views.
I already check this hook without success :
hook_entity_build_defaults_alter hook_entity_views_data_alter hook_views_pre_views
In each hook I have changed the $view->element[#cache][contexts] array.
I give some clarifications to my problem.
I've a "Product" content type. This content type has a reference field to a Taxonomy called "Family product" and a "Public price" number field. My goal is to display a computed price the for User called "Your price". "Your price" is not a field, because it's a computed value. To compute this value, I have another content-type called "Discount grid". With a form_alter on this content type, I list each term of the "Family product" and associate them with a textfield who take a percent of the discount value the administrator grants to this grid.
To finish, the User entity has a reference field to a "Discount grid" content. The association between the User and the Discount grid allow me to compute the "Your price" according to the family who belongs the "Product".
I hope I didn't loose you, not easy to explain.
So, I try many things since I've open this question, without success. To display my computed value with Views, I've created a custom Views field who display the computed "Your price" value by taking the "Discount grid" of the current user (the query() function is empty to prevent Views to search the field value on the database). It's working like a charm.
/**
* @ingroup views_field_handlers
* @ViewsField("node_costumer_price")
*/
class NodeCostumerPrice extends FieldPluginBase {
/**
* @{inheritdoc}
*/
public function query() {
// Leave empty to avoid a query on this field.
}
/**
* @{inheritdoc}
* @param \Drupal\views\ResultRow $values
*/
public function render(ResultRow $values) {
//Called a custom service who return the current User Discount grid
$grid = \Drupal::service('discount.service')->getGrid();
$node = $values->_entity;
$price = "";
$family = $node->get('field_family')->getValue();
$publicprice = $node->get('field_public_price')->getValue();
/* doing some calculation here */
return $this->t(number_format((float) $price, 2, ',', '') . ' €');
}
}
The problem is the cache. The computed value is always displaying the same price between two User with a different Discount grid.
I've created a custom cache context "discount". This context is matched on the node ID of the Discount Grid of the current User. This context work very well on a simple render array (tested returning a render array on a custom controller).
#modules/custom/discount/src/Context/DiscountCacheContext.php
/**
* Defines the DiscountCacheContext service, for "per discount grid" caching.
* Cache context ID: 'discount'.
*/
class DiscountCacheContext implements CacheContextInterface {
/**
* The account object.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $user;
/**
* Constructs a new UserCacheContextBase class.
*
* @param \Drupal\Core\Session\AccountInterface $user
* The current user.
*/
public function __construct(AccountInterface $user) {
$this->user = $user;
}
/**
* {@inheritdoc}
*/
public static function getLabel() {
return t('Discount');
}
/**
* {@inheritdoc}
*/
public function getContext() {
$user = User::load($this->user->id());
return empty($user->get('field_auto_part_discount_grid')->getValue()) ? 0 :
$user->get('field_auto_part_discount_grid')->getValue()['0']['target_id'];
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}
Now I'm searching how to "graft" this custom context cache on the Views. The last thing I've tried is to create a custom Views filter handler for injecting the cache context in it, without success. (by trying to reproduce the core/modules/user/src/Plugin/views/filter/Current class and adapt it with my custom cache context)
I hope be clear enough this time. I try all this week to find a solution without disable the Views caching (render time /2).