mirror of
				https://github.com/slawkens/myaac.git
				synced 2025-11-04 01:36:23 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			439 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			439 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
/**#@+
 | 
						|
 * @version 0.0.5
 | 
						|
 * @since 0.0.5
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * @package POT
 | 
						|
 * @version 0.1.5
 | 
						|
 * @author Wrzasq <wrzasq@gmail.com>
 | 
						|
 * @copyright 2007 - 2008 (C) by Wrzasq
 | 
						|
 * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3
 | 
						|
 * @todo future: Use fetchObject() to reduce amount of SQL queries.
 | 
						|
 * @todo future: Iterator classes (to map id => name iterations) with tutorial.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * Basic list class routines.
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * This class defines entire lists mechanism for classes that represents records set from OTServ database. All child classes only have to define {@link OTS_Base_List::init() init() method} to set table info for queries.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * Table on which list will operate has to contain integer <var>"id"</var> field and single row representing class has to support loading by this filed as key.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * This class is mostly usefull when you create own extensions for POT code.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * @package POT
 | 
						|
 * @version 0.1.5
 | 
						|
 * @property-write int $limit Sets LIMIT clause.
 | 
						|
 * @property-write int $offset Sets OFFSET clause.
 | 
						|
 * @property-write OTS_SQLFilter $filter Sets filter for list SQL query.
 | 
						|
 */
 | 
						|
abstract class OTS_Base_List implements IOTS_DAO, Iterator, Countable
 | 
						|
{
 | 
						|
/**
 | 
						|
 * Database connection.
 | 
						|
 *
 | 
						|
 * @var PDO
 | 
						|
 * @version 0.1.5
 | 
						|
 */
 | 
						|
    protected $db;
 | 
						|
 | 
						|
/**
 | 
						|
 * Limit for SELECT query.
 | 
						|
 *
 | 
						|
 * @var int
 | 
						|
 */
 | 
						|
    private $limit = false;
 | 
						|
 | 
						|
/**
 | 
						|
 * Offset for SELECT query.
 | 
						|
 *
 | 
						|
 * @var int
 | 
						|
 */
 | 
						|
    private $offset = false;
 | 
						|
 | 
						|
/**
 | 
						|
 * WHERE clause filter.
 | 
						|
 *
 | 
						|
 * @var OTS_SQLFilter
 | 
						|
 */
 | 
						|
    private $filter = null;
 | 
						|
 | 
						|
/**
 | 
						|
 * List of sorting criteriums.
 | 
						|
 *
 | 
						|
 * @var array
 | 
						|
 */
 | 
						|
    private $orderBy = array();
 | 
						|
 | 
						|
/**
 | 
						|
 * Query results.
 | 
						|
 *
 | 
						|
 * @var array
 | 
						|
 * @version 0.1.5
 | 
						|
 */
 | 
						|
    protected $rows;
 | 
						|
 | 
						|
/**
 | 
						|
 * Default table name for queries.
 | 
						|
 *
 | 
						|
 * @var string
 | 
						|
 */
 | 
						|
    protected $table;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class of generated objects.
 | 
						|
 *
 | 
						|
 * @var string
 | 
						|
 */
 | 
						|
    protected $class;
 | 
						|
 | 
						|
/**
 | 
						|
 * Sets database connection handler.
 | 
						|
 *
 | 
						|
 * @version 0.1.0
 | 
						|
 */
 | 
						|
    public function __construct()
 | 
						|
    {
 | 
						|
        $this->db = POT::getInstance()->getDBHandle();
 | 
						|
        $this->init();
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Sets list parameters.
 | 
						|
 */
 | 
						|
    abstract public function init();
 | 
						|
 | 
						|
/**
 | 
						|
 * Magic PHP5 method.
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * Allows object serialisation.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * @return array List of properties that should be saved.
 | 
						|
 */
 | 
						|
    public function __sleep()
 | 
						|
    {
 | 
						|
        return array('limit', 'offset', 'filter', 'orderBy', 'table', 'class');
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Magic PHP5 method.
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * Allows object unserialisation.
 | 
						|
 * </p>
 | 
						|
 */
 | 
						|
    public function __wakeup()
 | 
						|
    {
 | 
						|
        $this->db = POT::getInstance()->getDBHandle();
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Sets LIMIT clause.
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * Reduces amount of seleced rows up to given number.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * @param int|bool $limit Limit for SELECT (false to reset).
 | 
						|
 */
 | 
						|
    public function setLimit($limit = false)
 | 
						|
    {
 | 
						|
        if( is_int($limit) )
 | 
						|
        {
 | 
						|
            $this->limit = $limit;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            $this->limit = false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Sets OFFSET clause.
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * Moves starting rows of selected set to given position.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * @param int|bool $offset Offset for SELECT (false to reset).
 | 
						|
 */
 | 
						|
    public function setOffset($offset = false)
 | 
						|
    {
 | 
						|
        if( is_int($offset) )
 | 
						|
        {
 | 
						|
            $this->offset = $offset;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            $this->offset = false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns current row.
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * Returns object of class which handle single row representation. Object is initialised with ID of current position in result cursor.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * @version 0.1.3
 | 
						|
 * @return OTS_Base_DAO Current row.
 | 
						|
 */
 | 
						|
	#[\ReturnTypeWillChange]
 | 
						|
    public function current()
 | 
						|
    {
 | 
						|
        $id = current($this->rows);
 | 
						|
 | 
						|
        $class = 'OTS_' . $this->class;
 | 
						|
        return new $class( (int) $id['id']);
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Select rows from database.
 | 
						|
 *
 | 
						|
 * @throws PDOException On PDO operation error.
 | 
						|
 */
 | 
						|
    public function rewind(): void
 | 
						|
    {
 | 
						|
        $this->rows = $this->db->query( $this->getSQL() )->fetchAll();
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Moves to next row.
 | 
						|
 */
 | 
						|
    public function next(): void
 | 
						|
    {
 | 
						|
        next($this->rows);
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Current cursor position.
 | 
						|
 *
 | 
						|
 * @return mixed Array key.
 | 
						|
 */
 | 
						|
	#[\ReturnTypeWillChange]
 | 
						|
    public function key()
 | 
						|
    {
 | 
						|
        return key($this->rows);
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Checks if there are any rows left.
 | 
						|
 *
 | 
						|
 * @return bool Does next row exist.
 | 
						|
 */
 | 
						|
    public function valid(): bool
 | 
						|
    {
 | 
						|
        return key($this->rows) !== null;
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns number of rows on list in current criterium.
 | 
						|
 *
 | 
						|
 * @version 0.1.5
 | 
						|
 * @return int Number of rows.
 | 
						|
 * @throws PDOException On PDO operation error.
 | 
						|
 */
 | 
						|
    public function count(): int
 | 
						|
    {
 | 
						|
        return $this->db->query( $this->getSQL(true) )->fetchColumn();
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Sets filter on list.
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * Call without argument to reset filter.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * @param OTS_SQLFilter|null $filter Filter for list.
 | 
						|
 */
 | 
						|
    public function setFilter(OTS_SQLFilter $filter = null)
 | 
						|
    {
 | 
						|
        $this->filter = $filter;
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Clears ORDER BY clause.
 | 
						|
 */
 | 
						|
    public function resetOrder()
 | 
						|
    {
 | 
						|
        $this->orderBy = array();
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Appends sorting rule.
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * First parameter may be of type string, then it will be used as literal field name, or object of {@link OTS_SQLField OTS_SQLField class}, then it's representation will be used as qualiffied SQL identifier name.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * <p>
 | 
						|
 * Note: Since 0.0.7 version <var>$field</var> parameter can be instance of {@link OTS_SQLField OTS_SQLField class}.
 | 
						|
 * </p>
 | 
						|
 *
 | 
						|
 * @version 0.0.7
 | 
						|
 * @param OTS_SQLField|string $field Field name.
 | 
						|
 * @param int $order Sorting order (ascending by default).
 | 
						|
 */
 | 
						|
    public function orderBy($field, $order = POT::ORDER_ASC)
 | 
						|
    {
 | 
						|
        // constructs field name filter
 | 
						|
        if($field instanceof OTS_SQLField)
 | 
						|
        {
 | 
						|
            $table = $field->getTable();
 | 
						|
 | 
						|
            // full table name
 | 
						|
            if( !empty($table) )
 | 
						|
            {
 | 
						|
                $table = $this->db->tableName($table) . '.';
 | 
						|
            }
 | 
						|
 | 
						|
            $field = $table . $this->db->fieldName( $field->getName() );
 | 
						|
        }
 | 
						|
        // literal name
 | 
						|
        else
 | 
						|
        {
 | 
						|
            $field = $this->db->fieldName($field);
 | 
						|
        }
 | 
						|
 | 
						|
        $this->orderBy[] = array('field' => $field, 'order' => $order);
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns SQL query for SELECT.
 | 
						|
 *
 | 
						|
 * @version 0.1.5
 | 
						|
 * @param bool $count Shows if the SQL should be generated for COUNT() variant.
 | 
						|
 * @return string SQL query part.
 | 
						|
 */
 | 
						|
    protected function getSQL($count = false)
 | 
						|
    {
 | 
						|
        // fields list
 | 
						|
        if($count)
 | 
						|
        {
 | 
						|
            $fields = 'COUNT(' . $this->db->tableName($this->table) . '.' . $this->db->fieldName('id') . ')';
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            $fields = $this->db->tableName($this->table) . '.' . $this->db->fieldName('id') . ' AS ' . $this->db->fieldName('id');
 | 
						|
        }
 | 
						|
 | 
						|
        return $this->prepareSQL( array($fields) );
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns generic SQL query that can be adaptated by child classes.
 | 
						|
 *
 | 
						|
 * @version 0.1.5
 | 
						|
 * @since 0.1.5
 | 
						|
 * @param array $fields Fields to be selected.
 | 
						|
 * @return string SQL query.
 | 
						|
 */
 | 
						|
    protected function prepareSQL($fields)
 | 
						|
    {
 | 
						|
        $tables = array();
 | 
						|
 | 
						|
        // generates tables list for current qeury
 | 
						|
        if( isset($this->filter) )
 | 
						|
        {
 | 
						|
            $tables = $this->filter->getTables();
 | 
						|
        }
 | 
						|
 | 
						|
        // adds default table
 | 
						|
        if( !in_array($this->table, $tables) )
 | 
						|
        {
 | 
						|
            $tables[] = $this->table;
 | 
						|
        }
 | 
						|
 | 
						|
        // prepares tables names
 | 
						|
        foreach($tables as &$name)
 | 
						|
        {
 | 
						|
            $name = $this->db->tableName($name);
 | 
						|
        }
 | 
						|
 | 
						|
        // WHERE clause
 | 
						|
        if( isset($this->filter) )
 | 
						|
        {
 | 
						|
            $where = ' WHERE ' . $this->filter->__toString();
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            $where = '';
 | 
						|
        }
 | 
						|
 | 
						|
        // ORDER BY clause
 | 
						|
        if(empty($this->orderBy) )
 | 
						|
        {
 | 
						|
            $orderBy = '';
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            $orderBy = array();
 | 
						|
 | 
						|
            foreach($this->orderBy as $criterium)
 | 
						|
            {
 | 
						|
                switch($criterium['order'])
 | 
						|
                {
 | 
						|
                    case POT::ORDER_ASC:
 | 
						|
                        $orderBy[] = $criterium['field'] . ' ASC';
 | 
						|
                        break;
 | 
						|
 | 
						|
                    case POT::ORDER_DESC:
 | 
						|
                        $orderBy[] = $criterium['field'] . ' DESC';
 | 
						|
                        break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            $orderBy = ' ORDER BY ' . implode(', ', $orderBy);
 | 
						|
        }
 | 
						|
 | 
						|
        return 'SELECT ' . implode(', ', $fields) . ' FROM ' . implode(', ', $tables) . $where . $orderBy . $this->db->limit($this->limit, $this->offset);
 | 
						|
    }
 | 
						|
 | 
						|
/**
 | 
						|
 * Magic PHP5 method.
 | 
						|
 *
 | 
						|
 * @version 0.1.0
 | 
						|
 * @since 0.1.0
 | 
						|
 * @param string $name Property name.
 | 
						|
 * @param mixed $value Property value.
 | 
						|
 * @throws OutOfBoundsException For non-supported properties.
 | 
						|
 */
 | 
						|
    public function __set($name, $value)
 | 
						|
    {
 | 
						|
        switch($name)
 | 
						|
        {
 | 
						|
            case 'limit':
 | 
						|
                $this->setLimit($value);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'offset':
 | 
						|
                $this->setOffset($value);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'filter':
 | 
						|
                $this->setFilter($value);
 | 
						|
                break;
 | 
						|
 | 
						|
            default:
 | 
						|
                throw new OutOfBoundsException();
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**#@-*/
 | 
						|
 | 
						|
?>
 |