I have successfully started using Triggered Rules. Most of my actions involve using "Execute custom PHP code".
Now that I've got things up & running I'd like to move these custom php actions into a custom module.
I'm having trouble!
For example an existing rule (simplified from my real use case) looks like this:
Event:
- After saving new content (conditional on type)
Actions:
- Load a CCK referenced node
- Custom php (for example):
$referenced_node->field_counter['0']['value']++;
// increment simple counter in referenced node- Save the referenced node
This works great. And is easy using the "Execute custom PHP code" action as the loaded referenced node is available to me as $referenced_node.
Now I want to make a custom module.
- Can I simply use my custom action in place of the "Execute custom PHP code" action in my existing triggered rule?
- In other words can I still use the Rules actions that load and save the referenced node?
- If so, how do I then pass that referenced node into my custom action function to make changes to it?
- Or do I have to load and save the referenced node within my custom action?
my skeleton mymodule.rules.inc looks like this:
/**
* Implementation of hook_rules_action_info().
*/
function mymodule_rules_action_info() {
return array(
'mymodule_action_update_counter' => array(
'label' => t('Update Counter'),
'module' => 'MyModule',
),
);
}
/**
* Action:
*/
function mymodule_action_update_counter() {
$referenced_node->field_counter['0']['value']++;
}Any help greatly appreciated.
Thanks!
Comments
Copy from examples
Hi and welcome to the Rules world!
I have three tips to share:
1) There is quite good coder documentation for Rules available at http://drupal.org/node/298522. It has helped me a lot.
2) There is a module Rules Bonus Pack that could do what you want. It has an action for summing up numbers, including tokens, and returning the sum as a new number object in Rules. That could then be used to set the value on your field with tokens.
3) In the Rules Bonus Pack you could probably find more code to copy and tweak – there are a few actions setting field values.
Good luck!
//Johan Falk
**
Learn Drupal with Nodeone! Drupal 7 introduction | The Views module | Learn Page manager! | Drupal configuration learning curve | Rules for Drupal 6 | Theming Drupal 6 | 49 Drupal 6 modules you should know
Thanks Johan, I can see in
Thanks Johan,
I can see in your Bonus Pack that you are passing $settings and or $form to your action functions.
My actions don't have any form configuration. They basically run db_query using, for example, the nid from the node or a referenced node; perform some calculation/s and then update fields in the node or referenced nodes.
The bit I'm struggling on in moving this into a custom module is how to pass the referenced node/s into my actions function. Does $settings do this?
Thanks for any more help. Thanks also for your Rules videos! I've watched the whole set - they just finish short of explaining moving an action off into a custom module ;-)
Wow - this is tricky!! I've
Wow - this is tricky!!
I've managed to write a custom action, and load referenced node, update & then when I save I get:
warning: mysqli_real_escape_string() expects parameter 2 to be string, array given in /includes/database.mysqli.inc on line 330.I've tried returning the node to Rules for smart or forced saving and I've also tried doing the loading and saving of the node within my custom action. Both approaches give me the same error.
Any thoughts?
This is a stripped bare version with load & save within the action:
<?php
function my_rules_action_info() {
return array(
'my_action_update_appeal_totals' => array(
'label' => t('Update Appeal with Prediction Count'),
'arguments' => array(
'prediction_node' => array('type' => 'node', 'label' => t('Prediction')),
),
'module' => 'my',
),
);
}
function my_action_update_appeal_totals($prediction_node) {
$appeal = $prediction_node->field_prediction_time_appeal['0']['nid'];
$appeal = node_load($appeal);
$appeal->field_appeal_predict_count['0']['value']++;
$appeal = node_submit($appeal);
node_save ($appeal);
}
In this version, I used rules to load the referenced node and then save then referenced node:
<?php
function my_rules_action_info() {
return array(
'my_action_update_appeal_totals' => array(
'label' => t('Update Appeal with Prediction Count'),
'arguments' => array(
'prediction_node' => array('type' => 'node', 'label' => t('Prediction')),
'referenced_appeal_node' => array('type' => 'node', 'label' => t('Referenced Appeal')), //'save' => TRUE),
),
'module' => 'my',
),
);
}
function my_action_update_appeal_totals($prediction_node, $referenced_appeal_node) {
$referenced_appeal_node->field_appeal_predict_count['0']['value']++;
return array('referenced_appeal_node' => $referenced_appeal_node);
}
This still works perfectly if I use the Rules built in action "Execute custom PHP code". In this case I use a rules action to load the referenced node; then I execute custom php code ($referenced_appeal_node->field_appeal_predict_count['0']['value']++;) ; then I use a rules action to save the referenced node.
Am I doing something very basic wrong?
I'd really like to be able to write my own custom actions.
Thanks for any help,
Andy
how i dit it
just yesterday i was trying to solve this.
with rules you can follow here
http://nodeone.se/blogg/johan-falk/make-rules-dance-with-views-bulk-oper...
and with views bulk operations in here
http://drupal.org/node/1153916
i hope it helps to you :)
@candelas - thanks for your
@candelas - thanks for your links!
I've seen Johan's very good videos @nodeone on rules & VBO but what I'm trying to do here is learn how to write a custom action.
I can do this easily as a rules "Execute custom PHP code" action with just the single line:
$referenced_appeal_node->field_appeal_predict_count['0']['value']++;But I MUST learn how to do this in a custom module as I don't want to store php in the db. Plus my final use cases are more complex and I want the code controlled in a module.
There must be something wrong with my custom action code :-(
Missing language code?
Looks like you're missing a language code when referring to your field. Not sure how/if that would impact it, but try using
<?php$referenced_appeal_node->field_appeal_predict_count[LANGUAGE_NONE][0]['value']
?>
@makononov I should have said
@makononov
I should have said I'm using Drupal 6 - I think [LANGUAGE_NONE] is for 7.
Anyhow my field references are working fine and in my full code I'm checking with dsm() on the various nodes to make sure I have the correct node and that the field updates correctly.
So my node_load() runs OK.
Then my counter increments OK. (within the Rules action)
But the node_save() fails with the described error.
Or if I just return an array containing the updated node to Rules and use the Rules Save a Content action, it also fails with the same error.
This is the first time I've tried to write a custom action so I guess my method is wrong. I've tried quite a few variations and I'm stumped!
Any other ideas?
Thanks for any advice
You must declare all action variables
Rules will automatically save the objects returned by actions, if they are savable -- you don't have to run the 'save node' action manually.
What you DO have to do, which you also do, is return the variables that should be saved from the action working with them. For this to work, Rules must be aware of which variables it should be prepared to save, which you also well in hook_rules_action_info().
My guess at what's going awry here is that the ++ operator doesn't work very well with the deep nested array. Try something like this instead:
<?phpfunction my_action_update_appeal_totals($prediction_node, $referenced_appeal_node, $settings) {
$new_value = $referenced_appeal_node->field_appeal_predict_count['0']['value'] + 1;
$referenced_appeal_node->field_appeal_predict_count['0']['value'] = $new_value;
return array(
'referenced_appeal_node' => $referenced_appeal_node,
);
}
?>
I hope this may help. Good luck!
//Johan Falk
I'm a part of the Rules Issue Squad, helping out in the issue queue. You can join, too!
Also!
Oh, when you change the arguments for an action, you will most likely have to remove any configured actions of that kind and re-add them. Their settings are stored separately and not re-read just because the action has changed structure.
OK - Fantastic - I'm up and
OK - Fantastic - I'm up and running now :-)
My preferred route was to let Rules load & save nodes and referenced nodes and for me to just to supply code to perform calculations & add new values in my custom action. My experiment using node_load() and node_save() were experiments as I tried to get to grips with the correct way to pass referenced nodes as arguments into a custom action.
Unfortunately I think my multiple experiments were what was causing my problems & my inability to debug the cause.
The key step here as you mention is that it seems the only way to cleanly test a change to custom actions is to remove and then re-add them - otherwise expect unexpected behaviour!
BTW now I am confident that the changes I've made are actually the ones I'm testing (as the rules have been completing removed and replaced), I've checked that the ++ operator works fine as it keeps my action simpler.
OK - step 1 done. I know how to write an action.
Next - I have a whole bunch to write & organise into sets.
Thanks Johan and everyone for your help!
Just to add: I found that I
Just to add:
I found that I did NOT need to add a Rules action of "Save a Content" after my custom action as it seems that Rules automatically saves the changed node returned by the custom action.
This last week I've worked a
This last week I've worked a lot with the Rules module.
I've progressed through writing custom php actions onto having my custom actions in separate rules.inc files and my rules exported into separate rules_default.inc files.
Today, I've started looking at hook_nodeapi() & I'm starting to wonder if I wouldn't be better to drop Rules just write a custom module instead.
Pros and cons?
Some thoughts
Yes, hook_nodeapi() is definately an option. I see it like this:
I hope this can help!
//Johan Falk
**
Learn Drupal with Nodeone! Drupal 7 introduction | The Views module | Learn Page manager! | Drupal configuration learning curve | Rules for Drupal 6 | Theming Drupal 6 | 49 Drupal 6 modules you should know
Thanks Johan, So for this
Thanks Johan,
So for this project I'm sticking with Rules for now. But I may move to total custom module in a future refactor.
I think another advantage for Rules for me at the moment as I try to learn Drupal is that it's a simple way to keep my actions quite distinct and separate. I think this may be important as I start to learn where any performance bottlenecks are in my system (which has some interesting workflows). For example at the moment, I'm triggering multiple actions from a single Save Content of Type event. Actions include, writing to cck fields, page redirection, changing user roles, publishing/unpublishing nodes and building and mailing custom emails to lists of users and all of this built upon logic which includes running db queries & loading nodes or user objects. I'm thinking, for example, that using 'Rules Debug Rule Evaluation' that I might experiment with moving some actions to different events or cron.
It looks to me that Rules is really ideal if you want to provide some new custom events, conditions, actions but then allow your users to build or configure a system that may use them in different ways. I am building a very specific application with workflows that are not configurable by users/admins so if I were a more experienced developer, I would probably have gone straight to writing a custom module.
Thanks for all your input as I learn Drupal,
Andy