The idea of having properties that are lists of other entities is a really exciting idea for me. I'm glad there are already actions to manipulate them a little bit.

This might already be on the "To do" list, but I would like to see conditions that evaluate lists. I think they would be similar to the loops that can be put into the actions, in that a condition would be applied to each item in the list. The outer list condition should control whether all of the items need to meet the condition, or just one, or possibly even something like "at least 3". Any condition that takes the list's type could be reused this way, and this kind of abstraction seems like a really good idea.

CommentFileSizeAuthor
#2 821986.patch9.35 KBIsland Usurper
#1 821986.patch12.41 KBIsland Usurper

Comments

Island Usurper’s picture

Component: Rules Core » Rules Engine
Status: Active » Needs review
StatusFileSize
new12.41 KB

Here's a first stab at it. I have to tweak my setup so that I can run the tests myself, so there's no real guarantee it works like it should. The UI at least looks mostly right.

Island Usurper’s picture

StatusFileSize
new9.35 KB

Too much in that patch. Sorry.

Status: Needs review » Needs work

The last submitted patch, 821986.patch, failed testing.

Island Usurper’s picture

Status: Needs work » Needs review

#2: 821986.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 821986.patch, failed testing.

Island Usurper’s picture

Status: Needs work » Needs review

#2: 821986.patch queued for re-testing.

fago’s picture

Title: Intelligent list conditions » Evaluate conditions on list items

Interesting idea. I only thought about adding another loop plugin for evaluating conditions on list items following the all approach. I'm not entirely sure about the "one of" loop - what's the use case for something like that? Does it make sense to still execute actions if the conditions doesn't match all entries? Perhaps you can think of a nice use case for that?

A part from that it might make sense to do it with just one plugin and make the number of entries that have to match configurable. That way don't confuse users with multiple rather similar plugins.

Island Usurper’s picture

Status: Needs review » Needs work

That's interesting, because I think the "one of" would be more useful than "all".

Generally, when you are doing conditions on roles, you only care if the user has one specific role. The rest of the roles don't really matter. If you only have "all items" conditions available, it would be very hard to make anything useful when dealing with roles.

In Ubercart, I'm making an order's products a list of entities, and I can think of several times where it is useful to ask "if customer orders this particular product" but not let other products affect the outcome.

Logically, though, I guess "one of" is the negation of "all". And I like the idea of a configurable number of items that must meet the condition. I didn't do that because I was lazy. :) If we do that, then I guess we really don't need two plugins for list conditions.

fago’s picture

Interesting. For the roles use case I'd say we miss list-contains-item condition ( -> in_array()), but I've added a condition dedicated to roles (user_has_role) recently. Generally I think it's a good idea to do dedicated conditions/actions for everything that affects functionality, for everything else the general data conditions/actions should be fine.

In Ubercart, I'm making an order's products a list of entities, and I can think of several times where it is useful to ask "if customer orders this particular product" but not let other products affect the outcome.

Would the "contains" condition also work for that use case?
But I see that such a kind of loop could be useful for checking for the existence of something matching a certain condition. However still any actions applied with the action loop would be applied to the whole set.

Island Usurper’s picture

Erg. I might be wrong about "one of" being the opposite of "all". I apparently have not taken enough math classes.

I don't think "contains" would work because order:products is a list of entities. It would be hard to load up an order-product entity to be used in conditions like this. But I made order-products inherit from node entities, so I was hoping to get all of the node-specific conditions for free. Then I could have conditions like "if order has a product that costs more than $50, is published, and was created by a user whose account was created less than a month ago". In theory, comments and taxonomy terms could be treated the same way, because they could be represented as lists of entities.

I think you're right about action loops applying the action to every item, but I think it's already possible to get around that by using a Rule component instead of an actual action. The Rule would have its own conditions that it checks against the list item, and then evaluate it's actions if the conditions pass. I haven't actually tested this, but I expect it to work.

fago’s picture

>The Rule would have its own conditions that it checks against the list item, and then evaluate it's actions if the conditions pass. I haven't actually tested this, but I expect it to work.

It will, but for this case we don't need this condition loops at all. Just loop over the list and apply a component to each item.

>I don't think "contains" would work because order:products is a list of entities. It would be hard to load up an order-product entity to be used in conditions like this.

Entity lists are internally represented by their ids (while you can pass a full entity(ies) when creating wrapper too) - so the matching would be id-based but should work.

>But I made order-products inherit from node entities, so I was hoping to get all of the node-specific conditions for free.
Uhm, sounds dangerous. Consider someone is extending nodes, then your products won't have this extension. Thus rules integration for this node-centric extension would fail for your products. But it should be still rather to re-use node-integration - just take over the action info / condition info and rename it properly to use products.

>"if order has a product that costs more than $50, is published, and was created by a user whose account was created less than a month ago" -> then give a discount ;)

Makes sense to me.

Island Usurper’s picture

Uhm, sounds dangerous.

It shouldn't be, because products actually are nodes. If someone extends all nodes, then products should have access to that data somehow. But if they extend only some node types, then products wouldn't know about it, and their rules integration shouldn't try to access it. At least, that's the way I understand the 'parent' key in hook_rules_data_info().

fago’s picture

>It shouldn't be, because products actually are nodes.

Ah I see. However I'm still unsure whether it is a good idea to do. The problem is that a node can only be of one data type at at the same time. If a node fulfills multiple "roles", e.g. being a product and a organic group and a book node, it cannot be of the same types at the same time. I initially thought about introducing something like a "roles" concept for that, but didn't implement it as
a) it would have made things rather complex
b) would be something new devs would have to understand first
c) "roles" would be sometimes hard to detect, e.g. each node can be a book node.

There are multiple ways to go, the best one probably depends on the specific use case:
* For books, there are just two book related properties that are always there. If they are used and it is no book node, an exception is thrown (what aborts the action/condition execution).
* Stick to bundles/node types. Add the properties for the bundles where your module is enabled and for rules you may specify an array of allowed bundles using the 'bundles' key in the parameter info of an action/condition. If that array of allowed bundles changes though, it might invalidate existing configurations - e.g. because it is based upon a node of certain type. Those would fail the integrity check then and be marked as erroneous in the UI.
* Provide a condition to check for a node being a product. This might assert some new properties using the _assertion callback, but asserting another data type wouldn't be good for the above reasons. (Cannot have multiple at the same time). Just use 'node' as parameter and throw an exception if the passed node is no parameter.

Alternatively we might look into support such a feature. I think I previously called this "entity tagging" as roles is easily confused with user roles. That way a node could be tagged as "book", "group" and "product" at the same time. We could support a new key "tag" => 'product' in the parameter info array, which is respected when doing type matching. Additionally we could have a tags key in the variable info, which then can be asserted by conditions (or it is given by default for a certain variable). Doesn't sound too hard - indeed sounds very similar to the 'bundle' key we have already.

fago’s picture

Thinking about that all, it looks to me that the option "Stick to bundles/node types." is the best to go for groups/products. I fear that those "type tags" just unnecessarily overcomplicate things.

amitaibu’s picture

> However still any actions applied with the action loop would be applied to the whole set.

Maybe the new condition should be more of an action -- that will trim the list to only the ones matching the conditions.

> is the best to go for groups/products

Groups is a bit different than products:
1) Every fieldable entity can be a group. Groups are recognized by the presence of field "group_group"
2) There is a group entity, but it's for internal use. It's a an entity, just becuase CRUD and caching come for free when using Entity API.

itangalo’s picture

Some thoughts about a different approach for treating lists can be found here: http://groups.drupal.org/node/99919

adrien.felipe’s picture

Looks like the thread took another path than adding loops to conditions.

I have a use-case where I need loops for conditions:
- I have a node related to a list of users (with the relation module)
- Each user relation entity has a Score field (awesome concept)
- And I finally have an action that needs to be launch if one of the users score is greater than 5

This means that for the condition to be validated I need to loop through all related users.
And here the loop for condition makes sense as the number of users is not fixed.

This is just a simplificated example and I also need other conditions like : all other related users
Which means looping through all related users but excluding one or several in particular.
Here then lists make sense.

As I can't find some code doing that, I'll try to create my own rule to do so, even if I have no idea about rules API.
I'll give an eye first at Island Usurper's patch, but any advice showing me the direction would be appreciated.

@fago I didn't get by reading this thread why you looked worried about adding lists/loops to conditions?

wodenx’s picture

I'm wondering if anything ever came of this (or the approach mentioned in #16) - seems like both would be very useful.

itangalo’s picture

#18: Not that I know. :-/

DanZ’s picture

Component: Rules Engine » Rules Core

Any movement on this? It would be extremely useful.

I haven't looked at the current patch, but I already had some thoughts about this before finding this issue post.

The parameters could be as follows:

  • A condition which works on a single item of the list.
  • The list data item to check, obviously.
  • A numeric comparison operator: <, ≤, =, ≥, or >.
  • A number (ignored for the "all" operator).
  • A numeric type operator, "normal" or "percent"

The overall condition list evaluates as true if the right number of items on the list have their conditions evaluate as true.

This covers "none" with "= 0" and "all" with "= 100%".

This would probably have to be a multi-stage form, right? The type of condition you select will determine which kinds of lists can be selected.

The use case for me is e-commerce. I need to check all the products in an order to find out which shipping methods are allowed. For instance, Media Mail is only allowed if all the products are books.

soapboxcicero’s picture

I've created https://drupal.org/project/rules_list_conditions which provides two loops that you can use in a condition, ANY and ALL.

fago’s picture

Status: Needs work » Fixed

ad #20: You can already evaluate conditions on a specific list item by using the list[X] data selector. The idea of having configurable percentages for the number of items that must match is interesting, but as we've got the rules_list_condition module I think it would be a good addition there.

ad #21
Thanks for your contribution soapboxcicero - that looks very handy. I've added it to the list of useful integration modules on the project page.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.