#3216713:Add formatter and static caching
Closes #3216713
Merge request reports
Activity
155 155 return $fields; 156 156 } 157 157 } 158 159 /** 160 * Implements hook_entity_load(). 161 */ 162 function commerce_promotion_entity_load(array $entities, $entity_type_id) { 155 155 return $fields; 156 156 } 157 157 } 158 159 /** 160 * Implements hook_entity_load(). 161 */ 162 function commerce_promotion_entity_load(array $entities, $entity_type_id) { 163 // Add static caching for usage promotions and coupons. 164 $applicable_entity_type = in_array($entity_type_id, ['commerce_promotion', 'commerce_promotion_coupon']); 165 if ($applicable_entity_type) { 166 $is_promotion = $entity_type_id == 'commerce_promotion'; 167 $cache_name = $is_promotion ? 'PromotionUsage' : 'CouponUsage'; 168 $usage_cache = &drupal_static(__FUNCTION__ . ":{$cache_name}", []); That isn't what I meant by static caching.
The static caching needs to happen in the PromotionUsage service.
Using two properties on the service.
$couponUsage and $promotionUsage;
The usage should be cleared on register().
$couponUsage and $promotionUsage should be two arrays keyed. $couponUsage needs to be keyed by coupon id and promotion usage by promotion ID.
163 // Add static caching for usage promotions and coupons. 164 $applicable_entity_type = in_array($entity_type_id, ['commerce_promotion', 'commerce_promotion_coupon']); 165 if ($applicable_entity_type) { 166 $is_promotion = $entity_type_id == 'commerce_promotion'; 167 $cache_name = $is_promotion ? 'PromotionUsage' : 'CouponUsage'; 168 $usage_cache = &drupal_static(__FUNCTION__ . ":{$cache_name}", []); 169 170 if (empty($usage_cache)) { 171 $usage_service = \Drupal::service('commerce_promotion.usage'); 172 $usage_cache = $is_promotion ? 173 $usage_service->loadMultiple($entities) : 174 $usage_service->loadMultipleByCoupon($entities); 175 } 176 177 foreach ($entities as $entity) { 178 $entity->usage = (int) $usage_cache[$entity->id()]; 17 * }, 18 * ) 19 */ 20 class UsageLimitFormatter extends FormatterBase { 21 22 /** 23 * {@inheritdoc} 24 */ 25 public function viewElements(FieldItemListInterface $items, $langcode) { 26 $elements = []; 27 $field_name = $items->getName(); 28 $entity = $items->getEntity(); 29 30 // Get usage for promotions and coupons from the 31 //static cache populated in hook_entity_load(). 32 $current_usage = $entity->usage; added 1 commit
39 53 'mail' => $order->getEmail(), 40 54 ]) 41 55 ->execute(); 56 57 // Clear static cache for usage count of promotion/coupon. 58 $this->promotionUsage[$promotion->id()] = 0; changed this line in version 3 of the diff
94 114 } 95 $promotion_ids = EntityHelper::extractIds($promotions); 96 $query = $this->connection->select('commerce_promotion_usage', 'cpu'); 97 $query->addField('cpu', 'promotion_id'); 98 $query->addExpression('COUNT(promotion_id)', 'count'); 99 $query->condition('promotion_id', $promotion_ids, 'IN'); 100 if (!empty($mail)) { 101 $query->condition('mail', $mail); 102 } 103 $query->groupBy('promotion_id'); 104 $result = $query->execute()->fetchAllAssoc('promotion_id', \PDO::FETCH_ASSOC); 105 // Ensure that each promotion ID gets a count, even if it's not present 106 // in the query due to non-existent usage. 115 116 // Add static caching for usage promotions. 117 $this->promotionUsage = &drupal_static(__METHOD__, []); The static cache is $this->promotionUsage, there's no need to call &drupal_static() inside a class.
That is how I think loadMultiple() should look like:
public function loadMultiple(array $promotions, $mail = NULL) { if (empty($promotions)) { return []; } $promotion_ids = EntityHelper::extractIds($promotions); $usage_to_load = $promotion_ids; // When not specifying an email, filter out the promotion IDS for which we // already fetched the usage. if (!$mail) { $usage_to_load = array_diff_key($promotion_ids, $this->promotionUsage); } if ($usage_to_load) { $query = $this->connection->select('commerce_promotion_usage', 'cpu'); $query->addField('cpu', 'promotion_id'); $query->addExpression('COUNT(promotion_id)', 'count'); $query->condition('promotion_id', $usage_to_load, 'IN'); if (!empty($mail)) { $query->condition('mail', $mail); } $query->groupBy('promotion_id'); $this->promotionUsage += $query->execute()->fetchAllAssoc('promotion_id', \PDO::FETCH_ASSOC); } // Ensure that each promotion ID gets a count, even if it's not present // in the query due to non-existent usage. $counts = []; foreach ($promotion_ids as $promotion_id) { $counts[$promotion_id] = 0; if (isset($this->promotionUsage[$promotion_id])) { $counts[$promotion_id] = $this->promotionUsage[$promotion_id]['count']; } } return $counts; }
This will get the usage from the static cache if present, but only when the email is not specified.
Static cache for when the email is specified is probably unnecessary as this is done only once per request.
changed this line in version 3 of the diff
47 * @param array $third_party_settings 48 * Any third party settings. 49 * @param \Drupal\commerce_promotion\PromotionUsageInterface $usage 50 * The usage. 51 */ 52 public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, PromotionUsageInterface $usage) { 53 parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings); 54 55 $this->usage = $usage; 56 } 57 58 /** 59 * {@inheritdoc} 60 */ 61 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { 62 return new static($plugin_id, $plugin_definition, $configuration['field_definition'], $configuration['settings'], $configuration['label'], $configuration['view_mode'], $configuration['third_party_settings'], $container->get('commerce_promotion.usage')); Let's do the following instead.
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); $instance->usage = $container->get('commerce_promotion.usage'); return $instance;
See PaymentMethodProfileFormatter for an example. (That removes the need of overriding the __construct().
changed this line in version 3 of the diff
124 161 } 125 $coupon_ids = EntityHelper::extractIds($coupons); 126 $query = $this->connection->select('commerce_promotion_usage', 'cpu'); 127 $query->addField('cpu', 'coupon_id'); 128 $query->addExpression('COUNT(coupon_id)', 'count'); 129 $query->condition('coupon_id', $coupon_ids, 'IN'); 130 if (!empty($mail)) { 131 $query->condition('mail', $mail); 132 } 133 $query->groupBy('coupon_id'); 134 $result = $query->execute()->fetchAllAssoc('coupon_id', \PDO::FETCH_ASSOC); 135 // Ensure that each coupon ID gets a count, even if it's not present 136 // in the query due to non-existent usage. 162 163 // Add static caching for usage coupons. 164 $this->couponUsage = &drupal_static(__METHOD__, []); changed this line in version 3 of the diff
added 1 commit
added 1 commit