On an empty site, when I fill in an Article form with a new term in the Tags field, press Preview, then press Preview again, I get:
* Notice: Undefined index: taxonomy_term in taxonomy_field_formatter_view() (line 1227 of /Users/bjaspan/drupal/head/modules/taxonomy/taxonomy.module).
* Notice: Trying to get property of non-object in entity_extract_ids() (line 6452 of /Users/bjaspan/drupal/head/includes/common.inc).
* Notice: Trying to get property of non-object in taxonomy_term_uri() (line 138 of /Users/bjaspan/drupal/head/modules/taxonomy/taxonomy.module).
* Notice: Trying to get property of non-object in taxonomy_field_formatter_view() (line 1231 of /Users/bjaspan/drupal/head/modules/taxonomy/taxonomy.module).
* Notice: Undefined index: taxonomy_term in rdf_field_attach_view_alter() (line 730 of /Users/bjaspan/drupal/head/modules/rdf/rdf.module).
* Notice: Undefined index: taxonomy_term in taxonomy_field_formatter_view() (line 1227 of /Users/bjaspan/drupal/head/modules/taxonomy/taxonomy.module).
* Notice: Trying to get property of non-object in entity_extract_ids() (line 6452 of /Users/bjaspan/drupal/head/includes/common.inc).
* Notice: Trying to get property of non-object in taxonomy_term_uri() (line 138 of /Users/bjaspan/drupal/head/modules/taxonomy/taxonomy.module).
* Notice: Trying to get property of non-object in taxonomy_field_formatter_view() (line 1231 of /Users/bjaspan/drupal/head/modules/taxonomy/taxonomy.module).
* Notice: Undefined index: taxonomy_term in rdf_field_attach_view_alter() (line 730 of /Users/bjaspan/drupal/head/modules/rdf/rdf.module).
| Comment | File | Size | Author |
|---|---|---|---|
| #55 | 844388-clone-node.patch | 835 bytes | james.williams |
| #48 | 844388.patch | 3.43 KB | lotyrin |
| #46 | 844388 (1).patch | 3.43 KB | lotyrin |
| #44 | 844388.patch | 3.46 KB | lotyrin |
| #32 | 844388-preview-clone-field-prepare-docs.patch | 3.71 KB | lotyrin |
Comments
Comment #1
lotyrin commentedI've reproduced this on my CVS copy, going to try to figure it out. subscribing.
Comment #2
lotyrin commentedIt doesn't have to be a new term or a new article. Reproducible by editing or creating any Article, with any tags, clicking preview, then clicking preview again without saving.
Comment #3
lotyrin commentedDid some more testing, it's any node with any taxo references. Also, the terms don't appear in the preview display of the node.
Reflecting this in title.
Comment #4
effulgentsia commentedThis bug is probably a side-effect introduced by #735800: node form triggers form level submit functions on button level submits, without validation. In that issue, we made the entity editing workflow preserve the same entity across the multi-step process, so after each "preview" click, you still have the same object in $form_state['node']. However, field_attach_prepare_view() only calls the field's hook_field_formatter_prepare_view() once per entity, so taxonomy_field_formatter_prepare_view() isn't called on the second "preview". But that's the function that adds 'taxonomy_term' to $item, and because the second "preview" click resets $items to what was submitted by the form during field_attach_submit(), the lack of taxonomy_field_formatter_prepare_view() running is causing the bug.
I suspect the solution is for
$entity->_field_view_preparedto be cleared somewhere in the #builder_function pipeline, but I'm not sure where yet.Since I think this is a generic entity/field system issue that is simply surfacing for taxonomy, I'm changing the issue component accordingly.
Comment #5
effulgentsia commentedObviously, now that we've uncovered this bug, we'll need to add tests.
Comment #6
lotyrin commentedAs mentioned in #4, the entity editing workflow preserves the same copy of our entity across the multi-step process due to changes in #735800: node form triggers form level submit functions on button level submits, without validation.
The culprit in this specific instance is that _field_view_prepared gets set during preview, but allowing node_preview to alter our $node may have other unforeseen side-effects since node_preview makes a lot of operations on the node passed to it. It used to isolate some changes (the theme call) by creating a clone. It was only creating a clone before calling the theme function, however.
This patch creates a clone of the $node passed to node_preview at the beginning of that function which is the only $node any operations are performed on during the function call.
Tests are up next, but I want opinions on this solution.
Comment #7
effulgentsia commentedRe-evaluating where we clone $node within node_preview() may have its own merits worth exploring in another issue, but I think this issue isn't just for nodes. Fields can be added to comments, users, and other entity types, so I think the solution to this issue belongs inside the Field API. How about this?
Comment #8
lotyrin commentedAgreed. A solution inside the Field API is better.
I've moved my patch into a new issue #844502: Calling node_preview modifies the previewed node.
Comment #9
chx commentedIt's a nice piece but it needs tests.
Comment #10
bjaspan commentedRe-reading #661494: direct calls to node_view() do not trigger f_a_prepare_view() I must say I am not a big fan of the $entity->_field_view_prepared flag and would have argued against it had I been paying attention to field issues at that time. :-) My objection back in December would have been: We specifically designed the Field API to have consistent semantics regardless of the order or number of times you called various functions (i.e. no magic internal caches unless the API maintains them perfectly on its own). _field_view_prepared is nothing more than an invisible static cache enforcing page-load assumptions on the Field API: you can only call field_attach_prepare_view() once before calling field_attach_view() unless you know to clear this magic internal flag. The problem is that this approach it will break API uses cases that for whatever reason do not use the Field API that way.
I understand the logic behind why it went in, but I wonder if there were not other ways to solve the problem, e.g. by making field_attach_view() a multi-entity operation so it could call the multi-entity hook_field_attach_prepare_view() itself. It is too late to make that change for D7 in any case.
With that background in mind, my comments on the patch in #7 are:
1. I don't see why field_attach_submit() is the correct place to clear the flag. That just ties Field API's behavior even more tightly to form/page load semantics.
2. In the specific case of this bug, the node *is* being viewed, twice in fact (teaser and full), by preview. So why isn't field_attach_view() clearing the flag as it is supposed to? I'm tempted to say: Because preview clones the node before previewing it. But preview then views the node it cloned, so the flag should be cleared. This makes me think that node preview is first calling field_attach_prepare_view() and *then* cloning the node, so the flag is set on one object and cleared on another object. And aha! Now that I read #6 carefully, I see that is exactly what lotyrin is talking about.
So, my summary take on this bug:
1. $entity->_field_view_prepared was probably a mistake but we can't remove it without changing D7 APIs that cannot change at this point.
2. As a result, field_attach_prepare_view() and field_attach_view() are not truly two separate API calls. You must call the latter on all the entities on which you called the former, or you might leave the entities in an "undefined state." The API docs must be updated to reflect this.
3. As a result of #2, node.module is broken and something like #6 is probably the right patch. We will need similar patches for all other callers of these functions.
Arguably what I'm suggesting is in fact an API change, because we are changing the publicly defined semantics of functions. But that change occurred last December, and this change is simply fixing a bug in that patch.
Comment #11
sunField API maintainer recommends an API change.
Comment #12
yched commentedI'm not a big fan of _field_view_prepared either, of course. We went that road for lack of a better solution. I fully agree that the ideal solution is the one Barry points (make field_attach_view() a multi-entity operation so that it takes care of calling field_attach_prepare_view() itself). Even back then, it was a daunting change.
I'd tend to agree with Barry's analysis and see the solution in the range of #6.
Althgough : theme_node_preview() currently also clones the node. so if we go with #6, we should probably remove that one.
(hm, looking at the code in node_preview(), I cannot make sense of the
line. It possibly made sense before the changes to entity persistency in multi-step forms, but now, I'm not sure what it stands for. Sadly, no time to investigate right now)
Comment #13
bjaspan commentedre #11: I don't really recommend an API change. I recommend documenting the semantics of the API we have based on a change made in December.
re #12: I saw the same line in node_preview() and have exactly the same question as yched: Why is node_preview() calling _field_invoke_multiple() separately? It should not, and if it has to, that is a problem we should fix. Unless someone jumps up with the answer we should open a separate issue for it.
Comment #14
bjaspan commentedMy proposed Field API patch is attached. It is nothing but a documentation change. Actually the docs already suggested the required behavior we've discussed here; my patch merely makes it more explicit. Probably this no longer needs to be critical, but it is also trivial, so no harm in making sure it gets fixed.
Assuming my interpretation (and this patch) are correct, then #844502: Calling node_preview modifies the previewed node. should be upgraded to critical for the same reason this one was.
Comment #15
sunThe third person form is actually correct. So we either fix "Prepares" accordingly or we just leave both summaries alone.
37 critical left. Go review some!
Comment #16
bjaspan commentedRefusing to bikeshed. :-)
Comment #17
yched commentedLooks good to me.
Comment #18
sunComment #19
effulgentsia commented#16 is excellent. Let's now fix node_preview() to comply and add tests for the originally reported problem.
Comment #20
effulgentsia commentedWait a sec! I'm interpreting this to mean: "it is wrong to call f_a_prepare_view() twice for the same entity before calling f_a_view() for that entity". But isn't that the whole reason we have the _field_view_prepared flag? So that the same entity can appear in multiple sets, and each set can be "prepared" before any of the sets is viewed? If we follow the new documentation to the letter, why have the flag at all?
From #10:
Even if we were to follow the new docs, isn't the following sequence still possible?
- f_a_prepare_view()
- f_a_submit()
- f_a_view()
If we fix node_preview() to clone in a sane way, we probably won't encounter that sequence any more, but nothing in the Field API, even with the #16 docs, tells me that sequence is wrong. But that is the sequence that causes this issue's bug, because f_a_submit() overwrites whatever f_a_prepare_view() did with $items without also clearing the _field_view_prepared flag, and that leaves $entity in an inconsistent state.
Comment #21
bjaspan commentedFYI, I created #846356: node_preview() calls _field_invoke_multiple(). Now I'm thinking about Alex's comment...
Comment #22
catchNot really... the prepare view steps run based on formatters, which can differ depending on the view mode. The main reason for the prepared flag is that http://api.drupal.org/api/function/node_build_content/7 and http://api.drupal.org/api/function/node_view_multiple/7 both call those functions, but node_view_multiple() also calls node_build_content() via node_view() - so there has to be a way to stop those running twice.
Comment #23
bjaspan commentedAlex and I (and others) discussed this over lunch today and agreed that the problem with the current patch is merely one of wording in the new comment. We all agree that prepare_view() is unfortunate and perhaps a completely new function field_attach_view_multiple() should have been written instead (though I certainly do not claim to be sure of that), however at this point I think we should stick to the path of documenting the behavior we already have and leave fixing this API funkiness for D8.
Thus, new patch attached Field API patch attached. Alex has decreed the node issue will be fixed here too, so we're still waiting for that (see my review and other discussion at the now-deprecated #844502: Calling node_preview modifies the previewed node.).
Comment #24
lotyrin commentedI'd like to get this taken care of, but what solution are we going with here? The latest patch is only a documentation change. Do we roll #23 and #7 together?
Comment #25
lotyrin commentedWrong status.
Comment #26
bjaspan commentedI think the plan is to go with the doc change for Field API and a bug fix in node.module. Alex has decreed that both should be handled in this one issue and marked the node-related issue a duplicate. So, go ahead and add your bugfix and tests to the Field API patch on this issue.
Comment #27
lotyrin commentedThis is #6 and #23
Comment #29
lotyrin commentedThe problems with #6 and thereby #27, if we go that route are as chx said in #844502: Calling node_preview modifies the previewed node., the onus of cloning should be on the function which calls node_preview since only the caller knows whether it's safe for its node to be modified, and it is expensive to assume that it's not safe and always clone the node.
However, node_preview was cloning the node before this patch anyways (just not for the entirety of the call), so we might be risking some kittens' lives if we start considering removing the clone.
Besides, the test is broken, since it doesn't do a deep comparison, as bjaspan pointed out in #844502: Calling node_preview modifies the previewed node..
Also, isn't #846356: node_preview() calls _field_invoke_multiple() a duplicate? That call is why this issue occurs.
Comment #30
lotyrin commentedOverlapped with the bot.
Comment #31
lotyrin commentedFixed the syntax error.
Comment #32
lotyrin commentedHere's another approach. This bug is because we do half of field_attach_(prepare)_view, clone the node, then do the other half. My solution was to clone the node, then to both parts.
After thinking about and agreeing with chx that node_preview should be allowed to modify the node, and therefore cloning it is unneccesary, why was the clone in there at all, all it was doing was breaking our fields.
This patch removes the clone altogether.
Edit: See below, this is the wrong file.
Comment #33
lotyrin commentedWrong file on that last comment.
Comment #34
yched commentedNote that theme_node_preview() also clones the node...
Comment #35
bjaspan commentedSo part of the cause of the issue here is that entities are now cached across multistep forms, which includes node preview, right? So by not cloning the node in the preview, we're causing the changes it makes to be cached and used subsequently e.g. when the node is saved.
I agree that the caller should be responsible for cloning. However, can we say with confidence what the consequence of not cloning the node in the node_preview() is? If not, perhaps this is late in the game to be changing that behavior.
So now we've considered solving the problem by cloning the node a little earlier, a little more earlier, a lot earlier, or not at all. :-) Anyone want to argue strongly for one approach? In general, my recommendation would be to solve the immediate problem in a way that is the most likely to be safe, and open a non-critical D7 to resolve the issue more generally (which might get pushed to D8).
Comment #36
sunWe are cloning since I'm using Drupal, so I don't know the real reason. However, I believe that we're cloning, since in previous Drupal versions, certain node properties were identical and thus altered and overwritten when viewing and previewing a node. I think that this is no longer the case with D7, so we should be fine without cloning. Unless we have similar code like the @todo in http://api.drupal.org/api/function/user_comment_view/7 somewhere in this game.
Comment #37
lotyrin commentedRe #35: I propose that we don't clone the node at all, unless we can discover somewhere that it breaks something. So far, no tests have failed with it gone.
My guess is with sun, that whatever we were protecting from here in Drupal's history has since been fixed.
If this clone really needs to be done, it needs better docs for why, and a test for the corner case that it's protecting against.
Off topic: As for why theme_node_preview is cloning the node, it only does it for the teaser, so perhaps that's related to #721754: A node cannot be displayed in different view mode on its own page?
Comment #38
bjaspan commentedHere we change $node->in_preview but do not change it back. That means it will be set for the rest of this form's life in the entity cache, right? That is different than what used to happen, and does not seem correct. Should we set in_preview back to FALSE (or unset it)?
Powered by Dreditor.
Comment #39
catchunset() seems right.
I agree with not cloning unless we find we have to.
Comment #40
aschiwi commentedI don't know about the architecture of the patch but I applied it and it solves the problem of disappearing tags as well as the huge amount of error messages upon previewing.
Comment #41
lotyrin commentedI can roll a new patch with the unset() later this evening, but I think the biggest issue here is the lack of tests.
Any ideas for what a test would even do? Do we test for exactly the case that discovered the issue (make a node with taxo terms, preview twice)? Or do we add tests to field API?
Comment #42
bjaspan commentedI don't think there are any Field API tests to write because we haven't actually found a bug there. I agree with your suggestion to preview a node twice, making sure the terms are there both times.
Comment #43
lotyrin commentedOkay. I'll add the unset() and the test strategy from #42.
Comment #44
lotyrin commentedHere's a quick stab at the test. I know it's broken since it passes with and without the changes to node.pages.inc.
I'm not sure how exactly to test this, since doing two drupalPost() in a row seems to start two separate edit workflows, clearing the intermediate state which causes our problem. Do I need to do something different with my drupalPost() calls? Is there another Simpletest call I should be making instead?
Comment #45
tstoecklerI think you should pass NULL as the $path for drupalPost() the second time. See http://drupal.org/node/265762
Comment #46
lotyrin commentedRe #45: Thanks, I was reading through the docs trying to figure it out but didn't see that.
This patch includes my removal of the clone from node_preview, bjaspan's doc changes, and tests of node previews with taxo terms (one of which previews an already previewed node, testing the case that discovered our issue).
I've verified that the test fails on the CVS version of node_preview and passes with my changes.
Comment #48
lotyrin commentedI wonder if it didn't like the filename. Trying again.
Comment #49
chx commentedObviously I agree.
Comment #50
bjaspan commentedI personally would prefer an xpath test that verified the term names appeared inside <div class="preview">, but it is not critical.
I support RTBC.
Powered by Dreditor.
Comment #51
marcingy commented#48: 844388.patch queued for re-testing.
Comment #52
dries commentedOK, these changes are actually small and have been signed off by all the maintainers. Committed to CVS HEAD.
Comment #54
shaikhnizam commentedUse this patch, it will work fine
http://drupal.org/files/issues/field_default_prepare_view-934726-36.patch
Comment #55
james.williamsI'm really reluctant to open this fairly epic issue, and it may be better to open a new issue, but the history of the comments above go through the problem.
Issue #1025870: Previewing a node causes $node->uri['path'] to be set to 'node/' in hook_node_insert() is a problem that exists because the $node object is not cloned when previewing. Taxonomy fields rely on hook_field_formatter_prepare_view() being invoked to display properly (which caused this issue originally and probably #1062396: Taxonomy terms fails in node preview page if hidden format selected too), but this won't happen if that pesky
$node->_field_view_preparedis set. Surely previewing a node shouldn't affect the data in the $node object that is being created/edited on the node form? Currently, it does.Since lotyrin said way back in comment #37:
...I suggest that since not cloning does break something after all, it needs fixing. I cannot understand why previewing would be allowed to alter the original node object like this. If I edit or create a node, I don't expect previewing to change my node!
Of course, I realise it's not as simple as that, I respect that this issue has already gone through much discussion.
Comment #56
lotyrin commentedThis issue history is interesting and relevant to the linked discussions, but this issue is resolved. We can consider cloning or other solutions in the other issues.
Comment #57
daniel.nitsche commentedSorry to drag up an old issue, is this really fixed? I'm running 7.21 and I'm seeing the same problem.
Having a little dig around, it seems to me that $items in taxonomy_field_formatter_view (taxonomy.module) does not receive the expected taxonomy names, and so for taxonomy_term_reference_plain at least, no term appears at all (on a second preview).
I'm happy to log a new bug if this is completely unrelated.
Here's my workaround if anyone is interested:
PS. I initially thought this may have something to do with this line of code in taxonomy.module (that looks like a bug) but it turned out to be unrelated:
$name = ($item['tid'] != 'autocreate' ? $item['taxonomy_term']->name : $item['name']);