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'); }