<?php
/**
* Web Application Component Toolkit
*
* @link http://www.phpwact.org/
*
* @author Wact Development Team
* @link http://www.phpwact.org/team
*
* @copyright Copyright 2006, Jeff Moore
* @license http://opensource.org/licenses/mit-license.php MIT
*/

/**
*/
class Wact_Cache_Store_Memcache implements Wact_Cache_Store {

    /**
     * @var string memcached host
     */
    protected $host;
    
    /**
     * @var int memcached port
     */
    protected $port;
    
    /**
     * @var int Connection timeout
     */
    protected $timeout;
    
    /**
     * @var Memcache Memcache object
     */
    protected $memcache;
    
    /**
     * @var bool Connection state
     */
    protected $connected = FALSE;
    
    /**
     * Is the extension that supports this cache store available?  
     */
    function isAvailable() {
        return extension_loaded('memcache');
    }

    /**
     * Class constructor.
     * 
     * Stores connection parameters but doesn't connect
     * to the memcached system yet.
     *
     * @param $host string
     * @param $port int
     * @param $timeout int
     */
    public function __construct($host = 'localhost', $port = 11211, $timeout = 1) {
        $this->host = $host;
        $this->port = $port;
        $this->timeout = $timeout;
    }

    /**
     * Called internally before the first use of the cache.
     * 
     * Throws Wact_Cache_Exception on connection failure.
     */
    protected function connect() {
        $this->memcache = new Memcache();
        if (!$this->memcache->connect($this->host, $this->port, $this->timeout)) {
            throw new Wact_Cache_Exception('Could not connect to memcached.');
        }
        
        $this->connected = TRUE;
    }
    
    /**
    * @see Wact_Cache_Store.store
    */
    public function store($key, $data, $lifetime = NULL) {
        if (!$this->connected) {
            $this->connect();
        }
        
        settype($key, 'string');
        return $this->memcache->set($key, (string) $data, 0, $lifetime);
    }

    /**
    * @see Wact_Cache_Store.storeValue
    */
    public function storeValue($key, $data, $lifetime = NULL) {
        return $this->store($key, serialize($data), $lifetime);
    }
    
    /**
    * @see Wact_Cache_Store.fetch
    */
    public function fetch($key, $default = NULL) {
        if (!$this->connected) {
            $this->connect();
        }
        
        settype($key, 'string');
        $result = $this->memcache->get($key);
        if ($result === FALSE) {
            return $default;
        } else {
            return $result;
        }
    }

    /**
    * @see Wact_Cache_Store.fetch
    */
    public function fetchValue($key, $default = NULL) {
        $result = $this->fetch($key, FALSE);
        if ($result === FALSE) {
            return $default;
        }
        return unserialize($result);
    }
    
    /**
    * @see Wact_Cache_Store.includeCode
    */
    public function includeCode($key) {
        $code = $this->fetch($key, FALSE);
        if ($code !== FALSE) {
            // Strange concatination works better with source code parsing tools
            $result = eval(' ?' . '>' . $code . '<' . '?php ');

            if (is_null($result)) {
                return TRUE;
            } else {
                return $result;
            }
        }
        return FALSE;
    }
    
    /**
    * @see Wact_Cache_Store.remove
    */
    public function remove($key) {
        if (!$this->connected) {
            $this->connect();
        }
        
        settype($key, 'string');
        return $this->memcache->delete($key);
    }
    
    /**
    * Warning: "The flush has a one second granularity"
    * so this function implicitly delays execution for 1 second.
    * 
    * @see Wact_Cache_Store.clear
    */
    public function clear() {
        if (!$this->connected) {
            $this->connect();
        }
        
        if (!$this->memcache->flush()) {
            return FALSE;
        }
        
        sleep(1);
        
        return TRUE;
    }
    
}

?>