Вход Регистрация
Файл: onlinepoisk.wm-scripts.ru/vendor/AR/lib/Table.php
Строк: 600
<?php
/**
 * @package ActiveRecord
 */
namespace ActiveRecord;

/**
 * Manages reading and writing to a database table.
 *
 * This class manages a database table and is used by the Model class for
 * reading and writing to its database table. There is one instance of Table
 * for every table you have a model for.
 *
 * @package ActiveRecord
 */
class Table
{
    private static 
$cache = array();

    public 
$class;
    public 
$conn;
    public 
$pk;
    public 
$last_sql;

    
// Name/value pairs of columns in this table
    
public $columns = array();

    
/**
     * Name of the table.
     */
    
public $table;

    
/**
     * Name of the database (optional)
     */
    
public $db_name;

    
/**
     * Name of the sequence for this table (optional). Defaults to {$table}_seq
     */
    
public $sequence;

    
/**
     * A instance of CallBack for this model/table
     * @static
     * @var object ActiveRecordCallBack
     */
    
public $callback;

    
/**
     * List of relationships for this table.
     */
    
private $relationships = array();

    public static function 
load($model_class_name)
    {
        if (!isset(
self::$cache[$model_class_name]))
        {
            
/* do not place set_assoc in constructor..it will lead to infinite loop due to
               relationships requesting the model's table, but the cache hasn't been set yet */
            
self::$cache[$model_class_name] = new Table($model_class_name);
            
self::$cache[$model_class_name]->set_associations();
        }

        return 
self::$cache[$model_class_name];
    }

    public static function 
clear_cache($model_class_name=null)
    {
        if (
$model_class_name && array_key_exists($model_class_name,self::$cache))
            unset(
self::$cache[$model_class_name]);
        else
            
self::$cache = array();
    }

    public function 
__construct($class_name)
    {
        
$this->class Reflections::instance()->add($class_name)->get($class_name);

        
// if connection name property is null the connection manager will use the default connection
        
$connection $this->class->getStaticPropertyValue('connection',null);

        
$this->conn ConnectionManager::get_connection($connection);
        
$this->set_table_name();
        
$this->get_meta_data();
        
$this->set_primary_key();
        
$this->set_sequence_name();
        
$this->set_delegates();
        
$this->set_setters_and_getters();

        
$this->callback = new CallBack($class_name);
        
$this->callback->register('before_save', function(Model $model) { $model->set_timestamps(); }, array('prepend' => true));
        
$this->callback->register('after_save', function(Model $model) { $model->reset_dirty(); }, array('prepend' => true));
    }

    public function 
create_joins($joins)
    {
        if (!
is_array($joins))
            return 
$joins;

        
$self $this->table;
        
$ret $space '';

        
$existing_tables = array();
        foreach (
$joins as $value)
        {
            
$ret .= $space;

            if (
stripos($value,'JOIN ') === false)
            {
                if (
array_key_exists($value$this->relationships))
                {
                    
$rel $this->get_relationship($value);

                    
// if there is more than 1 join for a given table we need to alias the table names
                    
if (array_key_exists($rel->class_name$existing_tables))
                    {
                        
$alias $value;
                        
$existing_tables[$rel->class_name]++;
                    }
                    else
                    {
                        
$existing_tables[$rel->class_name] = true;
                        
$alias null;
                    }

                    
$ret .= $rel->construct_inner_join_sql($thisfalse$alias);
                }
                else
                    throw new 
RelationshipException("Relationship named $value has not been declared for class: {$this->class->getName()}");
            }
            else
                
$ret .= $value;

            
$space ' ';
        }
        return 
$ret;
    }

    public function 
options_to_sql($options)
    {
        
$table array_key_exists('from'$options) ? $options['from'] : $this->get_fully_qualified_table_name();
        
$sql = new SQLBuilder($this->conn$table);

        if (
array_key_exists('joins',$options))
        {
            
$sql->joins($this->create_joins($options['joins']));

            
// by default, an inner join will not fetch the fields from the joined table
            
if (!array_key_exists('select'$options))
                
$options['select'] = $this->get_fully_qualified_table_name() . '.*';
        }

        if (
array_key_exists('select',$options))
            
$sql->select($options['select']);

        if (
array_key_exists('conditions',$options))
        {
            if (!
is_hash($options['conditions']))
            {
                if (
is_string($options['conditions']))
                    
$options['conditions'] = array($options['conditions']);

                
call_user_func_array(array($sql,'where'),$options['conditions']);
            }
            else
            {
                if (!empty(
$options['mapped_names']))
                    
$options['conditions'] = $this->map_names($options['conditions'],$options['mapped_names']);

                
$sql->where($options['conditions']);
            }
        }

        if (
array_key_exists('order',$options))
            
$sql->order($options['order']);

        if (
array_key_exists('limit',$options))
            
$sql->limit($options['limit']);

        if (
array_key_exists('offset',$options))
            
$sql->offset($options['offset']);

        if (
array_key_exists('group',$options))
            
$sql->group($options['group']);

        if (
array_key_exists('having',$options))
            
$sql->having($options['having']);

        return 
$sql;
    }

    public function 
find($options)
    {
        
$sql $this->options_to_sql($options);
        
$readonly = (array_key_exists('readonly',$options) && $options['readonly']) ? true false;
        
$eager_load array_key_exists('include',$options) ? $options['include'] : null;

        return 
$this->find_by_sql($sql->to_s(),$sql->get_where_values(), $readonly$eager_load);
    }

    public function 
find_by_sql($sql$values=null$readonly=false$includes=null)
    {
        
$this->last_sql $sql;

        
$collect_attrs_for_includes is_null($includes) ? false true;
        
$list $attrs = array();
        
$sth $this->conn->query($sql,$this->process_data($values));

        while ((
$row $sth->fetch()))
        {
            
$model = new $this->class->name($row,false,true,false);

            if (
$readonly)
                
$model->readonly();

            if (
$collect_attrs_for_includes)
                
$attrs[] = $model->attributes();

            
$list[] = $model;
        }

        if (
$collect_attrs_for_includes && !empty($list))
            
$this->execute_eager_load($list$attrs$includes);

        return 
$list;
    }

    
/**
     * Executes an eager load of a given named relationship for this table.
     *
     * @param $models array found modesl for this table
     * @param $attrs array of attrs from $models
     * @param $includes array eager load directives
     * @return void
     */
    
private function execute_eager_load($models=array(), $attrs=array(), $includes=array())
    {
        if (!
is_array($includes))
            
$includes = array($includes);

        foreach (
$includes as $index => $name)
        {
            
// nested include
            
if (is_array($name))
            {
                
$nested_includes count($name) > $name $name[0];
                
$name $index;
            }
            else
                
$nested_includes = array();

            
$rel $this->get_relationship($nametrue);
            
$rel->load_eagerly($models$attrs$nested_includes$this);
        }
    }

    public function 
get_column_by_inflected_name($inflected_name)
    {
        foreach (
$this->columns as $raw_name => $column)
        {
            if (
$column->inflected_name == $inflected_name)
                return 
$column;
        }
        return 
null;
    }

    public function 
get_fully_qualified_table_name($quote_name=true)
    {
        
$table $quote_name $this->conn->quote_name($this->table) : $this->table;

        if (
$this->db_name)
            
$table $this->conn->quote_name($this->db_name) . ".$table";

        return 
$table;
    }

    
/**
     * Retrieve a relationship object for this table. Strict as true will throw an error
     * if the relationship name does not exist.
     *
     * @param $name string name of Relationship
     * @param $strict bool
     * @throws RelationshipException
     * @return Relationship or null
     */
    
public function get_relationship($name$strict=false)
    {
        if (
$this->has_relationship($name))
            return 
$this->relationships[$name];

        if (
$strict)
            throw new 
RelationshipException("Relationship named $name has not been declared for class: {$this->class->getName()}");

        return 
null;
    }

    
/**
     * Does a given relationship exist?
     *
     * @param $name string name of Relationship
     * @return bool
     */
    
public function has_relationship($name)
    {
        return 
array_key_exists($name$this->relationships);
    }

    public function 
insert(&$data$pk=null$sequence_name=null)
    {
        
$data $this->process_data($data);

        
$sql = new SQLBuilder($this->conn,$this->get_fully_qualified_table_name());
        
$sql->insert($data,$pk,$sequence_name);

        
$values array_values($data);
        return 
$this->conn->query(($this->last_sql $sql->to_s()),$values);
    }

    public function 
update(&$data$where)
    {
        
$data $this->process_data($data);

        
$sql = new SQLBuilder($this->conn,$this->get_fully_qualified_table_name());
        
$sql->update($data)->where($where);

        
$values $sql->bind_values();
        return 
$this->conn->query(($this->last_sql $sql->to_s()),$values);
    }

    public function 
delete($data)
    {
        
$data $this->process_data($data);

        
$sql = new SQLBuilder($this->conn,$this->get_fully_qualified_table_name());
        
$sql->delete($data);

        
$values $sql->bind_values();
        return 
$this->conn->query(($this->last_sql $sql->to_s()),$values);
    }

    
/**
     * Add a relationship.
     *
     * @param Relationship $relationship a Relationship object
     */
    
private function add_relationship($relationship)
    {
        
$this->relationships[$relationship->attribute_name] = $relationship;
    }

    private function 
get_meta_data()
    {
        
// as more adapters are added probably want to do this a better way
        // than using instanceof but gud enuff for now
        
$quote_name = !($this->conn instanceof PgsqlAdapter);

        
$this->columns $this->conn->columns($this->get_fully_qualified_table_name($quote_name));
    }

    
/**
     * Replaces any aliases used in a hash based condition.
     *
     * @param $hash array A hash
     * @param $map array Hash of used_name => real_name
     * @return array Array with any aliases replaced with their read field name
     */
    
private function map_names(&$hash, &$map)
    {
        
$ret = array();

        foreach (
$hash as $name => &$value)
        {
            if (
array_key_exists($name,$map))
                
$name $map[$name];

            
$ret[$name] = $value;
        }
        return 
$ret;
    }

    private function &
process_data($hash)
    {
        if (!
$hash)
            return 
$hash;

        foreach (
$hash as $name => &$value)
        {
            if (
$value instanceof DateTime)
            {
                if (isset(
$this->columns[$name]) && $this->columns[$name]->type == Column::DATE)
                    
$hash[$name] = $this->conn->date_to_string($value);
                else
                    
$hash[$name] = $this->conn->datetime_to_string($value);
            }
            else
                
$hash[$name] = $value;
        }
        return 
$hash;
    }

    private function 
set_primary_key()
    {
        if ((
$pk $this->class->getStaticPropertyValue('pk',null)) || ($pk $this->class->getStaticPropertyValue('primary_key',null)))
            
$this->pk is_array($pk) ? $pk : array($pk);
        else
        {
            
$this->pk = array();

            foreach (
$this->columns as $c)
            {
                if (
$c->pk)
                    
$this->pk[] = $c->inflected_name;
            }
        }
    }

    private function 
set_table_name()
    {
        if ((
$table $this->class->getStaticPropertyValue('table',null)) || ($table $this->class->getStaticPropertyValue('table_name',null)))
            
$this->table $table;
        else
        {
            
// infer table name from the class name
            
$this->table Inflector::instance()->tableize($this->class->getName());

            
// strip namespaces from the table name if any
            
$parts explode('\',$this->table);
            $this->table = $parts[count($parts)-1];
        }

        if(($db = $this->class->getStaticPropertyValue('
db',null)) || ($db = $this->class->getStaticPropertyValue('db_name',null)))
            $this->db_name = $db;
    }

    private function set_sequence_name()
    {
        if (!$this->conn->supports_sequences())
            return;

        if (!($this->sequence = $this->class->getStaticPropertyValue('
sequence')))
            $this->sequence = $this->conn->get_sequence_name($this->table,$this->pk[0]);
    }

    private function set_associations()
    {
        require_once '
Relationship.php';

        foreach ($this->class->getStaticProperties() as $name => $definitions)
        {
            if (!$definitions || !is_array($definitions))
                continue;

            foreach ($definitions as $definition)
            {
                $relationship = null;

                switch ($name)
                {
                    case '
has_many':
                        $relationship = new HasMany($definition);
                        break;

                    case '
has_one':
                        $relationship = new HasOne($definition);
                        break;

                    case '
belongs_to':
                        $relationship = new BelongsTo($definition);
                        break;

                    case '
has_and_belongs_to_many':
                        $relationship = new HasAndBelongsToMany($definition);
                        break;
                }

                if ($relationship)
                    $this->add_relationship($relationship);
            }
        }
    }

    /**
     * Rebuild the delegates array into format that we can more easily work with in Model.
     * Will end up consisting of array of:
     *
     * array('
delegate' => array('field1','field2',...),
     *       '
to'       => 'delegate_to_relationship',
     *       '
prefix'    => 'prefix')
     */
    private function set_delegates()
    {
        $delegates = $this->class->getStaticPropertyValue('
delegate',array());
        $new = array();

        if (!array_key_exists('
processed', $delegates))
            $delegates['
processed'] = false;

        if (!empty($delegates) && !$delegates['
processed'])
        {
            foreach ($delegates as &$delegate)
            {
                if (!is_array($delegate) || !isset($delegate['
to']))
                    continue;

                if (!isset($delegate['
prefix']))
                    $delegate['
prefix'] = null;

                $new_delegate = array(
                    '
to'        => $delegate['to'],
                    '
prefix'    => $delegate['prefix'],
                    '
delegate'    => array());

                foreach ($delegate as $name => $value)
                {
                    if (is_numeric($name))
                        $new_delegate['
delegate'][] = $value;
                }

                $new[] = $new_delegate;
            }

            $new['
processed'] = true;
            $this->class->setStaticPropertyValue('
delegate',$new);
        }
    }

    /**
     * Builds the getters/setters array by prepending get_/set_ to the method names.
     */
    private function set_setters_and_getters()
    {
        $build = array('
setters', 'getters');

        foreach ($build as $type)
        {
            $methods = array();
            $prefix = substr($type,0,3) . "_";

            foreach ($this->class->getStaticPropertyValue($type,array()) as $method)
                $methods[] = (substr($method,0,4) != $prefix ? "{$prefix}$method" : $method);

            $this->class->setStaticPropertyValue($type,$methods);
        }
    }
};
?>
Онлайн: 0
Реклама