lpa Posted December 26, 2013 Share Posted December 26, 2013 Hi Teppo, I can click on "Compare with current" but I don't see any diff. I get this on JS console: Uncaught TypeError: Cannot read property 'value' of null I am on Mac OS X with both Safari and Chrome. Link to comment Share on other sites More sharing options...
SteveB Posted December 29, 2013 Share Posted December 29, 2013 I've been experimenting with an addition to VersionControlForTextFields. Let's say we have a Page with some revision data. $soup = wire('pages')->get('/specials/soup/'); echo "<br/>Current soup: " . $soup->title; //Doing this gives Page a new method wire('modules')->get('ProcessRevisionHistoryForTextFields'); //What kind of soup were we serving last week? $soup->snapshot('-1 week'); echo "<br/>Old soup: " . $soup->title; After the call to snapshot() any version controlled fields of the Page will have the values they had at the time specified. The changes to make this work are made to the ProcessRevisionHistoryForTextFields.module file. Add one line to the init() public function init() { parent::init(); $this->addHook('Page::snapshot', $this, 'pagesnapshot'); //add this line } Add these: public function pagesnapshot($event) { $page = $event->data['object']; if ($data = $this->snapshot($page, $event->arguments(0))) foreach($data as $k=>$v) $page->$k = $v; } public function snapshot($page, $time='') { $id = $page->id; if (!$id) throw new WireException("Missing required param id"); if (!is_integer($time)) $time = strtotime($time); if (empty($time)) $time = time(); // how many of this page's fields do we keep history for? (configured for each template) $ct = count($page->template->versionControlFields); // find values $sql = " SELECT m.fields_id, m.pages_id, d.* FROM " . self::TABLE_NAME . " AS m, " . self::DATA_TABLE_NAME . " AS d WHERE m.pages_id = $id AND d." . self::TABLE_NAME . "_id = m.id AND m.timestamp <= FROM_UNIXTIME($time) ORDER BY m.timestamp DESC "; $result = $this->db->query($sql); // generate data (associative array) $data = array(); if ($result->num_rows) { while ($row = mysqli_fetch_assoc($result)) { $field = $this->fields->get($row['fields_id']); if (!array_key_exists($field->name, $data)) $data[$field->name] = $row['data']; if (count($data) >= $ct) break; } } return $data; } 3 Link to comment Share on other sites More sharing options...
teppo Posted December 30, 2013 Author Share Posted December 30, 2013 @SteveB: this looks very interesting. I had planned something similar (in the form of changesets, which would've been a bit bigger concept really), but your solution seems a *lot* simpler than what I had in mind. Would it be OK if I reviewed this, possibly made some small(ish) changes and implemented it as a part of the original module? Of course I'll add @author information to make it (as much as possible) obvious what part was written by whom.. Please note that I've just added LICENSE file, @license phpdoc tags etc. to clarify that this module is licensed under GPLv2. That has always been my intention, but it wasn't obvious earlier. This becomes especially important if code from other authors ends up in the module; that way their code included with the module would also be under GPLv2 from that point on. Hi Teppo, I can click on "Compare with current" but I don't see any diff. I get this on JS console: Uncaught TypeError: Cannot read property 'value' of null I am on Mac OS X with both Safari and Chrome. Thanks for reporting this, I'll have to take a closer look at the issue later. Link to comment Share on other sites More sharing options...
SteveB Posted December 30, 2013 Share Posted December 30, 2013 Would it be OK if I... Yes, that would be great. FYI, the first thing I had done was to simply modify ___execute() so I could pass it a page id and it would return the $data array of revisions. Then I wrote the snapshot function. Then I got the idea to hook it to pages. A couple more thoughts... Normally the revision data will be limited by data_max_age or data_row_limit settings. If you give the snapshot method a timestamp older than the oldest revision data you get current Page data and don't know whether that's really what the page was like at the specified time or not. The simple change below helps but doesn't tell you the difference between a Page which never changed and a Page with changes that are no longer in the database. public function pagesnapshot($event) { $page = $event->data['object']; if ($data = $this->snapshot($page, $event->arguments(0))) foreach($data as $k=>$v) $page->$k = $v; else return false; //ADDED THIS } Is there a simple way to have the snapshot capability automatically hooked into pages which have tracked fields? I'm wondering if the VersionControlForTextFields gather method could set that up. I noticed after I deleted a page that the version info for it did not go away. If data_max_age hasn't been set it won't age out and get cleaned up. 3 Link to comment Share on other sites More sharing options...
apeisa Posted December 31, 2013 Share Posted December 31, 2013 That $p->snapshot() stuff is supercool! It would be trivial to create "timeback machine" for frontend... 3 Link to comment Share on other sites More sharing options...
ryan Posted January 1, 2014 Share Posted January 1, 2014 I noticed after I deleted a page that the version info for it did not go away. If data_max_age hasn't been set it won't age out and get cleaned up. The module may need a Pages::deleted hook: public function init() { $this->pages->addHookAfter('deleted', $this, 'hookPageDeleted'); } public function hookPageDeleted($event) { $page = $event->arguments(0); $this->db->query("DELETE FROM " . self::TABLE_NAME . " WHERE pages_id=" . (int) $page->id); } 1 Link to comment Share on other sites More sharing options...
teppo Posted January 1, 2014 Author Share Posted January 1, 2014 @SteveB and @ryan: good point about deleted pages, this is now taken care of. No idea why I didn't think of this earlier. 2 Link to comment Share on other sites More sharing options...
teppo Posted January 25, 2014 Author Share Posted January 25, 2014 I've just pushed to GitHub new version of this module. This update includes some minor improvements, such as storing version data for pages starting from the moment they're added, and as a bigger addition $page->snapshot() feature exactly as described by @SteveB earlier: echo "Page title now: {$page->title}<br />"; $page->snapshot("-1 week"); echo "Page title last week: {$page->title}<br />"; I've been working on and off this for a while now and actually had to write a bunch of PHPUnit tests just to make sure that everything works as expected (too many moving parts to keep track of manually.) There's still some work to do here and especially performance-wise more tests to be made, but at least this shouldn't disrupt how other parts of the module work 9 Link to comment Share on other sites More sharing options...
Martijn Geerts Posted January 25, 2014 Share Posted January 25, 2014 I really like all the work & love you've put in this module. I consider this one, one of the best modules available for ProcessWire. I have big respect not only for the the module it self, but also for the care you take for this. 4 Link to comment Share on other sites More sharing options...
arjen Posted January 25, 2014 Share Posted January 25, 2014 That makes two of us! Great work indeed! 1 Link to comment Share on other sites More sharing options...
teppo Posted February 11, 2014 Author Share Posted February 11, 2014 Update: version 1.3.0, just pushed to GitHub, adds support for repeaters -- or, to be more precise, support for saving revision data for fields that are within repeaters. Repeaters being pages after all, it seemed most logical to treat them as such. If repeater field added to a template for which version control has been enabled contains fields that are also under version control, values of those fields will be stored just like they would be for the main page (page containing the repeater field). I'm not confident that my explanation made any sense, so let's just say that this should be self-evident once you try it. Main point is that instead of saving repeater values on per repeater basis the module is treating individual repeater fields (or repeater field fields..) separately Another thing to note is that snapshot feature added in previous update is now module called PageSnapshots. It's still bundled with VersionControlForTextFields and initiated (and automatically installed) by VersionControlForTextFields init() method, so this shouldn't change anything. I'm simply trying to keep the "core" version control module as lean as possible. Once again, I'd suggest making sure that things work properly before putting this update into real world use. There have been a lot of changes and something could've broken. I've tried to write and run tests vigorously, but those definitely won't catch all issues.. yet 10 Link to comment Share on other sites More sharing options...
dragan Posted February 14, 2014 Share Posted February 14, 2014 Version 0.9.2 of this module (just pushed to GitHub) introduces support for multi-language fields. See commit details for more info. I've also brought in some minor fixes etc. during this weekend, so if you've installed this module you should consider updating. I installed this today in a PW 2.4 site, but non-default language changes don't really show. Link to comment Share on other sites More sharing options...
dragan Posted February 14, 2014 Share Posted February 14, 2014 Q: How difficult would it be to create a daily cron job, to send out a daily email with all changes done in the last 24 hours? (in an abbreviated form, not too geeky) Quickly scanning the module code, I see you're using three extra DB tables. In the __data table, some entries in the property field look like this: data10141015 or data101410151016. I guess these relate to non-default languages, the number being the language id? If I only edit one single language field value, why does it store multiple languages though? Link to comment Share on other sites More sharing options...
teppo Posted February 14, 2014 Author Share Posted February 14, 2014 I installed this today in a PW 2.4 site, but non-default language changes don't really show. Could you specify what kind of field this is that's not saving, TextareaLanguage or something else? Based on your second post I'm guessing that data still gets saved to db tables, is that right? Are you using the default theme ("new" or old) or something else? I'm currently running a fresh test site where this seems to work properly, so any additional information would be helpful. Q: How difficult would it be to create a daily cron job, to send out a daily email with all changes done in the last 24 hours? (in an abbreviated form, not too geeky) I'd probably approach this directly via database. Table version_control_for_text_fields contains all changes and timestamps for those, so it would be easy to grab changes made during last 24 hours. Rest depends very much on what you want to send, i.e. do you want to also describe how content in each field changed and so on, so there's really no simple answer for this one. Quickly scanning the module code, I see you're using three extra DB tables. In the __data table, some entries in the property field look like this: data10141015 or data101410151016. I guess these relate to non-default languages, the number being the language id? If I only edit one single language field value, why does it store multiple languages though? Two tables, actually, and you're right in that those are language values. All values are stored mostly because that's what ProcessWire itself does -- it updates all language values simultaneously. You're right in that it feels a bit weird, especially here where rows are stored potentially for a very long time. I'm not yet sure how to get more specific data from ProcessWire (which language version has changed), so setting these values separately might require another method for handling data. This could also make certain database queries a lot more complicated. Created an issue for this one so I won't forget it right away.. 1 Link to comment Share on other sites More sharing options...
dragan Posted February 15, 2014 Share Posted February 15, 2014 Thanks for the feedback. I'm using mainly TextareaLanguage fields. And one of the four 2.4 default PW admin themes ("classic"). I see all edits in the DB, but they're not visible when I use the watch-icon in page-edit view. I'm also using FieldLanguageTabs, if that matters. Example: If I edit a french text-value somewhere, save, let the page reload, and use the version history icon (french lang. tab selected), I don't see anything in the "compare" hover, and clicking on "username / date" doesn't dynamically replace the textinput with the older version, as it does with the default language. I compared the PW DB-field names for one particular field - they look like this: pages_id data // default language data1014 // en data1015 // us-en data1016 // fr In your table version_control_for_text_fields__data, I see that each edit creates four DB-entries (one per language). The "property" fields look like this: data data1014 data10141015 // shouldn't this be data1015? data101410151016 // shouldn't this be 1016? I guess it could be a JS issue too, since I'm using the multilang field tabs module, but disabling that would not fare well with my client :-| Link to comment Share on other sites More sharing options...
teppo Posted February 15, 2014 Author Share Posted February 15, 2014 @dragan: thanks, that actually solved it. There was an issue with storing language versions; language ID's were getting "stacked" instead of last one being used, which resulted in useless data. Looks like I never properly tested this with multiple language versions.. I've just pushed fix to GitHub and would suggest you (and everyone else reading this) to update the module. To fix existing data you can do something like this in your database: UPDATE version_control_for_text_fields__data SET property = "data1015" WHERE property = "data10141015"; UPDATE version_control_for_text_fields__data SET property = "data1016" WHERE property = "data101410151016"; # .. and so on 1 Link to comment Share on other sites More sharing options...
dragan Posted February 16, 2014 Share Posted February 16, 2014 Thanks! Everything works silky smooth now Link to comment Share on other sites More sharing options...
apeisa Posted February 16, 2014 Share Posted February 16, 2014 Ups - I accidentally removed Teppo's reply, while using mobile UI. Pete - do we have any way to restore it? Sorry Teppo... 1 Link to comment Share on other sites More sharing options...
teppo Posted February 16, 2014 Author Share Posted February 16, 2014 I've surely written some crappy replies earlier, but this was first one bad enough to be removed No need to restore anything, really. Main point of that reply was that this module had a bug that @dragan uncovered. When more than two languages were in use, values were getting stacked, i.e. version_control_for_text_fields__data contained property values such as "data10141015" instead of "data1015", "data101410151016" instead of "data1016" and so on. This is fixed in current version at GitHub so I strongly suggest everyone using this module to update to that. To fix existing data you have to replace those nonsensical values directly in your database: UPDATE version_control_for_text_fields__data SET property = 'data1015' where property = 'data10141015'; UPDATE version_control_for_text_fields__data SET property = 'data1016' where property = 'data101410151016'; # .. and so on, depending on actual language page IDs (broken values should be easy to spot) 3 Link to comment Share on other sites More sharing options...
Pete Posted February 16, 2014 Share Posted February 16, 2014 Ups - I accidentally removed Teppo's reply, while using mobile UI. Pete - do we have any way to restore it? Sorry Teppo... Done 3 Link to comment Share on other sites More sharing options...
dragan Posted February 20, 2014 Share Posted February 20, 2014 Just a little word of caution: The fieldtype checkbox is also in the allowed field-types. At least with multi-lang sites, this creates strange entries in the DB: default language: 1 (OK - checked) all other languages: some string value from another, totally unrelated field Maybe leave out checkbox input type in the module config / settings dialogue altogether? (I know, I'm nitpicking here... to avoid confusion, I have removed that field from the watch settings) 1 Link to comment Share on other sites More sharing options...
teppo Posted February 21, 2014 Author Share Posted February 21, 2014 @dragan: that's good to know and definitely not nitpicking -- my intention at this point is to make this module support all native fieldtypes (except images and files, though I'll hopefully get there eventually), including checkboxes. I'm starting to realize that not writing specific tests for multilanguage part was a huge mistake, obviously there are quite a few weird things happening there As soon as I get the time, I'll write a test case for checkboxes (for starters) and see what exactly is going on. It should work. 3 Link to comment Share on other sites More sharing options...
adrianromega Posted March 3, 2014 Share Posted March 3, 2014 Hello and thanks for this great module. It seams to be working fine except that when is activated for a template, if that template contains image fields, after dragging and dropping the image, this module breaks the upload response and immediate image that was uploaded is not shown (instead is returned the return form inject function of this module). The version control is activated only for body field... Just wanted to mention this. Please tell me is I am doing something wrong. Thank you. 1 Link to comment Share on other sites More sharing options...
homma Posted March 4, 2014 Share Posted March 4, 2014 Hello, this module looks fantastic. But unfortunately, I encounter an error while setting up the module. I'm using ProcessWire 2.3.0 with Languages Support module. I installed the latest version of this module (1.3.1), but when I try to configure the module, it returns an error: "Method TemplatesArray::makeCopy does not exist or is not callable in this context" The other modules - Page Snapshot and Revision History For Text Fields are installed correctly and the configuration of Revision History is working. Any ideas to solve this issue? Thanks in advance! 1 Link to comment Share on other sites More sharing options...
teppo Posted March 7, 2014 Author Share Posted March 7, 2014 @adrianromega and @homma: thanks for reporting these issues. I've been terribly busy lately, but will take the time to process these properly (hopefully) this weekend. Your posts are noted and much appreciated Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now