<?php
/**
* General purpose indexer.
*
* @package tv2-engine
* @author Emilis Dambauskas (hide@address.com)
* @copyright 20022003 Emilis Dambauskas under {@link http://opensource.org/licenses/artistic-license.php Artistic license}
* @version $Id: ctlIndexer.class.php,v 1.1 2003/07/05 09:46:53 lunaticlt Exp $
* @class ctlIndexer
*/
class ctlIndexer
{
/**
* {@link $db Database}
* @attribute private object $db
*/
var $db;
/**
* Indexes array
* @attribute private array $indices
*/
var $indices;
/**
* Indices table name
* @attribute private string $itable
*/
var $itable;
/**
* Int keys table name
* @attribute private string $ikeys
*/
var $ikeys;
/**
* Float keys table name
* @attribute private string $fkeys
*/
var $fkeys;
/**
* String keys table name
* @attribute private string $skeys
*/
var $skeys;
/**
* String value lists table
* @attribute private string $slists
*/
var $slists;
/**
* Constructor. Links $this->db to {@link $db}, creates empty $this->indices array
*
* @constructor ctlIndexer
* @use $db
*/
function ctlIndexer()
{
$this->indices = array();
$this->db = &$GLOBALS['db'];
}
/**
* Loads indices from table, assignes values to table name attributes
*
* @method public load
* @return boolean TRUE on success, FALSE on failure
* @param array $tables array of table names. Format:
* array('itable'=>'index_table', 'ikeys'=>'int_keys'...)
*/
function load($tables)
{
$this->itable = $tables['itable'];
$this->ikeys = $tables['ikeys'];
$this->fkeys = $tables['fkeys'];
$this->skeys = $tables['skeys'];
$this->slists = $tables['slists'];
$ind = $this->db->getAll("SELECT * FROM $this->itable");
if ($ind === FALSE)
return FALSE;
foreach ($ind as $in)
$this->indices[$in['name']] = array($in['kid'],$in['type']);
return TRUE;
}
/**
* Creates a new index
*
* @method public createIndex
* @return boolean TRUE on success, FALSE on failure
* @param string $iname Index name
* @param optional string $type Index type (one of: <u>string</u>, int, float).
* Default: string
*/
function createIndex($iname, $type = 'string')
{
if (isset($this->indices[$iname]))
return TRUE;
$kid = $this->db->nextId('itable');
if (!$this->db->query("INSERT INTO $this->itable (kid,name,type) VALUES($kid,'$iname','$type')"))
return FALSE;
$this->indices[$iname] = array($kid, $type);
return TRUE;
}
/**
* Removes index
*
* @method public dropIndex
* @return boolean TRUE on success, FALSE on failure
* @param string $iname Index name
*/
function dropIndex($iname)
{
if (!isset($this->indices[$iname]))
return FALSE;
if (!$this->emptyIndex($iname))
return FALSE;
$kid = $this->indices[$iname][0];
if (!$this->db->query("DELETE FROM $this->itable WHERE kid=$kid"))
return FALSE;
unset($this->indices[$iname]);
return TRUE;
}
/**
* Removes values from index
*
* @method public emptyIndex
* @return boolean TRUE on success, FALSE on failure
* @param string $iname Index name
*/
function emptyIndex($iname)
{
$kid = $this->indices[$iname][0];
$type = $this->indices[$iname][1];
switch ($type)
{
case 'int':
return $this->db->query("DELETE FROM $this->ikeys WHERE kid=$kid");
break;
case 'float':
return $this->db->query("DELETE FROM $this->fkeys WHERE kid=$kid");
break;
case 'string':
$lids = $this->db->getCol("SELECT lid FROM $this->skeys WHERE kid=$kid");
if (!$this->db->query("DELETE FROM $this->slists WHERE lid IN (".implode(',',$lids).")"))
return FALSE;
return $this->db->query("DELETE FROM $this->skeys WHERE kid=$kid");
break;
}
return FALSE;
}
/**
* Adds item to index
*
* @method public addItem
* @return boolean TRUE on success, FALSE on failure
* @param int $id item id
* @param string $iname index name
* @param mixed $val item value
*/
function addItem($id, $iname, $val)
{
$kid = @$this->indices[$iname][0];
$type = @$this->indices[$iname][1];
switch ($type)
{
case 'int':
$val = (int) $val;
return $this->db->query("INSERT INTO $this->ikeys (kid,val,id) VALUES($kid,$val,$id)");
break;
case 'float':
$val = (float) $val;
return $this->db->query("INSERT INTO $this->fkeys (kid,val,id) VALUES($kid,$val,$id)");
break;
case 'string':
if (!$lid = $this->db->getOne("SELECT lid FROM $this->skeys WHERE kid=$kid AND val='$val'"))
{
$lid = $this->db->nextId('skeys');
if (!$this->db->query("INSERT INTO $this->skeys (kid,val,lid) VALUES($kid,'$val',$lid)"))
return FALSE;
}
return $this->db->query("INSERT INTO $this->slists (lid,id) VALUES($lid,$id)");
break;
}
return FALSE;
}
/**
* Updates indexed item value
*
* @method public updateItem
* @return boolean TRUE on success, FALSE on failure
* @param int $id item id
* @param string $iname index name
* @param mixed $val item value
*/
function updateItem($id, $iname, $val)
{
$kid = $this->indices[$iname][0];
$type = $this->indices[$iname][1];
switch($type)
{
case 'int':
$val = (int) $val;
return $this->db->query("UPDATE $this->ikeys SET val=$val WHERE kid=$kid AND id=$id");
break;
case 'float':
$val = (float) $val;
return $this->db->query("UPDATE $this->fkeys SET val=$val WHERE kid=$kid AND id=$id");
break;
case 'string':
if (!$this->removeItem($id,$iname))
return FALSE;
return $this->addItem($id,$iname,$val);
break;
}
return FALSE;
}
/**
* Removes item from index tables
*
* @method public removeItem
* @param int $id item id
*/
function removeItem($id)
{
$this->db->query("DELETE FROM $this->ikeys WHERE id=$id");
$this->db->query("DELETE FROM $this->fkeys WHERE id=$id");
$this->db->query("DELETE FROM $this->slists WHERE id=$id");
}
/**
* Returns an array of values stored in index
*
* @method public getValues
* @return mixed array of values on success, FALSE on failure
* @param string $iname Index name
*/
function getValues($iname)
{
$kid = $this->indices[$iname][0];
$type = $this->indices[$iname][1];
switch($type)
{
case 'int':
return $this->db->getCol("SELECT val FROM $this->ikeys WHERE kid=$kid GROUP BY val");
break;
case 'float':
return $this->db->getCol("SELECT val FROM $this->fkeys WHERE kid=$kid GROUP BY val");
break;
case 'string':
return $this->db->getCol("SELECT val FROM $this->skeys WHERE kid=$kid GROUP BY val");
break;
}
return FALSE;
}
/**
* Returns array of item ids indexed by values
*
* @method public getByIndex
* @return mixed array of item indexes or NULL if no values/no index found
* @param string $iname Index name
*/
function getByIndex($iname)
{
$kid = $this->indices[$iname][0];
$type = $this->indices[$iname][1];
switch ($type)
{
case 'int':
$rez = $this->db->getAll("SELECT val,id FROM $this->ikeys WHERE kid=$kid");
break;
case 'float':
$rez = $this->db->getAll("SELECT val,id FROM $this->fkeys WHERE kid=$kid");
break;
case 'string':
$rez = $this->db->getAll("SELECT k.val as val,l.id as id FROM $this->skeys k, $this->slists l WHERE k.kid=$id AND k.lid=l.lid");
break;
}
if (!isset($rez) || !is_array($rez))
return NULL;
foreach ($rez as $r)
$out[$r['val']][] = $r['id'];
return $out;
}
/**
* Returns an array of item ids that have common value
*
* @method public getByValue
* @return mixed array of item ids or FALSE on failure
* @param string $iname index name
* @param mixed $val item value
*/
function getByValue($iname, $val)
{
$kid = @$this->indices[$iname][0];
$type = @$this->indices[$iname][1];
switch ($type)
{
case 'int':
$val = (int) $val;
return $this->db->getCol("SELECT id FROM $this->ikeys WHERE kid=$kid and val=$val");
break;
case 'float':
$val = (float) $val;
return $this->db->getCol("SELECT id FROM $this->fkeys WHERE kid=$kid and val=$val");
break;
case 'string':
$lid = $this->db->getOne("SELECT lid FROM $this->skeys WHERE kid=$kid and val='$val'");
return $this->db->getCol("SELECT id FROM $this->slists WHERE lid=$lid");
break;
}
return FALSE;
}
/**
* Returns an array of item ids which have values specified in $vals
*
* @method public getByValueList
* @return mixed array of item ids or FALSE on failure
* @param string $iname index name
* @param array $vals array of item values
*/
function getByValueList($iname, $vals)
{
$kid = $this->indices[$iname][0];
$type = $this->indices[$iname][1];
switch ($type)
{
case 'int':
return $this->db->getCol("SELECT id FROM $this->ikeys WHERE kid=$kid and val IN(".implode(',',$vals).")");
break;
case 'float':
return $this->db->getCol("SELECT id FROM $this->fkeys WHERE kid=$kid and val IN(".implode(',',$vals).")");
break;
case 'string':
$lid = $this->db->getOne("SELECT lid FROM $this->skeys WHERE kid=$kid and val IN('".implode("','", $vals)."')");
return $this->db->getCol("SELECT id FROM $this->slists WHERE lid=$lid");
break;
}
return FALSE;
}
/**
* Returns items whose values are in a range. Applies only to int and float indexes.
*
* @method public getByRange
* @return mixed array of item ids or FALSE on failure
* @param string $iname index name
* @param optional mixed $from lower value. NULL if not specified. Note that 0 (zero) is a value.
* @param optional boolean $fs "from strict"? if TRUE '>' will be used, otherwise '>='. Defaults to FALSE.
* @param optional mixed $to upper value. NULL if not specified. Note that 0 (zero) is a value.
* @param optional boolean $ts "to strict"? if TRUE '<' will be used, '<=' otherwise. Defaults to FALSE.
*/
function getByRange($iname, $from = NULL, $fs = FALSE, $to = NULL, $ts = FALSE)
{
$kid = $this->indices[$iname][0];
$type = $this->indices[$iname][1];
$sql = 'SELECT id FROM ';
if ($type == 'int')
$sql .= $this->ikeys;
elseif ($type == 'float')
$sql .= $this->fkeys;
else
return FALSE;
$sql .= ' WHERE kid='.$kid;
if ($from !== NULL)
{
$sql .= 'AND val >';
if (!$fs)
$sql .= '=';
$sql .= " $from ";
}
if ($to !== NULL)
{
$sql .= 'AND val <';
if (!$ts)
$sql .= '=';
$sql .= " $to";
}
return $this->db->getCol($sql);
}
/**
* Returns an array of item ids matching a regular expression.
*
* @method public getByPreg
* @return mixed array on success, NULL on no results, FALSE on error
* @param string $iname index name
* @param string $preg regular expression. Full Perl-compatible regexp should be specified (e.g. /foo/i).
*/
function getByPreg($iname, $preg)
{
$kid = $this->indices[$iname][0];
$type = $this->indices[$iname][1];
if ($type != 'string')
return FALSE;
$lids = array();
$vls = $this->db->getAll("SELECT val,lid FROM $this->skeys WHERE kid=$kid");
foreach ($vls as $vl)
if (preg_match($preg,$vl['val']))
$lids[] = $vl['lid'];
if (!sizeof($lids))
return NULL;
return $this->db->getCol("SELECT id FROM $this->slists WHERE lid IN(".implode(',',$lids).")");
}
}
?>