Hello everybody.
Sorry if I ask something obvious but digging through the rule docbook and the group did not help me much.
I miss a documentation that goes beyond the "GUI" part but explains the mecanics and meaning of parameters of the most complex actions like "load node", "fill a cck field" and such.
What I need to do :
I have a content profile with an embedded node-reference toward another content type instance.
When the user create its profile, I want to silently create a new node of that type and assign it to the node reference in its content profile.
(in my use case this content type is a "counter card" that record aggregated value of service usages for a Non Profit Organization, I made the decision to make this a separate content type because I want to be able to list those "cards" separately and be able to archive them yearly if needed, only the current one being available to the user through its profile. Think, UML aggregation here).
I am able to create a rule triggered at node profile creation, and then create a new instance of my "counter card" content type, but I am at a loss to figure out how to tie it to the reference field in the content profile who's creation triggered the rule.
I understood that I could name the newly create "counter card" in the create node rule and I did, but I can't figure how to use that information in the next action.
The "configuration argument" fieldset makes no sense to me(yet) and the "value" AJAX field of the "set CCK field value" action refuse tokens ....
Very frustrating ... very very ....
Second :
I need to hide on form creation the reference field from the profile form, but I suppose I can do that with the "form rules" module, hiding the field in that case. right ?
Third :
I need the ownership of the newly created "counter card" node to be the same that the user the profile is created FOR and it is neither the acting user nor the author I think, because admin users can create new users ....
Is there a solution to that ?
PS : I did find the "Autocreate Node Reference" module (http://drupal.org/node/371518) but I would like to understand rules logic first, maybe keep the number of modules used low and I think the module is a bit "hack-ish" . I am not sure WHEN the new node is created with this module, will rules apply to it also, what are the assigned rights and ownerships etc ....
PS 2 : I can dare write some php (in a module please, php in the database makes me shiver badly), or maybe a custom action if needed. If that is the case I would appreciate pointers on how to do that and what hook to use from an experienced developer, just a few pointers to avoid false starts.
Thanks a lot for your time.
Comments
Some help along the way
Hi and welcome to Rules! I hope you will find more rewards than frustration. :-)
Here is some help along the way:
-1-
Adding references to the profile node can be tricky. As you write, the normal CCK widget won't accept tokens.
The way to do this is to use PHP, which requires you to activate the PHP filter. Once activated, you'll get a form to write PHP code for the entry. You'll want something like this:
return array(0 => array('nid' => $new_node->nid),
);
(Where $new_node is the machine name for the node (counter card) you just created.)
Furthermore, you might have to save the new node in order to give it a nid. There is a Rules action for this available – and be sure to tick the box "immediate save", so the save won't wait until the end of all the actions.
-2-
Yep, you can hide the form by using Rules Forms Support. An alternative and more common approach would be a custom mini-module that implements hook_form_alter, but I can't really say which of these approaches that are best.
-3-
When creating the new node (counter card), you'll have to set which of all the available user objects should be used as author. The author of the profile node should be available (and must be the user the profile belongs to) – if not, run the action "load node author" to get it into rules.
-PS1-
I don't really know how Autocreate Node Reference module works. Sorry. :-/
-PS2-
The PHP code to get the proper node reference is more or less necessary in this case, and there's no good way of removing it from configuration. If you really want it in code, you can export the rule. (That would enable version control, but you'd of course still have PHP in your database.)
I don't really know how to build modules, but you'll only need an extreme minimum to implement the hook_form_alter mentioned above. The Examples project at d.o should give a sound start if you want to see examples of module code.
Good luck!
//Johan Falk, NodeOne, Sweden
Thanks a lot for the quick
Thanks a lot for the quick reply.
I'll experiment with this asap.
I just wonder what $new_node really is since my new "counter card" node is created by a an action in the ruleset fired by the "content profile" node creation.
that's where I miss the logic of rule (I know there is one but I don't get it for now).
When you say the machine name we are not talking about the type name (cck type name) witch make no sense here but the instance name right ?
But what is truly the name of an instance except is nid ? Or do you name "machine name" the name called "Machine readable variable name " I assigned in the previous action where I created the counter card node ?
That would make sense, I'll try that.
As for PhP, if it is the only way, then, but It is one of my grief with Drupal : that mixing of configuration, code and user data that makes any migration from development to production a HARD problem, and something completely artistic, human dependent and error prone.
that's another subject ;)
thanks a lot again for the very quick help.
Hello again! The actual name
Hello again!
The actual name of the $new_node variable is set when you create the new node – there are fields for setting the label and machine name for the new object. It should be visible in some PHP hint box on most action settings pages, along with any other available objects.
A general way of finding available variables is to use
<?phpdpm(get_defined_vars());
?>
I agree that mixing configuration and content is a problem – as do many other Drupal developers. Drupal is moving towards a more clean cut on data, but there are many problems that have to be thought through first – what is content on one site might be considered configuration on another, depending on how it is used. One of many ways to perhaps solve this is to use the Features module, which can create mini-modules from the configuration of quite a few modules (which effectively moves the configuration to code). Features is still far from perfect, though.
I colleague of mine is doing development on the Deploy module, which can do some really cool stuff when it comes to staging content.
Good luck!
//Johan Falk, NodeOne, Sweden
I'am still at it and one full
I'am still at it and one full week playing with many solution JUST to have an association between two node seems crazy, to the very least.
rant warning
In the end it should just resolve to
Object1->link=Object2.
Object1.isdirty or Object1.save
nothing more.
Obviously we are far from it.
For the record and people trying to achieve the same thing I also tried with hook_nodeapi() but it triggers very suspicious behavior where hook_nodeapi is triggered in an infinite loop with the wrong parameters, I tried to explain things here http://drupal.org/node/812484
Sorry for the rant, and thanks for trying to help, it is just that my love/hate relationship with drupal is more and more getting toward the hate side of things the more I know about its innards. Unfortunately that feeling is never productive.
end of rant zone
Anyway ;) So now I am back to try to use rules to have the behavior I need, because it SHOULD allow me to intervene AFTER the content profile creation witch should simplifies things a bit.
I have 3 steps when the proper "profile node" creation triggers
1) create a new scoreboard node AND assign it to a variable, let's say new_fcons_for_profile
2) save that newly created node (save action on that new_fcons_for_profile variable)
3) Create the valid node ref with php evaluation in a "assign field value action"
The thing is it seems that my variable defined at step 1, the " is "undefined" when I come to step 3.
I put a dpm(new_fcons_for_profile) on top of php to get that.
but then I have an error in my php logs telling me the "eval'd statement" as syntaxt error.
That led me to wonder : am I allowed to have multiple line statements in the code box ? I am afraid not. tremendous for debugging.
Second I wanted to put your suggested
dpm(get_defined_vars());in the code box to have it evaluated at the point where the code should be ran (to be sure I am in the same context) but the interface prevent me from doing that. I suspect some regexp is scanning the code to look for some "return" keyword. Hell is paved with good intentions. It surely won't prevent anybody to enter wrong or malicious code (once php eval pandora's box is open there is no way to do so) but it SURE make things painful for debugging.When I put a fixed nid in the statement like :
return array(0 => array('nid' =>65),
);
where 65 is the nid of a "scoreboard" node created beforehand, everything seems to work fine.
So the trouble is really with $new_fcons_for_profile at
return array(0 => array('nid' => $new_fcons_for_profile->nid),
);
but I am puzzled.
I wondered if I had to reload the node I just saved (because Drupal does not seem to have a concept of object identity, thus I can have two "nodes object" in code (in different objects) that map to the same "underlying node" in the database layer.
The trouble is I don't know how because if the handle (variable $new_fcons_for_profile) I have at step 2 is not valid after node save then how can I do that ?
I am a bit out of ideas there so any sound idea would be welcome.
In the meantime i'll try to have that
dpm(get_defined_vars());chunk evaluated where I want it despite to be that [insert whatever curse your prefer here] regex in the GUI.Thanks a lot for your time all.
PS : At the least I hope reading this was entertaining in a cynical way ;)
a bit more datas
I circumvented the control about the code box with a simple
return (dpm(get_defined_vars()));What appeared when I created a new profile node is dumped below.
What seems apparent is that the node contained in the variable
new_fcons_for_profiledoes NOT seem to have a nid even after the save step. The save Step (2) works because the node is in the database at the end of the rule execution (and the immediate save is checked by the way) but the referring variablenew_fcons_for_profiledoes not seem to be updated with the new state of the node and especially the nid.And since it does not have a nid I can't "reload" the node in an intermediary step because I have no real "handle" on it, the nid being the unique and only identifier on a node (or the vid but it does not apply there)....
Reminds me then those old timers forbade me to EVER have treatments in a database (trigger, stored procs, auto inc fields) because it introduce inconsistencies of state...
... (Array, 2 elements)
*
settings (Array, 4 elements)
o
field_name (String, 28 characters ) field_asprof_ref_fiche_conso
o
#argument map (Array, 1 element)
+
node (String, 4 characters ) node
o
value (Array, 1 element)
+
0 (Array, 1 element)
#
nid (String, 0 characters )
o
code (String, 36 characters ) return (dpm(get_defined_vars()));
[...]
+
new_fcons_for_profile (Object) rules_variable
#
name (String, 21 characters ) new_fcons_for_profile
#
info (Array, 6 elements)
*
label (String, 28 characters ) NouvelleFicheConsoPourProfil
*
label callback (Boolean) FALSE
*
type (String, 4 characters ) node
*
save (Boolean) TRUE
*
saved (Boolean) FALSE
*
handler (String, 0 characters )
#
data (Object) rules_data_type_node
*
_data (Object) stdClass
o
type (String, 24 characters ) fiche_consommation_ascas
o
status (Boolean) FALSE
o
promote (Boolean) FALSE
o
sticky (Boolean) FALSE
o
uid (String, 1 characters ) 1
o
created (Integer) 1275149654
o
revision (Boolean) TRUE
o
comment (String, 1 characters ) 0
o
menu (Array, 12 elements)
+
[...]
o
name (String, 5 characters ) admin
o
title (String, 25 characters ) Fiche Conso ASCAS : admin
*
_info (Array, 5 elements)
o
label (String, 7 characters ) contenu
o
class (String, 20 characters ) rules_data_type_node
o
savable (Boolean) TRUE
o
identifiable (Boolean) TRUE
o
module (String, 4 characters ) Node
*
type (String, 4 characters ) node
#
_state (Array, 3 elements)
*
(Recursion)
#
_changed (Boolean) TRUE
Immediate save
I've had some trouble with missing NIDs myself. If you add a "save node" action and check the "immediate save" checkbox, it will get a nid. That helps, a lot.
Good luck,
//Johan Falk
Reporting success by another trick that may be helpful
After fighting a lot I was not able to make this work.
The node seems to get a nid but the "rule variable" seems not to have a hold on the saved node and so not get the nid. It stay in its unsaved state basically.
Hence I kept having php error in my logs because the
$new_fcons_for_profile->nidwas substituted with something wrong, probably blank and rendered the php invalid.I had to understand than the php code is not "php" passed to eval but a bit or a lot massaged by the rule module, something I find way to heavy handed as explained above. for instance It checks you have only a "return statement" which prevent all kind of debugging and severely restrict the logic you can put in the php.
On the other hand It took me time to figure than the TOKENS are available and substituted in the "php", something not completely natural for php code and absolutely not stated in the page.
So I spend lots of time wondering what was the use of the Tokens since I were not allowed to used them in the auto-complete fields (a place where it would have made sense), until I figured I could use them in the "php" box.
To achieve my goal I had to trick the engine with another module "node backreference module " http://drupal.org/project/backreference.
I configured the module in the CCK page of both types to have fields pointing to one another (to the profile from the "scorecard" type and back), and linked them up in "node backreference". Then since I create the "scorecard" in the rule, it does not have a nid has stated above but the profile has one, since the rule is activated "upon/after save", thus I can assign the profile to the new scorecard proper field and the module create the reverses link from the scorecard to the profile. I basically do the reverse of what I intended duplicating information a bit, but in my case having both link makes sense, even if I would love to not duplicated information, something that may bite me down the road.
I suppose the backreference module is able to do that because it is triggered after the "scorecard save" action when I assign the fields and fetch its own view of the "scorecard" node thus getting a nid.
These inconsistencies and out-of-sync multiple views on a node are a plague of drupal and a serious blow to reliability and integrity. And a huge waste of time for things that should be simple.
Since it is core to Drupal way of doing things I don't expect it changing soon, but maybe the rule module should reload the data of the node after saving it, to ensure it has up to date things. I say reload the member data, not the node, or we'll have again another inconsistent copy of the same node in memory and some variable pointing to the old one, etc ...
I understand it is a though problem though.
I hope this trick will help people that need to have 1-1 relationship automatically created.
I will also pursue the issue of how to do that programatically since it should be more efficient than with rules and much more portable through staging.
I am pursuing the issue with some kind folks here http://drupal.org/node/812484 in case we achieve something
Ho ! and rules miss a condition that knows how to check a field (being base or CCK) is NULL, would make rule much clearer and support the case of cck3 multiple fields being empty or not. ;)
Thanks a lot for your help itangalo
An example now posted
Seems like a lot of frustration… My sympathies.
I made an example of how to make the create-and-reference workflow work – it can be read, downloaded and tried at the Rules documentation pages: http://drupal.org/node/820938
I hope it might be of help in the future. (It seems you've found a solution that works for now.)
Cheers,
//Johan Falk, NodeOne, Sweden