<?php
/**
 * A class for handling database-based session storage.
 */
class session_handler_db implements session_handler
{
    /**
     * @var db_connection The db connection.
     */
    protected $connection;
    
    /**
     * @var string The database schema.
     *
     *  CREATE TABLE `session` (
     *    `id` varchar(255) NOT NULL,
     *    `touch` int(10) unsigned NOT NULL default '0',
     *    `data` text,
     *    PRIMARY KEY  (`id`)
     *  );
     */
    protected $table, $id, $touch, $data;
    
    ////////////////////////////////////////////////////////////////////////////
    // Construct and destruct functions.

    /**
     * @param string/db_connection (optional) $connection The db connection or
     * name.
     * @param string (optional) $table The table name.
     * @param string (optional) $id The id column name.
     * @param string (optional) $touch The touch column name.
     * @param string (optional) $data The data column name.
     */
    public function __construct($connection = 'default', $table = 'session', $id = 'id', $touch = 'touch', $data = 'data')
    {
        $this->connection = $connection;
        $this->table = $table;
        $this->id = $id;
        $this->touch = $touch;
        $this->data = $data;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Overload functions.

    ////////////////////////////////////////////////////////////////////////////
    // Interface functions.

    /**
     * Opens a session.
     * 
     * @param string $directory The session file directory.
     * @param string $name The session name.
     * @return boolean True if successful, else false.
     */
    public function open($directory, $name)
    {
        if (!$this->connection instanceof db_connection)
        {
            $this->connection = db::get($this->connection);
        }
        
        return true;
    }

    /**
     * Closes a session.
     * 
     * @return boolean True if successful, else false.
     */
    public function close()
    {
        return true;
    }

    /**
     * Reads from a session storage.
     * 
     * @param integer $id The session id.
     * @throws logicexception If the session id is not valid.
     * @return array The session data.
     */
    public function read($id)
    {
        $row = $this->connection->query()->select($this->table)
                                         ->column($this->data)
                                         ->where($this->id, $id)
                                         ->limit(1)
                                         ->execute()->fetch();
        
        return ($row) ? $row[$this->data] : '';
    }

    /**
     * Writes to a session storage.
     * 
     * @param integer $id The session id.
     * @param array $data The session data.
     * @return boolean True if successful, else false.
     */
    public function write($id, $data)
    {
        $affected = 0;
        
        try
        {
            $exist = count($this->connection->query()->select($this->table)
                                                     ->column($this->id)
                                                     ->where($this->id, $id)
                                                     ->limit(1)
                                                     ->execute());
            
            $query = $this->connection->query();
            
            if ($exist)
            {
                $query->update($this->table)
                      ->where($this->id, $id)
                      ->limit(1);
            }
            else
            {
                $query->insert($this->table);
            }
            
            $affected = count($query->column($this->id, $id)
                                    ->column($this->touch, time())
                                    ->column($this->data, $data)
                                    ->execute());
        }
        catch (exception $e)
        {
            return false;
        }
        
        return (boolean) $affected;
    }

    /**
     * Destroys a session.
     * 
     * @param integer $id The session id.
     * @throws logicexception If the session id is not valid.
     * @return boolean True if successful, else false.
     */
    public function destroy($id)
    {
        $this->connection->query()->delete($this->table)
                                  ->where($this->id, $id)
                                  ->limit(1)
                                  ->execute();
        
        return true;
    }

    /**
     * Clears expired sessions.
     * 
     * @param integer $life The expiration limit.
     * @return boolean True if successful, else false.
     */
    public function clear($life)
    {
        $this->connection->query()->delete($this->table)
                                  ->where('<', $this->touch, time() - $life)
                                  ->execute();
        
        return true;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Internal functions.
}
