Login   Register  
PHP Classes
elePHPant
Icontem

File: remodel.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of chema garrido  >  PHP Redis Model  >  remodel.php  >  Download  
File: remodel.php
Role: Example script
Content type: text/plain
Description: main class
Class: PHP Redis Model
CRUD operations to store and retrieve in Redis
Author: By
Last change:
Date: 2013-02-12 03:28
Size: 9,182 bytes
 

Contents

Class file image Download
<?php
/**
 *
 * Models for redis!
 * 
 * @author      Chema <chema@garridodiaz.com>
 * @package     Core
 * @version     0.1
 * @license     GPL v3
 * 
 * @todo
 * On update only save fields that are modified.
 * Fields validation, integer, varchar, email etc...
 * Create relations hasone , hasmany...
 * Fields filters, on read, on save.
 * if value is array: use a list 'TABLENAME:PK:SETNAME' and save it in a common list or set
 */

class Remodel {

    
/**
     * fields with values
     * @var array
     */
    
protected $_data = array();

    
/**
     * fields that has this model, if empty everything is allowed, recommended to set it.
     * @var array
     */
    
protected $_fields = array();

    
/**
     * redis instance
     * @var Predis
     */
    
protected $_redis

    
/**
     * common name used as redis key
     * @var string
     */
    
protected $_table_name;

    
/**
     * @var  string  PrimaryKey field name
     */
    
protected $_primary_key;

    
/**
     * redis keys constants to concat
     * DONOT change this if you had data already in the REDIS
     */
    
const NEXT_PK   '_pk_';   // 'TABLENAME:_pk_' => stores the pk counter
    
const ALL       '_all_';  // 'TABLENAME:ALL' => stores all the ids for this table
    
const KSEP      ':';      // Key Separator used for any KEY
    
    /**
     * create object and connect
     * @param Predis\Client $redis        connection or pipe
     * @param array $redis_config configuration
     * @param integer $pk          PK id to load.
     */
    
public function __construct($redis NULL, array $redis_config NULL $pk NULL )
    {
        if(
$redis!==NULL)
        {
            
$this->_redis $redis;
        }
        else
        {
            try 
            {
                
$this->_redis = new Predis\Client($redis_config);
            }
            catch (
Exception $e
            {
                throw new 
Exception("Error connecting to redis: ".print_r($e,1), 1);
            }
        } 

        if (
is_numeric($pk))
            
$this->load($pk);
    }

    
/**
     * Create a new model instance.
     *
     *     $model = Remodel::factory($name);
     *
     * @param   string   model name
     * @return  Model
     */
    
public static function factory($name)
    {
        
$class 'Model_'.$name;
        if(
class_exists($class))
        {
            return new 
$class;
        }
        else
        {
            throw new 
Exception('Factory model not found: '.$name1);
        }
    }

    
/**
     * creates a new item pk
     * @param  Redis $pipe usage of pipe to make it faster optional 
     * @return boolean 
     */
    
public function create($pipe NULL)
    {
        
$conn = ($pipe!==NULL)? $pipe:$this->_redis;

        
//getting the primary key, first we increase so there¡s no repeated id's
        
$this->pk($this->get_last_pk(TRUE));
      
        
//save the data at redis
        
if ($this->update($conn))
        {            
            
//save the primary in a global set
            
$conn->sadd($this->_table_name.self::KSEP
                            
.self::ALL$this->pk());
            
//end pipe
            
return TRUE;
        }
        
//if save not success decrease 
        
else
        {
            
$this->_redis->decr($this->_table_name.self::KSEP.self::NEXT_PK);
            return 
FALSE;
        }
    }

    
/**
     * update the current data at redis
     * @param  Redis $pipe usage of pipe to make it faster optional 
     * @return boolean       
     */
    
public function update($pipe NULL)
    {        
        
$conn = ($pipe!==NULL)? $pipe:$this->_redis;

        
//we add the pk to the array
        
$data array_merge(array( $this->_primary_key => $this->pk() ),$this->_data);

        return 
$conn->hmset($this->_table_name.self::KSEP.$this->pk(), $data);     
    }
    
   
/**
    * deletes a key from the redis
    * @param  integer $pk optional
    * @return boolean      
    */
    
public function delete($pk NULL)
    {
        
//if isnumeric we try to be friendly and use it as the index
        
if (!is_numeric($pk))
            
$pk $this->pk();
                
        
//remove the KEY from redis
        
$ret $this->_redis->del($this->_table_name.self::KSEP.$pk);

        
//delete the PK from the global list
        
if ($ret>0)
            
$ret $this->_redis->srem($this->_table_name.self::KSEP.self::ALL$this->pk());
        
        
$this->unload();

        return (
$ret>0)? TRUE FALSE;
    }
    
    
/**
     * updates or creates, shortcut
     * @param  Redis $pipe usage of pipe to make it faster optional
     */
    
public function save($pipe NULL)
    {
        
//if index exists calls update if doesn't exists create
        
($this->loaded())? $this->update($pipe):$this->create($pipe);
    }
    
    
/**
     * Just tells you if there's some data populated in the model using the primary
     * @return boolean
     */
    
public function loaded()
    {
        return (
array_key_exists($this->_primary_key$this->_data));
    }
    
    
/**
     * Unloads any data
     */
    
public function unload()
    {
        unset(
$this->_data);
    }

    
/**
     * loads values
     * @param  inteeger PK to load data  
     * @return boolean
     */
    
public function load($pk NULL)
    {
        if (
is_numeric($pk))
        {
            
$data $this->_redis->hgetall($this->_table_name.self::KSEP.$pk);
            if (!empty(
$data))
            {
                
$this->values($data);
                return 
TRUE;
            }
        }
        return 
FALSE;
    }

    
/**
     * loads/get an array of values into the model
     * @param  array $data  
     * @return boolean/array
     */
    
public function values(array $data NULL)
    {
        if (
is_array($data))
        {
            
$this->_data $data;
            return 
TRUE;
        }
        else return 
$this->_data;        
    }

    
/**
     * retrieves models for the specified range
     * lrange over TABLENAME:ALL
     * @param  integer/array $elements if array return those elements, if not = from
     * @param  integer $stop  to
     * @return array   remodel
     */
    
public function select($elements 0$stop 9)
    {
        if (!
is_array($elements))
            
$elements $this->get_all_pk($elements,$stop);

        
$ret = array();
       
        
// return array of Models
        
if(count($elements) >= 1)
        {
            
//@todo use of a pipe to improve load?
            //get values in a pipe put them in array and push them to the model
            
$class get_class($this);//using same model
            
foreach ($elements as $element)
            {
                
$model = new $class;
                
$model->load($element);
                if (
$model->loaded()) 
                    
$ret[]= $model;
                unset(
$model);
            }
        }

        return 
$ret;
    }

    
/**
     * returns the amount of elements in the redis set for that table
     * @param string set_name
     * @return integer
     */
    
public function count($set_name NULL)
    {        
        
//count all
        
if ($set_name === NULL)
            return 
$this->_redis->scard($this->_table_name.self::KSEP.self::ALL);
        else
//count set
            
return $this->_redis->scard($this->_table_name.self::KSEP.$set_name);   
    }
    
    
/**
     * set/get the primary key value of the object
     * @return integer id
     */
    
public function pk($pk NULL)
    {
        
//acting as setter
        
if (is_numeric($pk))
            
$this->_data[$this->_primary_key] = $pk;

        return (
$this->loaded())? $this->_data[$this->_primary_key] : FALSE;
    }

    
/**
     * retrieve the PK for the list of this table
     * @param  integer $start from
     * @param  integer $stop  to
     * @return array 
     */
    
public function get_all_pk($start 0$stop 9)
    {
        
//todo improve this!!
        
return $this->_redis->sort($this->_table_name.self::KSEP.self::ALL,array('by'=> 'nosort','limit' => array($start,$stop)));
    }

    
/**
     * retrieve the last PK used for the table
     * @param bool $increase if set to true we increase the redis PK before.
     * @return integer
     */
    
public function get_last_pk($increase FALSE)
    {
        if (
$increase === TRUE)
            
$this->_redis->incr($this->_table_name.self::KSEP.self::NEXT_PK);

        return 
$this->_redis->get($this->_table_name.self::KSEP.self::NEXT_PK);
    }
        
    
/**
     * Magic methods to set get
     */
    
public function __set($name$value)
    {
        
//check if fields exists in the `model`
        
if ( empty($this->_fields) OR in_array($name$this->_fields) )
        {
            
$this->_data[$name] = $value;
        }
        else throw new 
Exception($name.' does not exist in the model.'1);
        
    }

    public function 
__get($name)
    {
        return (
array_key_exists($name$this->_data)) ? $this->_data[$name] : NULL;
    }

    public function 
__isset($name)
    {
        return isset(
$this->_data[$name]);
    }

    public function 
__unset($name)
    {
        unset(
$this->_data[$name]);
    }
    
}