Note: this issue is a summary of a private email chain between several developers, apologies if any details are left out.
Many modules (such as mailcomment/mailhandler) use comment_save to insert comments directly, without going through FAPI. These modules may also make changes to a parent node in direct relation to the comment (see #813356: Expanded support for mailcomment attachments). No general mechanism exists to deal with such comments. It has been suggested that modules such as mailcomment either specifically code in support for comment_driven, or that comment_driven implement some mechanism (such as hook_comment) so that ALL new comments can be intercepted, not just those going through FAPI.
The attached patch implements the latter approach and is a proof-of-concept (not for production!). In a nutshell, it implements hook_comment and ONLY acts on comments that have bypassed FAPI (and thus comment_driven). It simply looks at any changes that have occurred to the node since the most recent revision tagged by comment_driven, and associates those changes with the comment. It requires whatever module generated the comment (in this case mailcomment) to make the changes to the node in a new revision.
| Comment | File | Size | Author |
|---|---|---|---|
| #25 | comment_driven-825304-25.patch | 2.55 KB | danepowell |
| #15 | comment_driven-825304-15.patch | 1.81 KB | danepowell |
| #8 | comment_driven-825304-8.patch | 1.01 KB | danepowell |
| comment_driven_insert.patch | 2.6 KB | danepowell |
Comments
Comment #1
danepowell commentedHere are comments from arhak and my responses:
I don't understand how that's the case really... if I'm not mistaken, it seems to simply hook into the comment editing form, pass the results to driven, save the changes to comment_driven_log, and then load the changes with comments when they are displayed. Let me know if I'm missing something.
Cool, not a blocking issue.
If we simply compare the "current" node revision to the most recent (by timestamp, not by vid), wouldn't that all but guarantee that only changes that occurred coincident with the comment actually get associated with it?
Hrm? I don't see how this represents any significant performance impact at all...
Okay, we'll make this user-configurable and only allow it to be enabled if comment_driven is enabled.
I could see spinning this off into a separate module, however it's such a tiny amount of code that I don't know if it'd make sense. I do think it would make sense to at least distribute and maintain it with the comment_driven package.
That's a failing of Drupal revisions, not of this module or this patch :) If another module is bypassing FAPI and absolutely needs support for these properties, we are not stopping them from specifically coding support for comment_driven. Also, this problem isn't one that I've given much thought too; there might still be some way to crack it.
Comment #2
arhak commented1-
IMO you're missing something, but I haven't explained that part yet, that is what needs time to be written down (we'll get there)
2- it is a minor "bug" of this patch, but somehow related to point 3
3- you will react to comments not posted through FAPI that are NOT intended to introduce any difference, (a little harder to obtain that point 2 above) but the same as cross posting occur and locking framework is needed in some cases, this point might be reached once a node edition has happened with a sufficient timestamp to be wrongly identified as intended to be a diff introduced by the comment when it wasn't (in short, it is not robust, but dirty)
4- you're querying and sorting, when there is no need to seek what at some point you knew already
pass the info through, don't go hunt what you had at hand
5- not a blocker issue, agreed
6- not a blocker issue
7-
comment_driven supports them already, but it just can't do it when working with vids
but it can if you pass the actual nodes (before vs after) instead of node_load-ing revision ids
that's why I would prefer to use its full potential over a limited version
Comment #3
arhak commentedBTW, this issue is related to #741274: Using comment driven programmatically
and a part of the e-mail thread that is missing is how to provide more support than that
and how/why you got to this proof-of-concept
PS: once I explain the point 1 (mentioned above) I will suggest another proof of concept that I would feel more comfortable
Comment #4
obrienmd commentedSubscribing.
Comment #5
obrienmd commentedArhak, any chance to write up your further explanation of point 1?
Comment #6
arhak commentedwhy is comment_driven more close to be a node-related module than a comment-related one?
first of all it relies on Driven API, which addresses only nodes
secondly its main goal is to maximize compatibility with node-related module (at the expense of the compatibility with some comment-related modules that might come up unsupported)
approach: what really happens when comment_driven gets in, is that a comment_form stops being an actual comment_form and it is replaced with a node_form for node edition.
it becomes then a node edition page with a comment_form attached to it, which is almost what revision log textarea would provide if it would work as a threaded history (the only reason to not use revision logs instead is that there are a lot of comment-related modules that are already bringing new features to comment forms and are perfectly compatible with comment_driven, which otherwise would have to duplicate their features to bring them to node's revision logs)
Driven API works with two nodes (not comments at all), and comment_driven seek to handle a node edition and a comment insertion at once
attempting to react on hook_comment makes necessary to determine which would be the two node's snapshots to use, which can be node objects, revisions, or submitted data (a $node_form & its $form_state['values']), resulting in either:
- a performance waste determining which revisions ids to use (IMO the worst approach)
- passing through two nodes (or revision ids)
- working with revisions (instead of actual nodes or submitted data) brings the limitation for properties which don't support revision
last, but not least: inventing a driven diff violates the principle of comment_driven to reflect the changes that were introduced at commenting time, (which actually is a comment being inserted at node edition time), having them apart and then bundling them together might result in a coarse fake
proposal: instead of telling comment_driven whether NOT to react (with the proposed flag to detect whether a form was actually submitted or not) it can be handled in hook_nodeapi, at the time a node its being edited (node_save) we have the two instants we need:
pre-insertandinsert, onpre-inserttime we have the node about to be changed, and oninserttime we have it again but already savedif we also receive a cid (especially flagged to tell comment_driven to react) it would be (IMO) much better:
- NO performance penalty to determine the two node's snapshots neither the comment to bound
- telling comment_driven to react would be as simple as passing a cid (special flag) and then comment_driven_nodeapi would take care of preserving the node_before on
pre-insertto make sure it will be available for comparison (against node_after) atinserttime- it wouldn't be working with revisions, and therefore there would be NO limitation for those properties that don't support revisions
PS: I would like to submit this patch, but right now I don't have the time to spare on it.
however, I'll do my best in reviewing proposed patches, and providing more info if needed (so far it seems to me that I accomplished easing Dane's work with the info I previously provided through mails, so IMHO the hook_nodeapi proposal shouldn't be taken lightly)
Comment #7
danepowell commentedThanks for your detailed reply arhak, I believe I fully understand what you are proposing now- I will take a crack at implementing hook_nodeapi and see what I can do.
Comment #8
danepowell commentedOkay, here is a patch that implements hook_nodeapi. If a module wishes to add support for comment_driven, then when it saves a node it simply needs to add the parameter
$node->associated_cidindicating which comment is associated with changes to the node. Please let me know what you think.Again, this is part of a larger effort to get Mailhandler/Mailsave/Mailcomment/Comment Driven to play nicely together as part of a unified workflow with attachments and Driven-based tracking. The associated issues in other queues are #855312: Pass full node to implementations of hook_mailhandler_post_save and #813356: Expanded support for mailcomment attachments.
Comment #9
arhak commentedis this working as expected?
it seems to me that the $op is
pre-insert(instead of "preinsert")and since all the processing is taking place on the same $op
$changes must be empty (almost) every time
the proposal at #6 talks about reacting on two $op:
re-insertandinsertdid you choose your own way or did you miss it?
Comment #10
danepowell commentedIt is working as expected in my test environment.
There is no "pre-insert" op that I'm aware of, just insert. And anyway, we are not reacting to node inserts, we are reacting to node updates, for which the relevant ops are "presave" and "update". See hook_nodeapi.
Maybe I did something slightly different from what you envisioned - I take the version that's about to be saved (passed as a parameter to hook_nodeapi) and compare it to the current version (from node_load). Do you see something wrong with that?
Comment #11
arhak commentedsorry, my bad
yes
presaveit is, and afterwardsinsert/updateso, $node is meant to be node_after and compared against $node_before from node_load
then two remarks:
- some comments would come handy, because it relies on no other module modifying the $node on
presave, which is unlikely due to the enormous weight of cdriven (but should be said IMO)- insertion code should be common (placed in one place to be reused)
Comment #12
danepowell commentedWould it be better to have a low-level insert function like...
or a higher-level function that takes a
$node_before,$node_after, and$cidand inserts a log entry like above?Or both? :)
Comment #13
arhak commentedlow-level
what if the high-level version receives node_before/after that haven't been saved, and therefore have no vid yet?
PS: I'm running out the door right now, that was from the top of my head (which is not very accurate)
Comment #14
arhak commentedon
presave$node->vidis equal to$node_before->vidright?
you'll have to wait until
insert/updateto get the propervidonce the revision have been savedComment #15
danepowell commentedHere is a patch with some improvements made. We must first act on presave to load the latest revision of the node and compare it to the new node, generate the changes, and attach them to the node object. Then we have to wait until update to get the new vid and actually insert the cdriven log.
Comment #16
arhak commentedyes, otherwise there won't be a chance to have it back
well, if you're forced to act in two times then comparison doesn't "have to be" in the first phase
you can attach the $node_before instead, and do the comparison in the second phase
yes, if we want the proper revision id (when revisions are enabled)
then we have to wait for the second phase
question
do we only care about
update?won't the
associated_cidwork forinsert? (I mean for other modules attempting to get advantage of this improvement but not onupdate)BTW using
driven_inspect_diff_nodesimplies a new dependency(which I don't like that much, I would prefer some kind of
module_existsconditional)Comment #17
danepowell commentedThat's true- it would mean attaching more data (mostly redundant), not that that really makes a difference though. Do you think attaching $node_before instead of $changes is better, or vice versa?
Is there any case you can imagine where a comment would be created simultaneously with a new node creation and need to be logged by cdriven?
That's true, I actually added that but forgot to include it in the patch. I guess options include adding the dependency as mentioned (I understand why you don't like this), adding a module_exists conditional (I don't really like this on principal, and it might be confusing for people expecting this to work out-of-the-box), or making this functionality a sub-module of cdriven with the appropriate dependencies (I like this idea, since the functionality and methodology are really completely different from the rest of cdriven)
Comment #18
arhak commentedit was just a comment, but giving it a second thought, I prefer the comparison in advance (1st phase)
updatewhich is not the usual approach of cdriven when inserting via FAPIout of the blue cdriven needed it when operating via FAPI,
in addition, read the titles of these issues:
#741274: Using comment driven programmatically
#825304: Support comments not inserted via FAPI
so, I guess yes, we should care
I guess we agree on why we don't like the first ones (pros and cons), and also why a third module might come handy, just it feels wrong having an extra module for such small code and out of cdriven
... lets not make a big deal of it
make it your call
Comment #19
danepowell commentedSorry, I guess I'm still not clear on what advantage trying to act on node inserts/creation (not just updates/edits) would offer. I don't know how or why you would create a new node and simultaneously create a comment, and what exactly cdriven would log in that case - you've just created the node, what "change" is cdriven supposed to capture?
Or are you proposing something else?
Comment #20
arhak commentedoh, please forgive me, I was talking nonsense
Comment #21
danepowell commentedNo worries, it happens to the best of us... I've had my fair share of head-desk moments on this project.
Comment #22
danepowell commentedJust to keep everyone on the same page, the patch in #15 is the latest and should work- it requires comment driven inspect to be enabled. We/I still need to decide how to handle that dependency- I'm leaning toward rolling a submodule of cdriven at this point.
Comment #23
danepowell commentedTagging to keep track of issues related to the mailhandler-2.x/notifications-4.x workflow
Comment #24
obrienmd commentedarhak, can this (#15) be committed? I have CVS commit access, and will do so if you approve.
Comment #25
danepowell commentedAh taking another look at this I see that arhak was wanting roll this functionality into a submodule. Here's a revised patch with that in mind- note that I haven't had time to test it, but it's substantially the same code as #15. Note that it creates two new files as part of a "Comment Driven NodeAPI" submodule.
Comment #26
danepowell commentedYes, patch #25 does work. Let's commit it!
Comment #27
obrienmd commentedI have tested #25 as well, looks to be working great!
Comment #28
arhak commentedDane & Obrien, you are the reviewers of this patch,
the commit call is yours
PS: the sub-module is good for now, after a rewrite it should be most likely within the main module
Comment #29
obrienmd commentedDane - Given your recent work w/ driven, are you comfortable w/ the state this patch is in? If so, I'll commit it.
Comment #30
arhak commented@#29 Dane has commit access, he can do it
Comment #31
danepowell commentedI am comfortable with it, I just haven't had time to commit it yet (been working on the other issues). Feel free to commit it or I'll get around to it shortly (probably tomorrow).
Comment #32
danepowell commentedSneaking this one in under the wire so to speak :) Committed #25 to HEAD (which I assume is 6.x-1.x).
Comment #33
danepowell commentedIn the spirit of developing good habits, here's a link to the commit message...
http://drupal.org/cvs?commit=504718