Jump to content

Create a revision archive for field values: Difference between revisions

From NusaATK
Oblygre (talk | contribs)
New page: {{howto|Expert|Olav B. Lygre <soppel at lygre dot no>}} Describes how to create a revision system so every change in selected fields in a node can be tracked. Create a table: <code>...
 
Oblygre (talk | contribs)
Put in a check for date type so empty dates will be saved
 
(18 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.


Create a table:
First create a table:
<code>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` )
)</code>
 
 
use this baseclass instead of your usual atkNode:
<code>class watkNode extends atkNode
  var $m_revision_fields=array();


<code>
  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` ))
</code>


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.
<syntaxhighlight lang="php">
  class watkNode extends atkNode { 
  var $m_revision_fields=array();  //Add fields from your node here to track changes
   function watkNode($type, $flags="")
   function watkNode($type, $flags="")
     {  
     {  
Line 27: Line 29:
       $this->addFlag(NF_TRACK_CHANGES);
       $this->addFlag(NF_TRACK_CHANGES);
     }
     }
   
 
   
   function postUpdate($record)
   function postUpdate($record)
     {
     {
Line 36: Line 37:
     return true;       
     return true;       
     }
     }
   function postAdd($record)
   function postAdd($record)
     {
     {
Line 43: Line 45:
     return true;       
     return true;       
     }
     }
   
 
  function  checkrevision($record)
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);
    $return;
     }
     }
           
   
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");
  global $g_user;
   $update_datetime=array('year'=>date('Y'),
   $update_datetime=array('year'=>date('Y'),
         'month'=>date('m'),
         'month'=>date('m'),
Line 65: Line 85:
         'minutes'=>date('i'),
         'minutes'=>date('i'),
         'seconds'=>date('s'));  
         'seconds'=>date('s'));  
         $rev_atkprimkey=str_replace("'",'',$rev_atkprimkey); //due to problems with ' in urls
         $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 78: Line 97:
     }
     }
   }
   }
}</code>
  </syntaxhighlight>


The revision node:
The revision node:
<code>


<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 98: Line 116:
       $this->setOrder("rev_table,rev_field,rev_datetime");
       $this->setOrder("rev_table,rev_field,rev_datetime");
       $this->setTable("revision");
       $this->setTable("revision");
     }
     }
   }</code>
    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

Complexity: Expert
Author: Olav B. Lygre <soppel at lygre dot no>

List of other Howto's

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.