Closed (fixed)
Project:
Feeds
Version:
6.x-1.x-dev
Component:
Code
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Reporter:
Created:
13 Nov 2009 at 14:57 UTC
Updated:
5 Feb 2011 at 23:01 UTC
Jump to comment: Most recent file
Comments
Comment #1
alex_b commented1. Introduce a
protected FeedsNodeProcessor::hash($item)and protectedFeedsNodeProcessor::getHash($nid)2. in FeedsNodeProcessor::process():
Comment #2
velosol commentedTrying to gather some initial ideas for the additions that need to be made:
Added to feeds.install $schema['feeds_node_item']:
Hash item function:
getHash function:
With regards to the hash function and database definition - it may be better/faster if we use the second argument of md5() to return the raw output (see: http://us2.php.net/manual/en/function.md5.php ) and treat it as an int.
Thoughts, additions, corrections, requests?
Edit: corrected syntax of update function and made protected func syntax match.
Edit2: reading up on that PHP page suggests that hash('md5', $to_hash) is faster than md5(), adjusting.
Comment #3
alex_b commentedThis is all looking very good. Adjustments can be done when the patch lands.
Comment #4
velosol commented[edit: most up-to-date below]
Patch, did someone say patch?
I modified FeedsNodeProcessor::map() as you suggested so that it can modify the $node as a parameter - however it still returns - good functionality?
Edit: I also left node_object_prepare in map() as the include statement for the node module is there and I didn't want to break it out of map.
I also included an update function in install as 6007.
I tested by running update.php then first deleting nodes and then importing again; and then trying to import again, I got a happy "There is no new content." I did NOT test importing over nodes that did not yet have a hash set - but I would assume that they would get one final 'fake' revision.
Comment #5
velosol commented[edit: most up-to-date below]
New patch- the last node_processor.patch was overwriting the $node even if it already existed because $node = new stdClass(); came after $node->nid = $nid when a $nid was returned by existingItemId().
This new one moves the creation of the $node up to where before it's really needed, but is cleaner.
Comment #6
alex_b commented1. Patch does not apply cleanly to HEAD (1 out of 3 hunks fails).
2. Minor request: Could you create the patch from the actual feeds/ directory? That'd be easier to apply :)
3. Let's move all the node initialization code from map() into process(), also the node_object_prepare() call. More consistent.
4. No need for commenting on closing brackets
} //class FeedsNodeProcessor5. Why is there a test for is_array() in hash() ? Couldn't we just hash('md5', serialize($item)) ?
6. getHash() should return an empty string if no hash was found, hash() must never return an empty string *). Let's not use 0 as return value as it is a different type than the usual return value. If we make the default value in the DB an empty string, we can keep the code simple.
7. Accordingly, the comparison
$hash === $this->getHash($nid)must use the triple equals as to exclude false positives between different types (FALSE, 0, NULL and '')8. There should also be a test for this behavior. Otherwise, future refactoring of this portion of the code would run a high risk of causing regression.
*)
http://php.net/manual/en/function.md5.php :
md5 on a null string returns null, md5 on an EMPTY string does not return null or an empty string. Rather it returns "d41d8cd98f00b204e9800998ecf8427e"
Comment #7
velosol commented@alex_b:
I have addressed most of the stuff in my working copy of the code - I can post that as a patch if you'd like, but I'd prefer to get some feedback re: my questions in 3 & 5.
1. D'oh! Was patching to alpha7. I can grab stuff from CVS, but it's a huge pain on this Windows box - any chance the -dev/HEAD portion could be tarballed for the front page of Feeds?
2. Will do in future patches, my mistake.
3. Done - all that's left is self::loadMappers() and the parent::map() call - do you want the static $included stuff to live on, or just do the module_load_include() call each time?
4. My bad again, it was in there because I had borked a previous attempt at the patch and didn't want to do it again - I'll take it out before rolling further patches.
5. I'm in the habit of type-checking - and it provided an easy way to return on bad input. If that's not a concern (second half of point 6?), do we even need the overhead of another function call vice:
$hash = hash('md5', serialize($item));in process()? *6. Updated getHash() in my working copy to return an empty string when no hash is found. **
7. Done.
8. Definitely! Unfortunately I'm not really great with Drupal's test framework - I'll poke around in other tests and see if I can come up with something, but I expect someone else may be able to do a better job.
* - I can't get hash('md5') nor md5() to ever return NULL (I tried passing, NULL, FALSE, empty strings to each) - only to get the d41...27e hash every time. Beyond that I'm not committed to any particular hash creation method.
** - Forgive my ignorance, but if the query doesn't find anything, the db_result/db_query returns FALSE, not the schema default, right? So we'd still have to catch the FALSE and return ''?
Comment #8
alex_b commented1. Use cygwin http://www.cygwin.com/ - You're a good contributor you should have your tool box in order :-)
3. Leave static in for now. We may want to factor this out in a follow up patch.
5. Drats. I should not have believed what i found in the PHP documentation comments. However, this still works in our favor: hashing an empty item will always return a hash string, while looking up a legacy item will return an empty string or - as you pointed out - looking up a missing item will return FALSE. In these cases, $hash == $this->getHash($nid) will evaluate to false and the item will be updated. Also no need for a triple equals check anymore.
8. :-)
Comment #9
velosol commented[edit: most up-to-date below]
Alright, based on the past couple of comments, I've got a new version of the patch (against dev/1.15). The last hunk looks strange (removes and adds the final '}', notes 'No newline at end of file') as I didn't touch that function - but I've left it in for the time being. I've also added to the function header comments to clarify behavior (protected hash always returns a hash, getHash returns hash or empty string).
I'll see what I can do to get a test set up for this functionality.
Is the feeds.install patch from comment #4 OK once this patch is up to snuff?
Comment #10
velosol commentedI guess I still need some more coffee!
[edit: see below for bug cause - and fix]
The patch in #9 will update a node, but not create a new revision. I was expecting to get revisions as I had with the patch in #5, but that isn't happening anymore - I think it's because of the $node->vid addition, although I can't pin it down to that.
Sorry I didn't catch this before posting the patch, I had only been checking if the node content was updated, not if the "revisions" link was available.
To get revisions again:
Ultimately the question is: What is the "correct" behavior? I think creating a new revision is expected, but that could be just for my use case.
And yes, I realize that this just further highlights the need for tests :) .
Comment #11
alex_b commentedI'd say the right behavior is that if "Create revisions" is checked on a content type, FeedsNodeProcessor should create new revisions for nodes of that type.
http://skitch.com/alexbarth/nebw2/feed-item-localhost
Comment #12
alex_b commented.install is looking good except the indentation in the update hook. Could you also roll just one patch for all files?
Comment #13
velosol commentedThe 'bug' in #10 was my own fault - copy and paste coding fails when the variables change; node_object_prepare() is now called properly and the node's revision status is set based on the setting in the content type (as in #11).
I'm still working towards tests.
The .install indentation is fixed and both .install and FeedsNodeProcessor.inc are in this patch.
Comment #14
alex_b commentedCool. Waiting for the tests for a closer review.
Comment #15
pbuyle commentedSome feed format (Atom for instance) provides a field that indicate the last modification time of an item (in Atom, that would be the
updatedelement).In addition to hashing, wouldn't it be nice to have the option to only update a node only if
$node->changed < $item->udpated?Comment #16
velosol commentedAfter a bit of a fight with testing and the core patch, I've got tests written and passing to verify the update-if-changed behavior. The other RSS file I've added (/tests/feeds/developmentseed.rss3) I had to attach separately as my cvs/diff would not incorporate it into the patch.
Please review and let me know if more needs to be done.
@monoglito404 : I believe this patch will take care of the
$node->changed < $item->updatedcase by virtue of hashing. If there's a specific case where hashing wouldn't take care of that use case (or another similar situation) please post back.Comment #17
alex_b commentedGreat. I did a close review and adjusted the following:
- rearranged innards of process() for better legibility (please review to make sure I'm not trampling over assumptions)
- in tests, use setSettings() instead of updateExisting()
- renamed developmentseed.rss3 to developmentseed_changes.rss2
- fixed broken tests in feeds_defaults.test
- added test to feeds_defaults.test node import testing the new import behavior, this required a new test feed nodes_changes.csv
- some other minor cleanups
- I got queasy about editFeedNode() because it has many assumptions, but these are just the same as in createFeedNode(). Let's leave it this way for now, at some point we'll need to abstract this out.
All tests passing. Please give this patch another close look (especially process()); see whether all tests are passing for you. When I get an RTBC I will commit.
FYI - check out cvsdo for adding files to cvs repositories you don't have access to (I know, CVS sucks).
Comment #18
velosol commentedI'm having some trouble getting (any) tests to work in my environment right now so I can't really put your patch (17) through its paces. I did however just do some import tests by hand and it seems as though
$node->logis cleared bynode_object_prepare()- moving the$node->log = "Created/..."below the n_o_p call fixed it.I will post back once I've got my test environment up and running again and an updated patch.
Edit: I forgot to mention: everything else you did looks great and other than the above, I think process() is good - it had been arranged the same as before with the map() code in place of the map call for consistency, so no 'real' reason. Both edit and createFeedNode could use some cleanup/unification, but I didn't know where to start so I just mimicked the old code. Also, I can't believe I missed setSettings!
Comment #19
alex_b commentedRe: tests: use simpletest 2.9, read its install file before you install your drupal site and follow it religiously. If you still can't get your tests running, please open another issue for this. I'd be interested in helping you fix it. I know tests can be iffy to run and I think it's important to smooth out the creases.
NW because of the
$node->logissue.Comment #20
velosol commentedThank you for the offer of help - it appears as though my issue is #523878: Fatal error: Maximum execution time of 180 seconds exceeded which hasn't yet been backported as it hit HEAD after SimpleTest 2.9 was made. I'll get the patch into my SimpleTest and hope that clears things up. Posting here so others with a similar issue may find the fix - if it still doesn't fix the problem, I will open a new issue.
This is the referenced patch:
Comment #21
velosol commentedMy testing platform is working again, yay! After moving the
$node->logas in 18 the RSS import to nodes test was working fine (as before) and no more log error on manual import.I found errors in Defaults: Node import test and ran the import manually - it was creating 9 Story nodes (incorrect) and also complaining that 'url' didn't have a default value. This happened regardless of location of
$node->log. If I added a mapping for (CSV) guid => (DB) url, it imported correctly. I assume the correct behavior is to not have to map anything to 'url', but then Drupal complains about the INSERT queries. I'm leaving NW because of this, but it may not be related.I also made minor doc updates in feeds_default.test. The updated patch has new files included (thanks for the cvsdo tip!). While the RSS to node test passes, I had been seeing errors on others*.
*:I was getting #587304: Call to undefined function drupal_realpath() on the CVS import to users, Defaults: Node import, and other(?) tests. I made the adjustment as noted in that issue and now everything not already mentioned that I can test is passing (i.e. those tests requiring SimplePie or Data were not run).
Comment #22
alex_b commentedCommitted. This is an *awesome* contribution. This is fixing the update option to an extent that makes it a viable option for large feeds.
I could not reproduce the URL error you reported on the node import form. Please open a new issue if it persists.
Thank you.
Comment #24
Equinger commentedMaybe this is an edge case, but this doesn't work if your feed items don't have timestamps. The reason is that "Feeds" applies the feed timestamp to all the items if there is no timestamp. Reasonable enough, but the hash in this case is guaranteed to be different from the hash value in the node regardless of whether the content is different.
I'm just adding a timestamp to my feed items now, but this is just an FYI.