Location: PHPKode > projects > Tv.2 CMS > tv2engine/ctlIndexer.class.php
<?php

/** 
 * General purpose indexer.
 * 
 * @package tv2-engine
 * @author Emilis Dambauskas (hide@address.com)
 * @copyright 2002–2003 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).")");
	}
}

?>
Return current item: Tv.2 CMS