diff --git a/livesupport/modules/storageServer/var/BasicStor.php b/livesupport/modules/storageServer/var/BasicStor.php
index c01c223f7..1fc93e3d0 100644
--- a/livesupport/modules/storageServer/var/BasicStor.php
+++ b/livesupport/modules/storageServer/var/BasicStor.php
@@ -23,7 +23,7 @@
Author : $Author: tomas $
- Version : $Revision: 1.27 $
+ Version : $Revision: 1.28 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/BasicStor.php,v $
------------------------------------------------------------------------------*/
@@ -52,7 +52,7 @@ require_once "Transport.php";
* Core of LiveSupport file storage module
*
* @author $Author: tomas $
- * @version $Revision: 1.27 $
+ * @version $Revision: 1.28 $
* @see Alib
*/
class BasicStor extends Alib{
@@ -269,10 +269,30 @@ class BasicStor extends Alib{
return ($cnt == 1);
}
+ /**
+ * Get gunid from token
+ *
+ * @param token string, access/put token
+ * @param type string 'put'|'access'|'download'
+ * @return string
+ */
+ function _gunidFromToken($token, $type='put')
+ {
+ $acc = $this->dbc->getRow("
+ SELECT to_hex(gunid)as gunid, ext FROM {$this->accessTable}
+ WHERE token=x'{$token}'::bigint AND type='$type'
+ ");
+ if(PEAR::isError($acc)){ return $acc; }
+ $gunid = StoredFile::_normalizeGunid($acc['gunid']);
+ if(PEAR::isError($gunid)){ return $gunid; }
+ return $gunid;
+ }
+
/**
* Create and return access link to real file
*
* @param realFname string, local filepath to accessed file
+ * (NULL for only increase access counter, no symlink)
* @param ext string, useful filename extension for accessed file
* @param gunid int, global unique id
* @param type string 'access'|'download'
@@ -281,16 +301,18 @@ class BasicStor extends Alib{
function bsAccess($realFname, $ext, $gunid, $type='access')
{
$token = StoredFile::_createGunid();
- $linkFname = "{$this->accessDir}/$token.$ext";
- if(!file_exists($realFname)){
- return PEAR::raiseError(
- "BasicStor::bsAccess: real file not found ($realFname)",
- GBERR_FILEIO);
- }
- if(! @symlink($realFname, $linkFname)){
- return PEAR::raiseError(
- "BasicStor::bsAccess: symlink create failed ($linkFname)",
- GBERR_FILEIO);
+ if(!is_null($realFname)){
+ $linkFname = "{$this->accessDir}/$token.$ext";
+ if(!file_exists($realFname)){
+ return PEAR::raiseError(
+ "BasicStor::bsAccess: real file not found ($realFname)",
+ GBERR_FILEIO);
+ }
+ if(! @symlink($realFname, $linkFname)){
+ return PEAR::raiseError(
+ "BasicStor::bsAccess: symlink create failed ($linkFname)",
+ GBERR_FILEIO);
+ }
}
$this->dbc->query("BEGIN");
$res = $this->dbc->query("
@@ -334,7 +356,7 @@ class BasicStor extends Alib{
$ext = $acc['ext'];
$gunid = StoredFile::_normalizeGunid($acc['gunid']);
$linkFname = "{$this->accessDir}/$token.$ext";
- if(! @unlink($linkFname)){
+ if(file_exists($linkFname)) if(! @unlink($linkFname)){
return PEAR::raiseError(
"BasicStor::bsRelease: unlink failed ($linkFname)",
GBERR_FILEIO);
@@ -839,7 +861,7 @@ class BasicStor extends Alib{
return TRUE;
}
- /* ==================================================== "private" methods */
+ /* ================================================== "protected" methods */
/**
* Check authorization - auxiliary method
*
@@ -944,7 +966,51 @@ class BasicStor extends Alib{
return TRUE;
}
- /* ------------------------------------------ redefined "private" methods */
+ /**
+ * Returns if gunid is free
+ *
+ */
+ function _gunidIsFree($gunid)
+ {
+ $cnt = $this->dbc->getOne("
+ SELECT count(*) FROM {$this->filesTable}
+ WHERE gunid=x'{$this->gunid}'::bigint
+ ");
+ if(PEAR::isError($cnt)) return $cnt;
+ if($cnt > 0) return FALSE;
+ return TRUE;
+ }
+
+ /**
+ * Set playlist edit flag
+ *
+ * @param playlistId string, playlist global unique ID
+ * @param val boolean, set/clear of edit flag
+ * @return boolean, previous state
+ */
+ function _setEditFlag($playlistId, $val=TRUE)
+ {
+ $ac =& StoredFile::recallByGunid($this, $playlistId);
+ if(PEAR::isError($ac)) return $ac;
+ $state = $ac->_getState();
+ if($val){ $ac->setState('edited'); }
+ else{ $ac->setState('ready'); }
+ return ($state == 'edited');
+ }
+
+ /**
+ * Check if playlist is marked as edited
+ *
+ * @param playlistId string, playlist global unique ID
+ * @return boolean
+ */
+ function _isEdited($playlistId)
+ {
+ $ac =& StoredFile::recallByGunid($this, $playlistId);
+ return $ac->isEdited($playlistId);
+ }
+
+ /* ---------------------------------------- redefined "protected" methods */
/**
* Copy virtual file.
* Redefined from parent class.
diff --git a/livesupport/modules/storageServer/var/GreenBox.php b/livesupport/modules/storageServer/var/GreenBox.php
index 2bdb76de1..758030ab2 100644
--- a/livesupport/modules/storageServer/var/GreenBox.php
+++ b/livesupport/modules/storageServer/var/GreenBox.php
@@ -23,7 +23,7 @@
Author : $Author: tomas $
- Version : $Revision: 1.31 $
+ Version : $Revision: 1.32 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/GreenBox.php,v $
------------------------------------------------------------------------------*/
@@ -35,7 +35,7 @@ require_once "BasicStor.php";
* LiveSupport file storage module
*
* @author $Author: tomas $
- * @version $Revision: 1.31 $
+ * @version $Revision: 1.32 $
* @see BasicStor
*/
class GreenBox extends BasicStor{
@@ -109,6 +109,39 @@ class GreenBox extends BasicStor{
return $oid;
}
+
+ /**
+ * Access stored file - increase access counter
+ *
+ * @param id int, virt.file's local id
+ * @param sessid string, session id
+ * @return string access token
+ */
+ function accessFile($id, $sessid='')
+ {
+ if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE)
+ return $res;
+ $gunid = $this->_gunidFromId($id);
+ $r = $this->bsAccess(NULL, '', $gunid, 'access');
+ if(PEAR::isError($r)){ return $r; }
+ $token = $r['token'];
+ return $token;
+ }
+
+ /**
+ * Release stored file - decrease access counter
+ *
+ * @param token string, access token
+ * @param sessid string, session id
+ * @return boolean
+ */
+ function releaseFile($token, $sessid='')
+ {
+ $r = $this->bsRelease($token, 'access');
+ if(PEAR::isError($r)){ return $r; }
+ return FALSE;
+ }
+
/**
* Analyze media file for internal metadata information
*
@@ -355,31 +388,326 @@ class GreenBox extends BasicStor{
* Create a new empty playlist.
*
* @param sessid string, session ID
- * @param playlistId string, playlist global unique ID
+ * @param gunid string, playlist global unique ID
* @param fname string, human readable menmonic file name
* @return string, playlist global unique ID
*/
- function createPlaylist($sessid, $playlistId, $fname)
+ function createPlaylist($sessid, $gunid, $fname)
{
require_once"LocStor.php";
$lc =& new LocStor($this->dbc, $this->config);
- return $lc->createPlaylist($sessid, $playlistId, $fname);
+ return $lc->createPlaylist($sessid, $gunid, $fname);
}
+ /**
+ * Return playlist as XML string
+ *
+ * @param sessid string, session ID
+ * @param id int, local object id
+ * @return string, XML
+ */
+ function getPlaylistXml($sessid, $id)
+ {
+ return $this->getMdata($id, $sessid);
+ }
+
+ /**
+ * Return playlist as hierarchical PHP hash-array
+ *
+ * @param sessid string, session ID
+ * @param id int, local object id
+ * @return array
+ */
+ function getPlaylistArray($sessid, $id)
+ {
+ $gunid = $this->_gunidFromId($id);
+ $pl =& StoredFile::recall($this, $id);
+ if(PEAR::isError($pl)){ return $pl; }
+ $gunid = $pl->gunid;
+ return $pl->md->genPhpArray();
+ }
+
+ /**
+ * Mark playlist as edited and return edit token
+ *
+ * @param sessid string, session ID
+ * @param id int, local object id
+ * @return string, playlist access token
+ */
+ function lockPlaylistForEdit($sessid, $id)
+ {
+ $gunid = $this->_gunidFromId($id);
+ require_once"LocStor.php";
+ $lc =& new LocStor($this->dbc, $this->config);
+ $res = $lc->editPlaylist($sessid, $gunid);
+ if(PEAR::isError($res)) return $res;
+ return $res['token'];
+ }
+
+ /**
+ * Release token, regenerate XML from DB and clear edit flag.
+ *
+ * @param sessid string, session ID
+ * @param token string, playlist access token
+ * @return string gunid
+ */
+ function releaseLockedPlaylist($sessid, $token)
+ {
+ $gunid = $this->bsCloseDownload($token, 'metadata');
+ if(PEAR::isError($gunid)) return $gunid;
+ $ac =& StoredFile::recallByGunid($this, $gunid);
+ if(PEAR::isError($ac)){ return $ac; }
+ $r = $ac->md->regenerateXmlFile();
+ if(PEAR::isError($r)) return $r;
+ $this->_setEditFlag($gunid, FALSE);
+ return $gunid;
+ }
+
+ /**
+ * Add audioclip specified by gunid to the playlist
+ *
+ * @param sessid string, session ID
+ * @param token string, playlist access token
+ * @param acGunid string, global unique ID of added file
+ * @return string, generated playlistElement gunid
+ */
+ function addAudioClipToPlaylist($sessid, $token, $acGunid)
+ {
+ $plGunid = $this->_gunidFromToken($token, 'download');
+ if(PEAR::isError($plGunid)) return $plGunid;
+ if(is_null($plGunid)){
+ return PEAR::raiseError(
+ "GreenBox::addClipToPlaylist: invalid token"
+ );
+ }
+ $pl =& StoredFile::recallByGunid($this, $plGunid);
+ if(PEAR::isError($pl)){ return $pl; }
+ $id = $pl->getId();
+ // get playlist length and record id:
+ $r = $pl->md->getMetadataEl('dcterms:extent');
+ if(PEAR::isError($r)){ return $r; }
+ $plLen = $r[0]['value'];
+ $plLenMid = $r[0]['mid'];
+ if(is_null($plLen)) $plLen = '00:00:00.000000';
+
+ // get audioClip legth and title
+ $ac =& StoredFile::recallByGunid($this, $acGunid);
+ if(PEAR::isError($ac)){ return $ac; }
+ $r = $ac->md->getMetadataEl('dcterms:extent');
+ if(PEAR::isError($r)){ return $r; }
+ $acLen = $r[0]['value'];
+ $r = $ac->md->getMetadataEl('dc:title');
+ if(PEAR::isError($r)){ return $r; }
+ $acTit = $r[0]['value'];
+
+ // get main playlist container
+ $r = $pl->md->getMetadataEl('playlist');
+ if(PEAR::isError($r)){ return $r; }
+ $parid = $r[0]['mid'];
+ if(is_null($parid)){
+ return PEAR::raiseError(
+ "GreenBox::addClipToPlaylist: can't find main container"
+ );
+ }
+ // get metadata container (optionally insert it)
+ $r = $pl->md->getMetadataEl('metadata');
+ if(PEAR::isError($r)){ return $r; }
+ $metaParid = $r[0]['mid'];
+ if(is_null($metaParid)){
+ $r = $pl->md->insertMetadataEl($parid, 'metadata');
+ if(PEAR::isError($r)){ return $r; }
+ $metaParid = $r;
+ }
+
+ // insert new palylist element
+ $r = $pl->md->insertMetadataEl($parid, 'playlistElement');
+ if(PEAR::isError($r)){ return $r; }
+ $plElId = $r;
+ $plElGunid = StoredFile::_createGunid();
+ $r = $pl->md->insertMetadataEl($plElId, 'id', $plElGunid, 'A');
+ if(PEAR::isError($r)){ return $r; }
+ $r = $pl->md->insertMetadataEl(
+ $plElId, 'relativeOffset', $plLen, 'A');
+ if(PEAR::isError($r)){ return $r; }
+ $r = $pl->md->insertMetadataEl($plElId, 'audioClip');
+ if(PEAR::isError($r)){ return $r; }
+ $acId = $r;
+ $r = $pl->md->insertMetadataEl($acId, 'id', $acGunid, 'A');
+ if(PEAR::isError($r)){ return $r; }
+ $r = $pl->md->insertMetadataEl($acId, 'playlength', $acLen, 'A');
+ if(PEAR::isError($r)){ return $r; }
+ $r = $pl->md->insertMetadataEl($acId, 'title', $acTit, 'A');
+ if(PEAR::isError($r)){ return $r; }
+ // calculate and insert total length:
+ $newPlLen = $this->_secsToPlTime(
+ $this->_plTimeToSecs($plLen) + $this->_plTimeToSecs($acLen)
+ );
+ if(is_null($plLenMid)){
+ $r = $pl->md->insertMetadataEl(
+ $metaParid, 'dcterms:extent', $newPlLen);
+ }else{
+ $r = $pl->md->setMetadataEl($plLenMid, $newPlLen);
+ }
+ if(PEAR::isError($r)){ return $r; }
+ // set access to audio clip:
+ $r = $this->bsAccess(NULL, '', $acGunid, 'access');
+ if(PEAR::isError($r)){ return $r; }
+ $acToken = $r['token'];
+ // insert token attribute:
+ $r = $pl->md->insertMetadataEl($acId, 'accessToken', $acToken, 'A');
+ if(PEAR::isError($r)){ return $r; }
+ return $plElGunid;
+ }
+
+ /**
+ * Remove audioclip from playlist
+ *
+ * @param sessid string, session ID
+ * @param token string, playlist access token
+ * @param plElGunid string, global unique ID of deleted playlistElement
+ * @return boolean
+ */
+ function delAudioClipFromPlaylist($sessid, $token, $plElGunid)
+ {
+ $plGunid = $this->_gunidFromToken($token, 'download');
+ if(PEAR::isError($plGunid)) return $plGunid;
+ if(is_null($plGunid)){
+ return PEAR::raiseError(
+ "GreenBox::addClipToPlaylist: invalid token"
+ );
+ }
+ $pl =& StoredFile::recallByGunid($this, $plGunid);
+ if(PEAR::isError($pl)){ return $pl; }
+ $id = $pl->getId();
+
+ // get main playlist container:
+ $r = $pl->md->getMetadataEl('playlist');
+ if(PEAR::isError($r)){ return $r; }
+ $parid = $r[0]['mid'];
+ if(is_null($parid)){
+ return PEAR::raiseError(
+ "GreenBox::addClipToPlaylist: can't find main container"
+ );
+ }
+ // get playlist length and record id:
+ $r = $pl->md->getMetadataEl('dcterms:extent');
+ if(PEAR::isError($r)){ return $r; }
+ $plLen = $r[0]['value'];
+ $plLenMid = $r[0]['mid'];
+ // get array of playlist elements:
+ $plElArr = $pl->md->getMetadataEl('playlistElement', $parid);
+ if(PEAR::isError($plElArr)){ return $plElArr; }
+ $found = FALSE;
+ foreach($plElArr as $el){
+ $plElGunidArr = $pl->md->getMetadataEl('id', $el['mid']);
+ if(PEAR::isError($plElGunidArr)){ return $plElGunidArr; }
+ // select playlist element to remove
+ if($plElGunidArr[0]['value'] == $plElGunid){
+ $acArr = $pl->md->getMetadataEl('audioClip', $el['mid']);
+ if(PEAR::isError($acArr)){ return $acArr; }
+ $acLenArr = $pl->md->getMetadataEl('playlength', $acArr[0]['mid']);
+ if(PEAR::isError($acLenArr)){ return $acLenArr; }
+ $acLen = $acLenArr[0]['value'];
+ $acTokArr = $pl->md->getMetadataEl('accessToken', $acArr[0]['mid']);
+ if(PEAR::isError($acTokArr)){ return $acTokArr; }
+ $acToken = $acTokArr[0]['value'];
+ // remove playlist element:
+ $r = $pl->md->setMetadataEl($el['mid'], NULL);
+ if(PEAR::isError($r)){ return $r; }
+ // release audioClip:
+ $r = $this->bsRelease($acToken, 'access');
+ if(PEAR::isError($r)){ return $r; }
+ $found = TRUE;
+ continue;
+ }
+ if($found){
+ // corect relative offsets in remaining elements:
+ $acOffArr = $pl->md->getMetadataEl('relativeOffset', $el['mid']);
+ if(PEAR::isError($acOffArr)){ return $acOffArr; }
+ $newOff = $this->_secsToPlTime(
+ $this->_plTimeToSecs($acOffArr[0]['value'])
+ -
+ $this->_plTimeToSecs($acLen)
+ );
+ $r = $pl->md->setMetadataEl($acOffArr[0]['mid'], $newOff);
+ if(PEAR::isError($r)){ return $r; }
+ }
+ }
+ // correct total length:
+ $newPlLen = $this->_secsToPlTime(
+ $this->_plTimeToSecs($plLen) - $this->_plTimeToSecs($acLen)
+ );
+ $r = $pl->md->setMetadataEl($plLenMid, $newPlLen);
+ if(PEAR::isError($r)){ return $r; }
+ return TRUE;
+ }
+
+ /**
+ * RollBack playlist changes to the locked state
+ *
+ * @param sessid string, session ID
+ * @param token string, playlist access token
+ * @return string gunid of playlist
+ */
+ function revertEditedPlaylist($sessid, $token)
+ {
+ $gunid = $this->bsCloseDownload($token, 'metadata');
+ if(PEAR::isError($gunid)) return $gunid;
+ $ac =& StoredFile::recallByGunid($this, $gunid);
+ if(PEAR::isError($ac)){ return $ac; }
+ $id = $ac->getId();
+ $mdata = $ac->getMetaData();
+ if(PEAR::isError($mdata)){ return $mdata; }
+ $res = $ac->replaceMetaData($mdata, 'string');
+ if(PEAR::isError($res)){ return $res; }
+ $this->_setEditFlag($gunid, FALSE);
+ return $gunid;
+ }
+
+ /**
+ * Convert playlist time value to float seconds
+ *
+ * @param plt string, playlist time value (HH:mm:ss.dddddd)
+ * @return int, seconds
+ */
+ function _plTimeToSecs($plt)
+ {
+ $arr = split(':', $plt);
+ if(isset($arr[2])){ return ($arr[0]*60 + $arr[1])*60 + $arr[2]; }
+ if(isset($arr[1])){ return $arr[0]*60 + $arr[1]; }
+ return $arr[0];
+ }
+
+ /**
+ * Convert float seconds value to playlist time format
+ *
+ * @param s0 int, seconds
+ * @return string, time in playlist time format (HH:mm:ss.dddddd)
+ */
+ function _secsToPlTime($s0)
+ {
+ $m = intval($s0 / 60);
+ $r = $s0 - $m*60;
+ $h = $m / 60;
+ $m = $m % 60;
+ return sprintf("%02d:%02d:%09.6f", $h, $m, $r);
+ }
+
+ /* ---------- */
/**
* Open a Playlist metafile for editing.
* Open readable URL and mark file as beeing edited.
*
* @param sessid string, session ID
- * @param playlistId string, playlist global unique ID
+ * @param gunid string, playlist global unique ID
* @return struct
* {url:readable URL for HTTP GET, token:access token, chsum:checksum}
*/
- function editPlaylist($sessid, $playlistId)
+ function editPlaylist($sessid, $gunid)
{
require_once"LocStor.php";
$lc =& new LocStor($this->dbc, $this->config);
- return $lc->editPlaylist($sessid, $playlistId);
+ return $lc->editPlaylist($sessid, $gunid);
}
/**
@@ -388,7 +716,7 @@ class GreenBox extends BasicStor{
* @param sessid string, session ID
* @param playlistToken string, playlist access token
* @param newPlaylist string, new playlist as XML string
- * @return string, playlistId
+ * @return string, gunid
*/
function savePlaylist($sessid, $playlistToken, $newPlaylist)
{
@@ -401,28 +729,28 @@ class GreenBox extends BasicStor{
* Delete a Playlist metafile.
*
* @param sessid string, session ID
- * @param playlistId string, playlist global unique ID
+ * @param gunid string, playlist global unique ID
* @return boolean
*/
- function deletePlaylist($sessid, $playlistId)
+ function deletePlaylist($sessid, $gunid)
{
require_once"LocStor.php";
$lc =& new LocStor($this->dbc, $this->config);
- return $lc->deletePlaylist($sessid, $playlistId);
+ return $lc->deletePlaylist($sessid, $gunid);
}
/**
* Check whether a Playlist metafile with the given playlist ID exists.
*
* @param sessid string, session ID
- * @param playlistId string, playlist global unique ID
+ * @param gunid string, playlist global unique ID
* @return boolean
*/
- function existsPlaylist($sessid, $playlistId)
+ function existsPlaylist($sessid, $gunid)
{
require_once"LocStor.php";
$lc =& new LocStor($this->dbc, $this->config);
- return $lc->existsPlaylist($sessid, $playlistId);
+ return $lc->existsPlaylist($sessid, $gunid);
}
/**
@@ -431,14 +759,14 @@ class GreenBox extends BasicStor{
* beeing edited.
*
* @param sessid string, session ID
- * @param playlistId string, playlist global unique ID
+ * @param gunid string, playlist global unique ID
* @return boolean
*/
- function playlistIsAvailable($sessid, $playlistId)
+ function playlistIsAvailable($sessid, $gunid)
{
require_once"LocStor.php";
$lc =& new LocStor($this->dbc, $this->config);
- return $lc->playlistIsAvailable($sessid, $playlistId);
+ return $lc->playlistIsAvailable($sessid, $gunid);
}
/* ============================================== methods for preferences */
@@ -569,6 +897,5 @@ class GreenBox extends BasicStor{
return $pa;
}
- /* ==================================================== "private" methods */
}
?>
\ No newline at end of file
diff --git a/livesupport/modules/storageServer/var/MetaData.php b/livesupport/modules/storageServer/var/MetaData.php
index 23650e238..942519e6d 100644
--- a/livesupport/modules/storageServer/var/MetaData.php
+++ b/livesupport/modules/storageServer/var/MetaData.php
@@ -23,7 +23,7 @@
Author : $Author: tomas $
- Version : $Revision: 1.17 $
+ Version : $Revision: 1.18 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/MetaData.php,v $
------------------------------------------------------------------------------*/
@@ -182,6 +182,89 @@ class MetaData{
return "\n\n";
}
+ /**
+ * Get metadata element value and record id
+ *
+ * @param category string, metadata element name
+ * @param parid int, metadata record id of parent element
+ * @return hash {mid: int - record id, value: metadata alue}
+ */
+ function getMetadataEl($category, $parid=NULL)
+ {
+ // handle predicate namespace shortcut
+ $a = XML_Util::splitQualifiedName(strtolower($category));
+ if(PEAR::isError($a)) return $a;
+ $catNs = $a['namespace'];
+ $cat = $a['localPart'];
+ $cond = "gunid=x'{$this->gunid}'::bigint AND predicate='$cat'";
+ if(!is_null($catNs)) $cond .= " AND predns='$catNs'";
+ if(!is_null($parid)) $cond .= " AND subjns='_I' AND subject='$parid'";
+ $sql = "
+ SELECT id as mid, object as value
+ FROM {$this->mdataTable}
+ WHERE $cond
+ ORDER BY id
+ ";
+ $all = $this->dbc->getAll($sql);
+ if(PEAR::isError($all)) return $all;
+ return $all;
+ }
+
+ /**
+ * Set metadata value / delete metadata record
+ *
+ * @param mid int, metadata record id
+ * @param value string, new metadata value (NULL for delete)
+ * @return boolean
+ */
+ function setMetadataEl($mid, $value=NULL)
+ {
+ if(!is_null($value)){
+ $sql = "
+ UPDATE {$this->mdataTable}
+ SET object='$value'
+ WHERE id={$mid}
+ ";
+ $res = $this->dbc->query($sql);
+ }else{
+ $res = $this->deleteRecord($mid);
+ }
+ if(PEAR::isError($res)) return $res;
+ return TRUE;
+ }
+
+ /**
+ * Insert new metadata element
+ *
+ * @param parid int, metadata record id of parent element
+ * @param category string, metadata element name
+ * @param value string, new metadata value (NULL for delete)
+ * @param predxml srring, 'T' | 'A' | 'N' (tag, attr., namespace)
+ * @return int, new metadata record id
+ */
+ function insertMetadataEl($parid, $category, $value=NULL, $predxml='T')
+ {
+ $cnt = $this->dbc->getOne("
+ SELECT count(*) FROM {$this->mdataTable}
+ WHERE gunid=x'{$this->gunid}'::bigint AND id=$parid
+ ");
+ if(PEAR::isError($cnt)) return $cnt;
+ if($cnt < 1){
+ return PEAR::raiseError(
+ "MetaData::insertMetadataEl: container not found"
+ );
+ }
+ $a = XML_Util::splitQualifiedName(strtolower($category));
+ if(PEAR::isError($a)) return $a;
+ $catNs = $a['namespace'];
+ $cat = $a['localPart'];
+ $objns = (is_null($value) ? '_blank' : '_L' );
+ $nid= $this->storeRecord('_I', $parid, $catNs, $cat, $predxml,
+ $objns, $value);
+ if(PEAR::isError($nid)) return $nid;
+ return $nid;
+ }
+
/**
* Get metadata element value
*
@@ -199,24 +282,7 @@ class MetaData{
*/
function getMetadataValue($category, $lang=NULL, $objns='_L')
{
- // handle predicate namespace shortcut
- $a = XML_Util::splitQualifiedName(strtolower($category));
- if(PEAR::isError($a)) return $a;
- $catNs = $a['namespace'];
- $cat = $a['localPart'];
- $cond = "
- gunid=x'{$this->gunid}'::bigint AND objns='$objns' AND
- predicate='$cat'
- ";
- if(!is_null($catNs)) $cond .= " AND predns='$catNs'";
- $sql = "
- SELECT id as mid, object as value
- FROM {$this->mdataTable}
- WHERE $cond
- ORDER BY id
- ";
- $all = $this->dbc->getAll($sql);
- if(PEAR::isError($all)) return $all;
+ $all = $this->getMetadataEl($category);
$res = array();
// add attributes to result
foreach($all as $i=>$rec){
@@ -249,6 +315,7 @@ class MetaData{
function setMetadataValue($category, $value, $lang=NULL, $mid=NULL,
$container='metadata')
{
+ // resolve aktual element:
$rows = $this->getMetadataValue($category, $lang);
$aktual = NULL;
if(count($rows)>1){
@@ -267,36 +334,22 @@ class MetaData{
}
}else $aktual = $rows[0];
if(!is_null($aktual)){
- if(!is_null($value)){
- $sql = "
- UPDATE {$this->mdataTable}
- SET object='$value'
- WHERE id={$aktual['mid']}
- ";
- $res = $this->dbc->query($sql);
- }else{
- $res = $this->deleteRecord($aktual['mid']);
- }
+ $res = $this->setMetadataEl($aktual['mid'], $value);
if(PEAR::isError($res)) return $res;
}else{
+ // resolve container:
$contArr = $this->getMetadataValue($container, NULL, '_blank');
if(PEAR::isError($contArr)) return $contArr;
- $id = $contArr[0]['mid'];
- if(is_null($id)){
+ $parid = $contArr[0]['mid'];
+ if(is_null($parid)){
return PEAR::raiseError(
"MetaData::setMdataValue: container ($container) not found"
);
}
- $a = XML_Util::splitQualifiedName(strtolower($category));
- if(PEAR::isError($a)) return $a;
- $catNs = $a['namespace'];
- $cat = $a['localPart'];
- $nid= $this->storeRecord('_I', $id, $catNs, $cat, $predxml='T',
- '_L', $value);
+ $nid = $this->insertMetadataEl($parid, $category, $value);
if(PEAR::isError($nid)) return $nid;
if(!is_null($lang)){
- $res= $this->storeRecord('_I', $nid, 'xml', 'lang', $predxml='A',
- '_L', $lang);
+ $res = $this->insertMetadataEl($nid, 'xml:lang', $lang, 'A');
if(PEAR::isError($res)) return $res;
}
}
@@ -546,6 +599,29 @@ class MetaData{
}
/* =========================================== XML reconstruction from db */
+ /**
+ * Generate PHP array from metadata database
+ *
+ * @return array with metadata tree
+ */
+ function genPhpArray()
+ {
+ $res = array();
+ $row = $this->dbc->getRow("
+ SELECT * FROM {$this->mdataTable}
+ WHERE gunid=x'{$this->gunid}'::bigint
+ AND subjns='_G' AND subject='{$this->gunid}'
+ ");
+ if(PEAR::isError($row)) return $row;
+ if(is_null($row)){
+ }else{
+ $node = $this->genXMLNode($row, FALSE);
+ if(PEAR::isError($node)) return $node;
+ }
+ $res = $node;
+ return $res;
+ }
+
/**
* Generate XML document from metadata database
*
@@ -580,24 +656,34 @@ class MetaData{
* Generate XML element from database
*
* @param row array, hash with metadata record fields
+ * @param genXML boolean, if TRUE generate XML else PHP array
* @return string, XML serialization of node
*/
- function genXMLNode($row)
+ function genXMLNode($row, $genXML=TRUE)
{
if(DEBUG) echo"genXMLNode:\n";
if(DEBUG) var_dump($row);
extract($row);
- $arr = $this->getSubrows($id);
+ $arr = $this->getSubrows($id, $genXML);
if(PEAR::isError($arr)) return $arr;
if(DEBUG) var_dump($arr);
extract($arr);
- $node = XML_Util::createTagFromArray(array(
- 'namespace' => $predns,
- 'localPart' => $predicate,
- 'attributes'=> $attrs,
-# 'content' => $object." X ".$children,
- 'content' => ($object == 'NULL' ? $children : $object),
- ), FALSE);
+ if($genXML){
+ $node = XML_Util::createTagFromArray(array(
+ 'namespace' => $predns,
+ 'localPart' => $predicate,
+ 'attributes'=> $attrs,
+ 'content' => ($object == 'NULL' ? $children : $object),
+ ), FALSE);
+ }else{
+ $node = array_merge(
+ array(
+ 'elementname' => ($predns ? "$predns:" : '').$predicate,
+ 'content' => $object,
+ 'children'=> $children,
+ ), $arr
+ );
+ }
return $node;
}
@@ -606,12 +692,14 @@ class MetaData{
* one metadata record
*
* @param parid int, local id of parent metadata record
+ * @param genXML boolean, if TRUE generate XML else PHP array for
+ * children
* @return hash with three fields:
* - attr hash, attributes
* - children array, child nodes
* - nSpaces hash, namespace definitions
*/
- function getSubrows($parid)
+ function getSubrows($parid, $genXML=TRUE)
{
if(DEBUG) echo" getSubrows:\n";
$qh = $this->dbc->query($q = "
@@ -641,7 +729,7 @@ class MetaData{
$attrs["{$predns}{$sep}{$predicate}"] = $object;
break;
case"T":
- $children[] = $this->genXMLNode($row);
+ $children[] = $this->genXMLNode($row, $genXML);
break;
default:
return PEAR::raiseError(
@@ -649,7 +737,7 @@ class MetaData{
} // switch
}
$qh->free();
- $children = join(" ", $children);
+ if($genXML) $children = join(" ", $children);
return compact('attrs', 'children', 'nSpaces');
}