<?php // -*- tab-width: 3; indent-tabs-mode: 1; -*-
/*
* $Id: sotf_ComplexNodeObject.class.php,v 1.35 2005/01/06 10:22:48 micsik Exp $
*
* Created for the StreamOnTheFly project (IST-2001-32226)
* Authors: András Micsik, Máté Pataki, Tamás Déri
* at MTA SZTAKI DSD, http://dsd.sztaki.hu
*/
class sotf_ComplexNodeObject extends sotf_NodeObject {
/** constructor */
function sotf_ComplexNodeObject($tablename, $id='', $data='') {
$this->sotf_NodeObject($tablename, $id, $data);
}
/************************************************
* GENERAL
************************************************/
/** Abstract methods, which should be implemented in all subclasses:*/
//function getDir()
//function getMetaDir()
//function checkDirs
/** overrides function in sotf_NodeObject */
/*
function isLocal() {
$retval = is_dir($this->getDir());
debug("isLocal2", $retval);
return $retval;
}
*/
function create() {
$succ = parent::create();
if($succ) {
$this->checkDirs();
$this->saveMetadataFile();
}
return $succ;
}
function delete() {
global $db;
if($this->isLocal()) {
// delete files from the repository
debug("deleting: ", $this->getDir());
sotf_Utils::erase($this->getDir());
// delete from sql db
// somehow foreign keys do not work in this case, so let's do it by hand:
$db->query("DELETE FROM sotf_object_roles WHERE object_id='" . $this->id . "'");
}
return parent::delete();
}
function update() {
parent::update();
if(parent::isLocal()) {
$this->checkDirs();
$this->saveMetadataFile();
}
}
/** caches icon for object, and adds indicator flag for Smarty templates whether there is an icon */
function getAllWithIcon() {
$retval = $this->getAll();
$retval['icon'] = sotf_Blob::cacheIcon($retval['id']);
return $retval;
}
function cacheIcon() {
return sotf_Blob::cacheIcon($this->id);
}
function getStationId() {
//debug("class", get_class($this));
switch($this->tablename) {
case "sotf_stations":
return $this->id;
default:
return $this->get('station_id');
}
}
/************************************************
* METADATA
************************************************/
function saveMetadataFile() {
global $permissions;
$name = get_class($this);
$name = str_replace("sotf_", "", $name);
$xml = "<$name>";
$xml .= sotf_Utils::writeXML('data', $this->data, 1);
$roles = $this->getRoles();
$xml .= sotf_Utils::writeXML('role', $roles, 1);
$perms = $permissions->listUsersAndPermissions($this->id);
$xml .= sotf_Utils::writeXML('permission', $perms, 1);
$xml = $xml . "\n</$name>\n";
$file = $this->getMetaDir() . '/metadump.xml';
debug("dumping metadata xml in", $file);
$fp = fopen("$file", "w");
fwrite($fp, $xml);
fclose($fp);
return true;
}
/************************************************
* LANGUAGE HACK
************************************************/
/** can be static */
function getLanguagesArray($languages = '') {
if(!$languages)
$languages = $this->get('language');
if(!empty($languages)) {
$langs = explode(',',$languages);
return $langs;
}
return array();
}
/** can be static */
function getLanguagesLocalized($languages = '') {
global $page;
if(!$languages)
$languages = $this->get('language');
if(!empty($languages)) {
$langs = explode(',',$languages);
for($i=0; $i<count($langs); $i++) {
if($i>0)
$lstring .= ', ';
$lstring .= $page->getlocalized($langs[$i]);
}
}
debug("lstring", $lstring);
return $lstring;
}
// language hack
function setLanguageWithParams() {
$langs = sotf_Utils::getParameter('language1');
$l2 = sotf_Utils::getParameter('language2');
$l3 = sotf_Utils::getParameter('language3');
if($l2) {
$langs .= ",$l2";
if($l3) {
$langs .= ",$l3";
}
}
$this->set('language', $langs);
}
function getLanguageSelectBoxes() {
global $smarty, $config, $page;
for($i=0; $i<count($config['languages']); $i++) {
$langNames[$config['languages'][$i]] = $page->getlocalized($config['languages'][$i]);
}
asort($langNames);
$smarty->assign('LANG_CODES', array_keys($langNames));
$smarty->assign('LANG_NAMES', array_values($langNames));
$langs = explode(',',$this->get('language'));
$smarty->assign('PRG_LANG1', $langs[0]);
$smarty->assign('PRG_LANG2', $langs[1]);
$smarty->assign('PRG_LANG3', $langs[2]);
}
function get2LetterLanguageCode($languages = '') {
if(!$languages)
$languages = $this->get('language');
if(!empty($languages)) {
$langs = explode(',',$languages);
switch($langs[0]) {
case 'eng': return 'en';
case 'ger':
case 'deu': return 'de';
case 'hun': return 'hu';
case 'fra': return 'fr';
case 'dut': return 'nl';
default:
return '';
logError("Unknown translation to 2-letter code: " . $langs[0]);
}
} else {
return 'en';
}
}
/************************* ROLE MANAGEMENT **************************************/
/** Retrieves roles and contacts associated with this object */
function getRoles($language='') {
global $db, $vocabularies, $lang, $repository;
if(empty($language))
$language = $lang;
$roles = $db->getAll("SELECT id, contact_id, role_id FROM sotf_object_roles WHERE object_id='$this->id' ORDER BY role_id, contact_id");
for($i=0; $i<count($roles); $i++) {
$cobj = & $repository->getObject($roles[$i]['contact_id']);
if($cobj) {
$roles[$i]['role_name'] = $vocabularies->getRoleName($roles[$i]['role_id'], $language);
$roles[$i]['creator'] = $vocabularies->isCreator($roles[$i]['role_id']);
$roles[$i]['contact_data'] = $cobj->getAllWithIcon();
if(hasPerm($roles[$i]['contact_id'], 'change')) {
$roles[$i]['change_contact'] = 1;
}
} else {
logError("Referred contact does not exist: " . $roles[$i]['contact_id']);
unset($roles[$i]);
}
}
return $roles;
}
/** Retrieves roles and contacts associated with this object */
function getCreators() {
global $db;
$creators = $db->getAssoc("SELECT c.* FROM sotf_contacts c, sotf_object_roles o, sotf_roles r WHERE c.id = o.contact_id AND o.role_id=r.role_id AND r.creator='t' AND o.object_id='$this->id' ORDER BY c.name", false, null, DB_FETCHMODE_ASSOC, false);
return $creators;
}
function getCreatorNames() {
$creators = $this->getCreators();
$first = true;
foreach($creators as $creator) {
if($first)
$first = false;
else
$names .= ', ';
$names .= $creator['name'];
}
return $names;
}
/** Static: finds the id for a given role (if exists). */
function findRole($objectId, $contactId, $roleId) {
global $db;
$id = $db->getOne("SELECT id FROM sotf_object_roles WHERE object_id='$objectId' AND contact_id='$contactId' AND role_id='$roleId' ");
return $id;
}
/** Adds a new role/contact to the object. */
function addRole($contactId, $roleId) {
$ro = new sotfNodeObject("sotf_object_roles");
$ro->set('contact_id', $contactId);
$ro->set('role_id', $roleId);
$ro->create();
return $ro->id;
}
/** Changes an existing role/contact pair. */
function changeRole($id, $contactId, $roleId) {
$ro = new sotfNodeObject("sotf_object_roles", $id);
$ro->set('contact_id', $contactId);
$ro->set('role_id', $roleId);
$ro->update();
}
//********************** ICON management ***********************************
/** Gets icon of the thing. Returns binary string containing the logo. */
function getIcon()
{
return sotf_Blob::findBlob($this->id, 'icon');
}
/** Deletes icon of the thing */
function deleteIcon() {
if(!$this->isLocal())
raiseError("operation_for_local_objects_only");
sotf_Blob::saveBlob($this->id, 'icon','');
$iconFile = $this->getMetaDir() . '/icon.png';
if(is_readable($iconFile)) {
if(!unlink($iconFile))
addError("Could not delete icon file!");
}
}
/**
* Sets icon for object.
*
* @param object $file pathname of file
* @return boolean True if the function succeeded, else false
*/
function setIcon($file)
{
global $config;
$tmpfile = $config['tmpDir'].'/'.time().".png";
$succ = $this->prepareIcon($file, $tmpfile, $config['iconWidth'], $config['iconHeight']);
if (!$succ) {
addError("Could not resize image");
//return false;
} else {
if ($fp = fopen($tmpfile,'rb')) {
$data = fread($fp,filesize($tmpfile));
fclose($fp);
// save into DB
sotf_Blob::saveBlob($this->id, "icon", $data);
// save into file system
$iconFile = $this->getMetaDir() . '/icon.png';
sotf_Utils::save($iconFile, $data);
} else
addError("could not open icon file!");
}
if(is_file($tmpfile)) {
debug("remove tmpfile", $tmpfile);
unlink($tmpfile);
}
sotf_Blob::uncacheIcon($this->id);
return true;
} // end func setIcon
/** Resizes the given image 'imgfile', converts it into PNG and puts it into 'newfile'. */
function prepareIcon($imgfile, $newfile, $iconWidth = 100, $iconHeight = 100) {
global $config;
if ($imgfile == "") {
raiseError("No image file specified");
return false;
}
if (!file_exists($imgfile)) {
raiseError("File does not exist: $imgfile");
return false;
}
//$info = GetAllFileInfo($file->getPath());
//if (($info['png']['width'] == $iconWidth) && ($info['png']['height'] == $iconHeight))
debug("imgfile", $imgfile);
$currentimagesize = getimagesize($imgfile);
if(!$currentimagesize || ($currentimagesize[0]==0 && $currentimagesize[1]==0)) {
addError("not_an_image");
return false;
}
$image_width = $currentimagesize[0];
$image_height= $currentimagesize[1];
$sizefactor = 1;
// TODO: convert to PNG!!
if(($image_height == $iconHeight) && ($image_width == $iconWidth)) {
if(!copy($imgfile, $newfile))
raiseError("Could not copy image file");
return true;
}
if (($image_height > $iconHeight) || ($image_width > $iconWidth))
{
$sizefactor = min((double)($iconHeight / $image_height), (double)($iconWidth / $image_width));
}
$newwidth = (int) ($image_width * $sizefactor);
$newheight = (int) ($image_height * $sizefactor);
$newsize = $newwidth . "x" . $newheight;
debug("resizing image", $newsize);
$cmd = '"' . $config['magickDir'] . "/convert\" $imgfile -resize $newsize $newfile 2>&1";
debug("resize command", $cmd);
exec($cmd, $exec_output, $exec_retval);
if($exec_retval > 0) {
logError("img resize error", join("\n",$exec_output));
return false;
}
debug("Image was resized from ".$image_width."x".$image_height." to", $newsize);
return true;
}
//********************** JINGLE management ***********************************
/**
* Sets jingle of the station.
* @use $config['audioFormats']
*/
function setJingle($filename, $copy=false) {
global $config, $page;
$source = $filename;
if(!is_file($source))
raiseError("no such file: $source");
$srcFile = new sotf_AudioFile($source);
$target = $this->getMetaDir() . '/jingle_' . $srcFile->getFormatFilename();
debug("jingle file", $target);
if($srcFile->type != 'audio')
raiseError("this is not an audio file");
if(is_file($target)) {
raiseError($page->getlocalized('format_already_present'));
}
if($copy)
$success = copy($source,$target);
else
$success = rename($source,$target);
if(!$success)
raiseError("could not copy/move $source");
return true;
//TODO? save into database
}
/**
* Gets a jingle of the station.
*
* @param integer $index Format index of the jingle in the $config['audioFormats'] global variable
* @return mixed Returns the path of the jingle if exist, else return boolean false
* @use $config['audioFormats']
*/
function getJingle($index = 0) {
global $config;
$file = $this->getMetaDir() . '/jingle_' . sotf_AudioCheck::getFormatFilename($index);
debug("searching for", $file);
if (is_file($file) && !is_file($file.'.lock')) {
return $file;
}
$file = '';
$jdir = $this->getMetaDir();
if(is_dir($jdir)) {
$d = dir($jdir);
while($entry = $d->read()) {
if (substr($entry, 0, 6) == 'jingle_') {
$file = $jdir . '/' . $entry;
break;
}
}
$d->close();
}
debug("2nd round", $file);
if($file)
return $file;
else
return false;
}
/** Deletes a jingle */
function deleteJingle($file, $index='') {
if(!preg_match("/^jingle/", $file))
raiseError("Invalid filename");
$file = sotf_Utils::getFileInDir($this->getMetaDir(), $file);
debug("delete file", $file);
if(!unlink($file)) {
addError("Could not delete jingle $index!");
}
// TODO: delete from SQL???
}
}