Page 1 of 1

How to easily implement (faux) multi-user record locking

PostPosted: Sun Oct 21, 2012 7:44 pm
by auphi
Hey all,

It is possible that this already exists somewhere, but after spending hours searching I was unable to find a satisfactory answer and wanted to share the solution that I came up with (since it took me a while to work out). There is no need to add a separate "last modified" column to your tables, as Xataface already stores that information in the dataface__record_mtimes table. You will need to add this code into the delegate class for each of the tables that you want to provide locking on.

In the table's delegate class (i.e. in the 'tablename'.php file), add
Code: Select all
   //Create a new hidden timestamp field with the page load time at the end of the form.
   function block__before_form_close_tag(){
      echo '<input name="timestamp" id="timestamp" type="hidden" value="'.time().'" data-xf-field="timestamp" />';
   }

   //Check if the data has been saved after we have already loaded the page, before overwriting, if so, return an error!
   function beforeSave(&$record){
      $recid = $record->getID(); //Get the record ID
      $rec = df_get_record('dataface__record_mtimes', array('recordid'=>$recid)); //Pull the last modified time from the dataface record
      $timestamp = $_POST['timestamp'];
      if($rec->display('mtime') > $timestamp) //Check to see if the last modified time is greater than the page load time
      {
         $msg = "ERROR: It appears that someone has recently modified this record, and your changes could not be saved. Here is the current record. Please re-enter your changes and try saving again.";
         header('Location: '.$record->getURL('-action=edit').'&--msg='.urlencode($msg)); //Reload the page so that the fields update.
         return PEAR::raiseError('',DATAFACE_E_NOTICE); //Return an error and don't save the record.
      }
   }


Voila! (You can test this by opening two copies of the same record in different tabs. Save one, and then try and save the other. You should receive the error message and the record will not be saved.)

Note that time() returns the current Unix timestamp in seconds. I used this because it is the format that Xataface stores its record information in, thus I didn't need to add a new "last modified" column to every table. That being the case, if two people both try and update the same record at the exact same time (ie. < 1 second apart) one record will still end up overwriting the other like it would have otherwise. If this is a concern for you, I would suggest adding a "last modified" column to all of your tables, and using microtime() for saving your "page load time" and "last modified" timestamps (and then of course you will have to modify this code a bit).

Re: How to easily implement (faux) multi-user record locking

PostPosted: Fri Oct 26, 2012 8:40 am
by shannah
Great solution. I have been planning on adding some record versioning features to Xataface (which could be used to accomplish this) but have never gotten around to it.