Score:1

Why custom condition is not containing parent entity?

us flag

I'm using:

  • Drupal 9.1.7
  • Commerce 2.24

I'm trying to create my custom condition (based on https://docs.drupalcommerce.org/commerce2/developer-guide/core/conditions). However parent entity is always NULL. Seems like parent entity is only working when I specify commerce_order as entity_type only, but I need commerce_order_item. ParentEntityAwareInterface and ParentEntityAwareTrait are in use. Debugging show that:

  public function evaluate(EntityInterface $entity) {
    $this->assertEntity($entity);
    /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
    $order_item = $entity;
    /** @var \Drupal\commerce_promotion\Entity\PromotionInterface $promotion */
    $promotion = $this->parentEntity;
    //$promotion is NULL
    // rest of the code
  }

$promotion is always null.

Annotation:

 * @CommerceCondition(
 *   id = "myproj_product_condition",
 *   label = @Translation("Product chooser"),
 *   category = @Translation("Product chooser"),
 *   entity_type = "commerce_order_item",
 *   parent_entity_type = "commerce_promotion",
 *   weight = 9,
 * )
apaderno avatar
us flag
I looked at the code used by the *Commerce Core* module. I cannot say why `$this->parentEntity` would be `NULL`, but the explanation could be in [`Promotion::getConditions()`](https://git.drupalcode.org/project/commerce/-/blob/8.x-2.x/modules/promotion/src/Entity/Promotion.php#L271), [`Promotion::apply()`](https://git.drupalcode.org/project/commerce/-/blob/8.x-2.x/modules/promotion/src/Entity/Promotion.php#L590), and [`Promotion::applies()`](https://git.drupalcode.org/project/commerce/-/blob/8.x-2.x/modules/promotion/src/Entity/Promotion.php#L554).
apaderno avatar
us flag
See the comment on `Promotion::applies()`: *Filter the conditions just in case there are leftover **order item conditions** (which have been moved to offer conditions).* (Emphasis is mine.)
Codium avatar
us flag
@apaderno I'm debugging and it show that my condition `evaluate()` method is running before `\Drupal\commerce\Plugin\Commerce\Condition\ParentEntityAwareTrait::setParentEntity`, so that's why parent entity is NULL. Strange.
apaderno avatar
us flag
`setParentEntity()` is not always called. For what I can see, reading the code, the only classes calling that method are `Promotion`, but only for *commerce_order* conditions, and `PaymentGateway`.
apaderno avatar
us flag
I don't understand what *which have been moved to offer conditions* would mean, in the code comment I quoted earlier. What happens when a module implements a condition that is associated to the `Promotion` class but asks to get a `OrderItem` instance as argument? Is there code that assigns those conditions to an instance of the `OfferItem` or `Offer` class instead of the `Promotion` class as the class annotation says?
apaderno avatar
us flag
That is essentially the reason why I haven't posted an answer: It's not clear to me what the Commerce Core code is doing, not at the point to show which code is assigning a condition to a class instance that is different to the one requested in the annotation.
Score:0
in flag

The docs note this:

(If you want the Condition to apply to multiple parent entity types, you can leave this property unset; however, you will need to be careful in your evaluate() method implementation to check the type of the parent entity before accessing any of the parent entity's methods.)

So it seems the annotation would be:

 * @CommerceCondition(
 *   id = "myproj_product_condition",
 *   label = @Translation("Product chooser"),
 *   category = @Translation("Product chooser"),
 *   entity_type = "commerce_order_item",
 *   weight = 9,
 * )

and assert:

$promotion = $this->parentEntity;

if (check $promotion is a certain entity type) {
 ...
}

Clear your cache after updating the Annotation (and may have to re-create the Rule? unsure if it affects that). Beyond that it could be a bug in Drupal Commerce.

apaderno avatar
us flag
The annotation used from the OP isn't wrong. It's the same annotation used by the [`OrderItemQuantity`](https://git.drupalcode.org/project/commerce/-/blob/8.x-2.x/modules/promotion/src/Plugin/Commerce/Condition/OrderItemQuantity.php#L29) class, which also uses `$promotion = $this->parentEntity;` in its [`evaluate()`](https://git.drupalcode.org/project/commerce/-/blob/8.x-2.x/modules/promotion/src/Plugin/Commerce/Condition/OrderItemQuantity.php#L81) method. The error isn't setting both *entity_type* and *parent_entity_type*; if there is something wrong, it's something else.
Kevin avatar
in flag
The entity type in that example is different, though? `commerce_order` vs `commerce_order_item`?
apaderno avatar
us flag
I meant that the issue should be further investigated, to understand whether `$this->parentEntity` can always be used and whether there is an alternative.
Codium avatar
us flag
@apaderno I see only examples of commerce_order + commerce_promotion, but condition can work with commerce_order_item as well according to docs
apaderno avatar
us flag
@Codium It does, but in that case, the condition doesn't get it's `parentEntity` set. I think I understood why that happens, looking at the methods I linked in the other comment I posted, but I still find something not clear.
Codium avatar
us flag
@apaderno i'm investigating further, thanks for you help
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.