Create a revision archive for field values: Difference between revisions
Appearance
No edit summary |
Put in a check for date type so empty dates will be saved |
||
| (15 intermediate revisions by 2 users not shown) | |||
| Line 3: | Line 3: | ||
Describes how to create a revision system so every change in selected fields in a node can be tracked. | Describes how to create a revision system so every change in selected fields in a node can be tracked. | ||
First create a table: | |||
<code> | <code> | ||
CREATE TABLE IF NOT EXISTS `revision` ( | CREATE TABLE IF NOT EXISTS `revision` ( | ||
`rev_table` varchar( 50 ) NOT NULL , | `rev_table` varchar( 50 ) NOT NULL , | ||
`rev_field` varchar( 50 ) NOT NULL , | `rev_field` varchar( 50 ) NOT NULL , | ||
`rev_atkprimkey` varchar( 200 ) NOT NULL , | `rev_atkprimkey` varchar( 200 ) NOT NULL , | ||
`rev_datetime` datetime NOT NULL , | `rev_datetime` datetime NOT NULL , | ||
`rev_username` varchar( 25 ) NOT NULL , | `rev_username` varchar( 25 ) NOT NULL , | ||
`rev_value` text, | `rev_value` text, | ||
PRIMARY KEY ( `rev_table` , `rev_field` , `rev_datetime` , `rev_username` , `rev_atkprimkey` )) | PRIMARY KEY ( `rev_table` , `rev_field` , `rev_datetime` , `rev_username` , `rev_atkprimkey` )) | ||
</code> | </code> | ||
use this baseclass instead of your usual atkNode | |||
< | Then use this baseclass instead of your usual atkNode. | ||
class watkNode extends atkNode | Add fields from your node to | ||
{ | $this->m_revision_fields(array("field1","field")); | ||
Then every fieldchange in these fields will be saved to the database. | |||
<syntaxhighlight lang="php"> | |||
class watkNode extends atkNode { | |||
var $m_revision_fields=array(); //Add fields from your node here to track changes | var $m_revision_fields=array(); //Add fields from your node here to track changes | ||
function watkNode($type, $flags="") | function watkNode($type, $flags="") | ||
| Line 25: | Line 29: | ||
$this->addFlag(NF_TRACK_CHANGES); | $this->addFlag(NF_TRACK_CHANGES); | ||
} | } | ||
function postUpdate($record) | function postUpdate($record) | ||
{ | { | ||
| Line 32: | Line 37: | ||
return true; | return true; | ||
} | } | ||
function postAdd($record) | function postAdd($record) | ||
{ | { | ||
| Line 39: | Line 45: | ||
return true; | return true; | ||
} | } | ||
function checkrevision($record) { | |||
$save_revision_fields=array(); | $save_revision_fields=array(); | ||
foreach($this->m_revision_fields as $revision_field) | foreach($this->m_revision_fields as $revision_field) { | ||
if ($record[$revision_field]<>$record['atkorgrec'][$revision_field]) | if ($record[$revision_field]<>$record['atkorgrec'][$revision_field]) { | ||
$save_revision_fields[$revision_field]=$record[$revision_field]; | $attrib=$this->getAttribute($revision_field); | ||
if (is_object($attrib)) { //Check that attribute exists | |||
if(stripos(get_class($attrib),'date')) {//date must be handled different | |||
$value=$attrib->display(array($revision_field=>$record[$revision_field]),"view"); | |||
$value_old=$attrib->display(array($revision_field=>$record['atkorgrec'][$revision_field]),"view"); | |||
if ($value_old<>$value) { | |||
$save_revision_fields[$revision_field]=$value; | |||
} | |||
} | |||
elseif(stripos(get_class($attrib),'manytoonerelation')) {//onetomanyrelation must be handled different | |||
$value=$attrib->display(array($revision_field=>$record[$revision_field]),"view"); | |||
$value_old=$attrib->display(array($revision_field=>$record['atkorgrec'][$revision_field]),"view"); | |||
if ($value_old<>$value and array_merge($record['atkorgrec'][$revision_field],$record[$revision_field])<>$record['atkorgrec'][$revision_field]) { | |||
$save_revision_fields[$revision_field]=$value; //If different descriptor and different PK's save | |||
} | |||
} | |||
else { | |||
$save_revision_fields[$revision_field]=$attrib->display(array($revision_field=>$record[$revision_field])); | |||
} | |||
} | |||
} | |||
} | |||
if (count($save_revision_fields)>0) | if (count($save_revision_fields)>0) | ||
$this->updaterevision($record['atkprimkey'],$save_revision_fields); | $this->updaterevision($record['atkprimkey'],$save_revision_fields); | ||
} | |||
function updaterevision($rev_atkprimkey,$save_revision_fields) | function updaterevision($rev_atkprimkey,$save_revision_fields) { | ||
global $g_user; | |||
$revnode=&atkGetNode("revision.revision"); | $revnode=&atkGetNode("revision.revision"); | ||
$update_datetime=array('year'=>date('Y'), | $update_datetime=array('year'=>date('Y'), | ||
'month'=>date('m'), | 'month'=>date('m'), | ||
| Line 59: | Line 85: | ||
'minutes'=>date('i'), | 'minutes'=>date('i'), | ||
'seconds'=>date('s')); | 'seconds'=>date('s')); | ||
$rev_atkprimkey=str_replace("'",'',$rev_atkprimkey); | $rev_atkprimkey=str_replace("'",'',$rev_atkprimkey); | ||
foreach($save_revision_fields as $field=>$value) | foreach($save_revision_fields as $field=>$value) { | ||
$rec['rev_atkprimkey']=$rev_atkprimkey; | $rec['rev_atkprimkey']=$rev_atkprimkey; | ||
$rec['rev_table']=$this->m_table; | $rec['rev_table']=$this->m_table; | ||
| Line 72: | Line 97: | ||
} | } | ||
} | } | ||
</syntaxhighlight> | |||
</ | |||
The revision node: | The revision node: | ||
< | <syntaxhighlight lang="php"> | ||
useattrib("atkattribute"); | useattrib("atkattribute"); | ||
useattrib("atkdatetimeattribute"); | useattrib("atkdatetimeattribute"); | ||
useattrib("atktextattribute"); | useattrib("atktextattribute"); | ||
class revision extends atkNode | class revision extends atkNode { | ||
function revision() | function revision() | ||
{ $this->atkNode("revision",NF_ADD_LINK); | { $this->atkNode("revision",NF_ADD_LINK); | ||
| Line 93: | Line 116: | ||
$this->setOrder("rev_table,rev_field,rev_datetime"); | $this->setOrder("rev_table,rev_field,rev_datetime"); | ||
$this->setTable("revision"); | $this->setTable("revision"); | ||
} | |||
function rev_value_display($record,$mode) // Override the display function so the preformatted data is shown as saved in the database. | |||
{ | |||
return $record['rev_value']; | |||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
What's missing here is a generic way of showing the different revisions. | |||
An example of how this may look in the outlook theme is showed below. | |||
This requires editing the edit & view handler, and the two templates. | |||
[[Image:revision.gif]] | |||
Latest revision as of 09:55, 11 December 2009
|
ATK Howto: Create a revision archive for field values
|
Describes how to create a revision system so every change in selected fields in a node can be tracked.
First create a table:
CREATE TABLE IF NOT EXISTS `revision` (
`rev_table` varchar( 50 ) NOT NULL ,
`rev_field` varchar( 50 ) NOT NULL ,
`rev_atkprimkey` varchar( 200 ) NOT NULL ,
`rev_datetime` datetime NOT NULL ,
`rev_username` varchar( 25 ) NOT NULL ,
`rev_value` text,
PRIMARY KEY ( `rev_table` , `rev_field` , `rev_datetime` , `rev_username` , `rev_atkprimkey` ))
Then use this baseclass instead of your usual atkNode. Add fields from your node to $this->m_revision_fields(array("field1","field")); Then every fieldchange in these fields will be saved to the database.
class watkNode extends atkNode {
var $m_revision_fields=array(); //Add fields from your node here to track changes
function watkNode($type, $flags="")
{
$this->atkNode($type, $flags);
if (count($this->m_revision_fields)>0)
$this->addFlag(NF_TRACK_CHANGES);
}
function postUpdate($record)
{
if (count($this->m_revision_fields)>0)
$this->checkrevision($record);
parent::postUpdate($record);
return true;
}
function postAdd($record)
{
if (count($this->m_revision_fields)>0)
$this->checkrevision($record);
parent::postAdd($record);
return true;
}
function checkrevision($record) {
$save_revision_fields=array();
foreach($this->m_revision_fields as $revision_field) {
if ($record[$revision_field]<>$record['atkorgrec'][$revision_field]) {
$attrib=$this->getAttribute($revision_field);
if (is_object($attrib)) { //Check that attribute exists
if(stripos(get_class($attrib),'date')) {//date must be handled different
$value=$attrib->display(array($revision_field=>$record[$revision_field]),"view");
$value_old=$attrib->display(array($revision_field=>$record['atkorgrec'][$revision_field]),"view");
if ($value_old<>$value) {
$save_revision_fields[$revision_field]=$value;
}
}
elseif(stripos(get_class($attrib),'manytoonerelation')) {//onetomanyrelation must be handled different
$value=$attrib->display(array($revision_field=>$record[$revision_field]),"view");
$value_old=$attrib->display(array($revision_field=>$record['atkorgrec'][$revision_field]),"view");
if ($value_old<>$value and array_merge($record['atkorgrec'][$revision_field],$record[$revision_field])<>$record['atkorgrec'][$revision_field]) {
$save_revision_fields[$revision_field]=$value; //If different descriptor and different PK's save
}
}
else {
$save_revision_fields[$revision_field]=$attrib->display(array($revision_field=>$record[$revision_field]));
}
}
}
}
if (count($save_revision_fields)>0)
$this->updaterevision($record['atkprimkey'],$save_revision_fields);
}
function updaterevision($rev_atkprimkey,$save_revision_fields) {
global $g_user;
$revnode=&atkGetNode("revision.revision");
$update_datetime=array('year'=>date('Y'),
'month'=>date('m'),
'day'=>date('d'),
'hours'=>date('H'),
'minutes'=>date('i'),
'seconds'=>date('s'));
$rev_atkprimkey=str_replace("'",'',$rev_atkprimkey);
foreach($save_revision_fields as $field=>$value) {
$rec['rev_atkprimkey']=$rev_atkprimkey;
$rec['rev_table']=$this->m_table;
$rec['rev_field']=$field;
$rec['rev_username']=$g_user["full_name"];
$rec['rev_datetime']= $update_datetime;
$rec['rev_value']=$value;
$revnode->addDb($rec);
unset($rec);
}
}
The revision node:
useattrib("atkattribute");
useattrib("atkdatetimeattribute");
useattrib("atktextattribute");
class revision extends atkNode {
function revision()
{ $this->atkNode("revision",NF_ADD_LINK);
$this->add(new atkAttribute("rev_atkprimkey", AF_SEARCHABLE|AF_PRIMARY));
$this->add(new atkAttribute("rev_table", AF_SEARCHABLE|AF_PRIMARY));
$this->add(new atkAttribute("rev_field", AF_SEARCHABLE|AF_PRIMARY));
$this->add(new atkDateTimeAttribute("rev_datetime", AF_SEARCHABLE|AF_PRIMARY));
$this->add(new atkAttribute("rev_username", AF_SEARCHABLE));
$this->add(new atkTextAttribute("rev_value", AF_SEARCHABLE));
$this->setOrder("rev_table,rev_field,rev_datetime");
$this->setTable("revision");
}
function rev_value_display($record,$mode) // Override the display function so the preformatted data is shown as saved in the database.
{
return $record['rev_value'];
}
}
What's missing here is a generic way of showing the different revisions.
An example of how this may look in the outlook theme is showed below.
This requires editing the edit & view handler, and the two templates.