In RulesPlugin::setParent(), the existing parent is removed before the check for compatible containers. In the odd instance of setting the parent of an action to an incompatible container, if the RulesEvaluationException is actually caught, the existing parent is forcibly removed before the error check.

See use case in #1666802-3: Keep embedded elements under compatible containers in container UI.

Comments

zhangtaihao’s picture

Status: Needs review » Active
StatusFileSize
new1.58 KB

Corrected issue title.

Also, it would seem much more reasonable to use 'embeddable' from $this->pluginInfo() to check for compatibility. Opinions?

zhangtaihao’s picture

Title: Setting parent of abstract plugin to incompatible container removes its current parent » Setting parent of plugin to incompatible container removes its current parent
Status: Active » Needs review

Changed issue status.

zhangtaihao’s picture

Status: Active » Needs work

Okay, that hasn't worked.

zhangtaihao’s picture

Status: Needs work » Needs review
StatusFileSize
new2.01 KB

Okay the problem with using 'embeddable' is that RulesEventSet extends from RulesRuleSet and uses RulesRuleSet::rule() to add a rule, which adds it as an action, which in turns tries to call setParent().

My personal judgment says 'reaction rule' should be embeddable in 'event set'.

zhangtaihao’s picture

All tests pass on my server.

mitchell’s picture

Status: Needs review » Active

Tested adding an action to a conditional with #1:

Hmm. I found the relationship between making RulesPlugin throw an error if you try to apply an invalid parent plugin setting along with RulesContainerPluginUI making options like these unavailable in the UI to be very interesting. These seem almost like implied behaviors, whereas it could be possible to integrate the concepts in a deeper way and expose this functionality through Rules' API and UI API with more reused functionality. Could an abstract plugin instances' declared embeddables be reflected in entity_info and these patches be based on that?

What about adding a property to Rules Configurations to represent the embeddables provided to RulesAbstractPluginDefaults? Perhaps, both patches could also be reworked similar to what I said above, and then another could rework checkParameterSettings()? This is getting significantly above my head now. But wow, that //TODO: Make sure used values are allowed. (key/value pairs + allowed values) almost matches excatly!

I'll reply to #4 separately.
Edited slightly.

mitchell’s picture

> My personal judgment says 'reaction rule' should be embeddable in 'event set'.
This seems like a perfect match to the topic in #841336: [Meta] Interchange with other rules languages by aligning concepts.

Edit: And I think it should be a separate issue.

zhangtaihao’s picture

I am unsure as to what you meant about #1666802-25: Keep embedded elements under compatible containers in container UI being unnecessary. That change was to prevent the row to add "stuff" to actions from being considered draggable, basically because the operations row isn't in a table footer. EDIT: But, yes, you're right, it should become unnecessary once the bugs are fixed.

Regarding further integrating the concepts between the engine and the UI, I would beg to differ. There should be minimal coupling between plugin and UI via Faces. Plugins are meant to drive functionality. Configuration is represented as entities. This is for the purpose of consistency and (again) loose coupling between data, functionality and user interface (much like the MVC concept). Thus, entity_info and plugin_info serve entirely different purposes. This separation of concerns is also evident in Drupal 8 Plugin architecture.

The reason in the patch I'm using the 'embeddable' declaration from the plugin info to test for compatible containers is that the alternative was to declare a redundant method (e.g. getCompatibleContainer()). Additionally, the only reason the UI also uses 'embeddable' from plugin info should be to complement the conceptual hierarchy in the plugin controllers, not the other way around.

Also, parent isn't something to go into the rules_config entity, basically because a rules_config entity has no parent (i.e. RulesPlugin::isRoot() == TRUE). That certain configurations have children is merely a quality of the container plugin sub-concept.

Finally, as you suggested, I have added an issue for #4:

#1672444: carify the UI-only use of the embeddable key

mitchell’s picture

> I am unsure as to what you meant about #1666802-25: Keep embedded elements under compatible containers in container UI being unnecessary.
Oh, I see how my words came out now. I meant to say that testing #25 with this patch isn't necessary, because it prevents this error from occurring. That's all.

zhangtaihao’s picture

Cool.

I was just about to suggest that getting setParent() right is also to play nice with code-level manipulation.

zhangtaihao’s picture

StatusFileSize
new1.72 KB

There is an additional problem with the existing setParent() code: when using == to check if the given parent is already current, PHP triggers the error message "Fatal error: Nesting level too deep - recursive dependency?" on the line that does the comparison. Presumably somehow the child's and parent's references to each other trigger the recursive check. To fix the issue, the comparison operator needs to be changed to ===.

This symptom can be reproduced using the import from #1666802-21: Keep embedded elements under compatible containers in container UI.

Rerolled patch from #1 with the minor change.

zhangtaihao’s picture

Also worth pointing out that this issue now effectively depends on #1672444: carify the UI-only use of the embeddable key.

zhangtaihao’s picture

StatusFileSize
new1.82 KB
new844 bytes

Same thing as #11 happens when trying to drag a tree into another embeddable.

You can test using the attached action set. Try to drag the "(Else) If" from one conditional to another and save.

This patch is the same as #1 with the additional $strict argument for array_search() passed as TRUE. This is effectively the same change as #11, just for PHP internals.

zhangtaihao’s picture

I've temporarily updated Conditional Rules to match this change.

zhangtaihao’s picture

Status: Active » Needs review

Changing issue status.

klausi’s picture

Assigned: Unassigned » fago
Status: Needs review » Reviewed & tested by the community
+++ b/includes/rules.core.inc
@@ -394,25 +394,27 @@ abstract class RulesPlugin extends RulesExtendable {
-    if ($this->parent == $parent) {
+    if ($this->parent === $parent) {

unrelated change?

But otherwise I think this makes sense, we should definitively replace those hard-coded Action/Condition classes and interfaces. Marking as RTBC, but leaving for fago as he knows this one better than me.

fago’s picture

Status: Reviewed & tested by the community » Needs work

In RulesPlugin::setParent(), the existing parent is removed before the check for compatible containers. In the odd instance of setting the parent of an action to an incompatible container, if the RulesEvaluationException is actually caught, the existing parent is forcibly removed before the error check.

ouch. yep let's fix that, however the patch does much more than that.

+++ b/includes/rules.core.inc
@@ -394,25 +394,27 @@ abstract class RulesPlugin extends RulesExtendable {
-    if ($this->parent == $parent) {
+    if ($this->parent === $parent) {

As klausi said, unrelated. Also I don't think we should do that, as the UI might treat with some serialized and unserialized configs.

+++ b/includes/rules.core.inc
@@ -394,25 +394,27 @@ abstract class RulesPlugin extends RulesExtendable {
+    $pluginInfo = $this->pluginInfo();
+    if (empty($pluginInfo['embeddable'])) {
+      throw new RulesEvaluationException('This element cannot be embedded.', array(), $this, RulesLog::ERROR);
+    }

Embeddable is supposed to be an UI-helper-flag, whereas the API only limits embedding things to the interfaces.

Any reasons why we should change that?

fago’s picture

Okay the problem with using 'embeddable' is that RulesEventSet extends from RulesRuleSet and uses RulesRuleSet::rule() to add a rule, which adds it as an action, which in turns tries to call setParent().

Exactly, I doubt this would work. So why was that RTBC?

zhangtaihao’s picture

Comparing $this->parent == $parent causes two objects each with potential circular references to be compared for all attributes, causing a PHP recursive loop. Of course, I can create that as a separate issue.

What did you mean by "some serialized, some unserialized"?

zhangtaihao’s picture

Issue summary: View changes

Corrected name.

fago’s picture

Assigned: fago » Unassigned
Issue summary: View changes

Of course, I can create that as a separate issue.

Yes, please. As said I'm hesitate of doing so as I fear it might break the UI - see below.

What did you mean by "some serialized, some unserialized"?

During editing Rules in the UI configurations get serialized, while others get loaded. So one might end up having two different objects of the same configuration instantiated. I guess, taking the passed parent would be the right thing to do in any case - but it needs solid testing to make sure nothing breaks.