<?php
require_once('Driver.php');
require_once('MDB2.php');
/**
* A driver that use MDB2 as data store
*/
class AJAX_Locking_Driver_MDB2 extends AJAX_Locking_Driver
{
/**
* Instance of a MDB2 connection
*
* @var MBD2 connection
*/
var $mdb2;
/**
* Default table and columns names
*
* @var array
*/
var $names = array(
'table' => 'ajax_locks',
'columns' => array(
'type' => 'type',
'id' => 'id',
'user' => '[user]',
'time' => '[time]'
)
);
/**
* Constructor
*
* @param mixed $dsn DSN for MDB2 connection
* @param array $names names of table and its columns where store data
* @param int $timeout session timeout
* @return AJAX_Locking_Driver
*/
function AJAX_Locking_Driver_MDB2($dsn = false, $names = false, $timeout = false)
{
parent::AJAX_Locking_Driver($timeout);
$this->mdb2 =& MDB2::factory($dsn);
if (PEAR::isError($this->mdb2)) {
die($this->mdb2->getMessage());
}
// eventually override default names of table and columns
if ($names && is_array($names)) {
$names['columns'] = array_merge($this->names['columns'], $names['columns']);
$this->names = array_merge($this->names, $names);
}
}
/**
* Locks an object
*
* @param mixed $user id of the user who wants to lock
* @param string $type type/classname of the object
* @param mixed $id id of the object
* @return boolean true if the unlock was successfull, false otherwise
*/
function lock($user, $type, $id)
{
$result = false;
$this->mdb2->beginTransaction();
$sql = $this->_getStatusSQL($type, $id);
$rs = $this->mdb2->query($sql);
if (PEAR::isError($rs)) {
die($rs->getMessage());
}
$row = $rs->fetchRow();
if (!$row) {
// object is unlocked: lock it
$sql = $this->_getLockSQL($user, $type, $id);
$affected =& $this->mdb2->exec($sql);
if (PEAR::isError($affected)) {
die($affected->getMessage());
}
$result = true;
} else {
// object is locked: check if lock expired
$time = $row[3];
if (time() - $time > $this->timeout) {
// lock expired: remove it and lock
$sql = $this->_getUnlockSQL($type, $id);
$this->mdb2->exec($sql);
$sql = $this->_getLockSQL($user, $type, $id);
$this->mdb2->exec($sql);
$result = true;
} else {
// object properly locked by (another?) user
$result = ($owner == $user);
}
}
$this->mdb2->commit();
return $result;
}
/**
* Unlocks an object
*
* @param mixed $user id of the user who wants to unlock
* @param string $type type/classname of the object
* @param mixed $id id of the object
* @return boolean true if the unlock was successfull, false otherwise
*/
function unlock($user, $type, $id)
{
$result = false;
$this->mdb2->beginTransaction();
$sql = $this->_getStatusSQL($type, $id);
$rs = $this->mdb2->query($sql);
if (PEAR::isError($rs)) {
die($rs->getMessage());
}
$row = $rs->fetchRow();
if (!$row) {
// object was not locked
$result = false;
} else {
// check if user is owner of the lock
$owner = $row[2];
if ($user == $owner) {
// unlock it
$sql = $this->_getUnlockSQL($type, $id);
$this->mdb2->exec($sql);
$result = true;
} else {
// user cannot unlock it
$result = false;
}
}
$this->mdb2->commit();
return $result;
}
/**
* Returns the status of the object (lock or unlocked)
*
* @param mixed $user id of the user who wants to know the object's status
* @param string $type type/classname of the object
* @param mixed $id id of the object
* @return string the status and the owner of the object
*/
function status($user, $type, $id)
{
$result = "~";
$this->mdb2->beginTransaction();
$sql = $this->_getStatusSQL($type, $id);
$rs = $this->mdb2->query($sql);
if (PEAR::isError($rs)) {
die($rs->getMessage());
}
$row = $rs->fetchRow();
if (!$row) {
// object is unlocked
$result = AJAX_LOCKING_UNLOCKED . '~' . 'noboby';
} else {
// object is locked:
// 1. check if current user is owner of the lock
// 2. check if lock expired
$owner = $row[2]; $time = $row[3];
$timeout = (time() - $time > $this->timeout);
if ($owner == $user) {
if ($timeout) {
// lock expired: remove it and inform it's ower
$sql = $this->_getUnlockSQL($type, $id);
$this->mdb2->exec($sql);
$result = AJAX_LOCKING_TIMEOUT . '~' . $owner;
} else {
$result = AJAX_LOCKING_OWNED . '~' . $owner;
}
} else {
if ($timeout) {
// lock expired: remove it
$sql = $this->_getUnlockSQL($type, $id);
$this->mdb2->exec($sql);
$result = AJAX_LOCKING_UNLOCKED . '~' . 'nobody';
} else {
$result = AJAX_LOCKING_LOCKED . '~' . $owner;
}
}
}
$this->mdb2->commit();
return $result;
}
/**
* Returns the list of all active locks for administration purpose
*
* @return array of locks (owner, type, id), false if not implemented
*/
function getLocks()
{
$locks = array();
$sql = $this->_getListSQL($type, $id);
$rs = $this->mdb2->query($sql);
if (PEAR::isError($rs)) {
die($rs->getMessage());
}
while (($row = $rs->fetchRow())) {
list($owner, $type, $id, $time) = $row;
$timeout = (time() - $time > $this->timeout);
if (!$timeout) {
$locks[] = array(
'owner' => $owner,
'type' => $type,
'id' => $id
);
}
}
return $locks;
}
/**
* Administrately delete lock
*
* @param string $type
* @param mixed $id
*
* @return true if the lock is deleted successfully, false otherwise
*/
function deleteLock($type, $id)
{
$sql = $this->_getUnlockSQL($type, $id);
return $this->mdb2->exec($sql);
}
function _getStatusSQL($type, $id)
{
$sql = sprintf("select * from %s where %s = %s and %s = %s",
$this->names['table'],
$this->names['columns']['type'], $this->mdb2->quote($type),
$this->names['columns']['id'], $this->mdb2->quote($id));
return $sql;
}
function _getLockSQL($user, $type, $id)
{
$timestamp = time();
$sql = sprintf("insert into %s (%s, %s, %s, %s) values(%s, %s, %s, %s)",
$this->names['table'],
$this->names['columns']['type'], $this->names['columns']['id'], $this->names['columns']['user'], $this->names['columns']['time'],
$this->mdb2->quote($type),
$this->mdb2->quote($id),
$this->mdb2->quote($user),
$timestamp);
return $sql;
}
function _getUnlockSQL($type, $id)
{
$sql = sprintf("delete from %s where %s = %s and %s = %s",
$this->names['table'],
$this->names['columns']['type'], $this->mdb2->quote($type),
$this->names['columns']['id'], $this->mdb2->quote($id));
return $sql;
}
function _getListSQL($type, $id)
{
$sql = sprintf("select * from %s",
$this->names['table']);
return $sql;
}
}
?>