0 follower

CJoinElement

Package system.db.ar
Inheritance class CJoinElement
Since 1.0
Version $Id$
Source Code framework/db/ar/CActiveFinder.php
CJoinElement represents a tree node in the join tree created by CActiveFinder.

Public Properties

Hide inherited properties

PropertyTypeDescriptionDefined By
children array list of child join elements CJoinElement
id integer the unique ID of this tree node CJoinElement
model CActiveRecord the model associated with this tree node CJoinElement
records array list of active records found by the queries. CJoinElement
relation CActiveRelation the relation represented by this tree node CJoinElement
stats array list of stat elements CJoinElement
tableAlias string table alias for this join element CJoinElement

Public Methods

Hide inherited methods

MethodDescriptionDefined By
__construct() Constructor. CJoinElement
afterFind() Calls CActiveRecord::afterFind of all the records. CJoinElement
beforeFind() Calls CActiveRecord::beforeFind. CJoinElement
buildQuery() Builds the join query with all descendant HAS_ONE and BELONGS_TO nodes. CJoinElement
count() Count the number of primary records returned by the join statement. CJoinElement
find() Performs the recursive finding with the criteria. CJoinElement
findWithBase() Performs the eager loading with the base records ready. CJoinElement
getColumnPrefix() Returns the column prefix for column reference disambiguation CJoinElement
getColumnSelect() Generates the list of columns to be selected. CJoinElement
getCondition() Returns the WHERE clause. Column references are properly disambiguated. CJoinElement
getGroupBy() Returns the GROUP BY clause. Column references are properly disambiguated. CJoinElement
getHaving() Returns the HAVING clause. Column references are properly disambiguated. CJoinElement
getJoinCondition() Returns the join statement (this node joins with its parent) CJoinElement
getOrder() Returns the ORDER BY clause. Column references are properly disambiguated. CJoinElement
getPrimaryKeyRange() Returns the condition that specifies only the rows with the selected primary key values. CJoinElement
getPrimaryKeySelect() Returns the primary key selection CJoinElement
getTableNameWithAlias() Returns the table name and the table alias (if any). This can be used directly in SQL query without escaping. CJoinElement
lazyFind() Performs lazy find with the specified base record. CJoinElement
runQuery() Executes the join query and populates the query results. CJoinElement

Property Details

children property
public array $children;

list of child join elements

id property
public integer $id;

the unique ID of this tree node

model property
public CActiveRecord $model;

the model associated with this tree node

records property
public array $records;

list of active records found by the queries. They are indexed by primary key values.

relation property
public CActiveRelation $relation;

the relation represented by this tree node

stats property (available since v1.0.4)
public array $stats;

list of stat elements

tableAlias property
public string $tableAlias;

table alias for this join element

Method Details

__construct() method
public void __construct(CActiveFinder $finder, mixed $relation, CJoinElement $parent=NULL, integer $id=0)
$finder CActiveFinder the finder
$relation mixed the relation (if the third parameter is not null) or the model (if the third parameter is null) associated with this tree node.
$parent CJoinElement the parent tree node
$id integer the ID of this tree node that is unique among all the tree nodes
Source Code: framework/db/ar/CActiveFinder.php#344 (show)
public function __construct($finder,$relation,$parent=null,$id=0)
{
    
$this->_finder=$finder;
    
$this->id=$id;
    if(
$parent!==null)
    {
        
$this->relation=$relation;
        
$this->_parent=$parent;
        
$this->_builder=$parent->_builder;
        
$this->tableAlias=$relation->alias===null?'t'.$id:$relation->alias;
        
$this->model=CActiveRecord::model($relation->className);
        
$this->_table=$this->model->getTableSchema();
    }
    else  
// root element, the first parameter is the model.
    
{
        
$this->model=$relation;
        
$this->_builder=$relation->getCommandBuilder();
        
$this->_table=$relation->getTableSchema();
    }

    
// set up column aliases, such as t1_c2
    
$table=$this->_table;
    if(
$this->model->getDbConnection()->getDriverName()==='oci')  // Issue 482
        
$prefix='T'.$id.'_C';
    else
        
$prefix='t'.$id.'_c';
    foreach(
$table->getColumnNames() as $key=>$name)
    {
        
$alias=$prefix.$key;
        
$this->_columnAliases[$name]=$alias;
        if(
$table->primaryKey===$name)
            
$this->_pkAlias=$alias;
        else if(
is_array($table->primaryKey) && in_array($name,$table->primaryKey))
            
$this->_pkAlias[$name]=$alias;
    }
}

Constructor.

afterFind() method (available since v1.0.3)
public void afterFind()
Source Code: framework/db/ar/CActiveFinder.php#668 (show)
public function afterFind()
{
    foreach(
$this->records as $record)
        
$record->afterFindInternal();
    foreach(
$this->children as $child)
        
$child->afterFind();
}

Calls CActiveRecord::afterFind of all the records.

beforeFind() method (available since v1.0.11)
public void beforeFind()
Source Code: framework/db/ar/CActiveFinder.php#659 (show)
public function beforeFind()
{
    
$this->model->beforeFindInternal();
}

Calls CActiveRecord::beforeFind.

buildQuery() method
public void buildQuery(CJoinQuery $query)
$query CJoinQuery the query being built up
Source Code: framework/db/ar/CActiveFinder.php#680 (show)
public function buildQuery($query)
{
    foreach(
$this->children as $child)
    {
        if(
$child->relation instanceof CHasOneRelation || $child->relation instanceof CBelongsToRelation
            
|| $child->relation->together || ($this->_finder->joinAll && !$this->_finder->baseLimited))
        {
            
$child->_joined=true;
            
$query->join($child);
            
$child->buildQuery($query);
        }
    }
}

Builds the join query with all descendant HAS_ONE and BELONGS_TO nodes.

count() method (available since v1.0.3)
public integer count(CDbCriteria $criteria=NULL)
$criteria CDbCriteria the query criteria
{return} integer number of primary records.
Source Code: framework/db/ar/CActiveFinder.php#628 (show)
public function count($criteria=null)
{
    
$query=new CJoinQuery($this,$criteria);
    
// ensure only one big join statement is used
    
$this->_finder->baseLimited=false;
    
$this->_finder->joinAll=true;
    
$this->buildQuery($query);

    
$select=is_array($criteria->select) ? implode(',',$criteria->select) : $criteria->select;
    if(
$select!=='*' && !strncasecmp($select,'count',5))
        
$query->selects=array($select);
    else if(
is_string($this->_table->primaryKey))
    {
        
$prefix=$this->getColumnPrefix();
        
$schema=$this->_builder->getSchema();
        
$column=$prefix.$schema->quoteColumnName($this->_table->primaryKey);
        
$query->selects=array("COUNT(DISTINCT $column)");
    }
    else
        
$query->selects=array("COUNT(*)");

    
$query->orders=$query->groups=$query->havings=array();
    
$query->limit=$query->offset=-1;
    
$command=$query->createCommand($this->_builder);
    return 
$command->queryScalar();
}

Count the number of primary records returned by the join statement.

find() method
public void find(CDbCriteria $criteria=NULL)
$criteria CDbCriteria the query criteria
Source Code: framework/db/ar/CActiveFinder.php#385 (show)
public function find($criteria=null)
{
    if(
$this->_parent===null// root element
    
{
        
$query=new CJoinQuery($this,$criteria);
        if(
$this->_finder->baseLimited===null)
            
$this->_finder->baseLimited=($criteria->offset>=|| $criteria->limit>=0);
        
$this->buildQuery($query);
        
$this->runQuery($query);
    }
    else if(!
$this->_joined && !empty($this->_parent->records)) // not joined before
    
{
        
$query=new CJoinQuery($this->_parent);
        
$this->_joined=true;
        
$query->join($this);
        
$this->buildQuery($query);
        
$this->_parent->runQuery($query);
    }

    foreach(
$this->children as $child// find recursively
        
$child->find();

    foreach(
$this->stats as $stat)
        
$stat->query();
}

Performs the recursive finding with the criteria.

findWithBase() method
public void findWithBase(mixed $baseRecords)
$baseRecords mixed the available base record(s).
Source Code: framework/db/ar/CActiveFinder.php#591 (show)
public function findWithBase($baseRecords)
{
    if(!
is_array($baseRecords))
        
$baseRecords=array($baseRecords);
    if(
is_string($this->_table->primaryKey))
    {
        foreach(
$baseRecords as $baseRecord)
            
$this->records[$baseRecord->{$this->_table->primaryKey}]=$baseRecord;
    }
    else
    {
        foreach(
$baseRecords as $baseRecord)
        {
            
$pk=array();
            foreach(
$this->_table->primaryKey as $name)
                
$pk[$name]=$baseRecord->$name;
            
$this->records[serialize($pk)]=$baseRecord;
        }
    }

    
$query=new CJoinQuery($this);
    
$this->buildQuery($query);
    if(
count($query->joins)>1)
        
$this->runQuery($query);
    foreach(
$this->children as $child)
        
$child->find();

    foreach(
$this->stats as $stat)
        
$stat->query();
}

Performs the eager loading with the base records ready.

getColumnPrefix() method
public string getColumnPrefix()
{return} string the column prefix for column reference disambiguation
Source Code: framework/db/ar/CActiveFinder.php#942 (show)
public function getColumnPrefix()
{
    if(
$this->tableAlias!==null)
        return 
$this->tableAlias.'.';
    else
        return 
$this->_table->rawName.'.';
}

getColumnSelect() method
public string getColumnSelect(mixed $select='*')
$select mixed columns to be selected. Defaults to '*', indicating all columns.
{return} string the column selection
Source Code: framework/db/ar/CActiveFinder.php#799 (show)
public function getColumnSelect($select='*')
{
    
$schema=$this->_builder->getSchema();
    
$prefix=$this->getColumnPrefix();
    
$columns=array();
    if(
$select==='*')
    {
        foreach(
$this->_table->getColumnNames() as $name)
            
$columns[]=$prefix.$schema->quoteColumnName($name).' AS '.$schema->quoteColumnName($this->_columnAliases[$name]);
    }
    else
    {
        if(
is_string($select))
            
$select=explode(',',$select);
        
$selected=array();
        foreach(
$select as $name)
        {
            
$name=trim($name);
            
$matches=array();
            if((
$pos=strrpos($name,'.'))!==false)
                
$key=substr($name,$pos+1);
            else
                
$key=$name;
            if(isset(
$this->_columnAliases[$key]))  // simple column names
            
{
                
$columns[]=$prefix.$schema->quoteColumnName($key).' AS '.$schema->quoteColumnName($this->_columnAliases[$key]);
                
$selected[$this->_columnAliases[$key]]=1;
            }
            else if(
preg_match('/^(.*?)\s+AS\s+(\w+)$/i',$name,$matches)) // if the column is already aliased
            
{
                
$alias=$matches[2];
                if(!isset(
$this->_columnAliases[$alias]) || $this->_columnAliases[$alias]!==$alias)
                {
                    
$this->_columnAliases[$alias]=$alias;
                    
$columns[]=$name;
                    
$selected[$alias]=1;
                }
            }
            else
                throw new 
CDbException(Yii::t('yii','Active record "{class}" is trying to select an invalid column "{column}". Note, the column must exist in the table or be an expression with alias.',
                    array(
'{class}'=>get_class($this->model), '{column}'=>$name)));
        }
        
// add primary key selection if they are not selected
        
if(is_string($this->_pkAlias) && !isset($selected[$this->_pkAlias]))
            
$columns[]=$prefix.$schema->quoteColumnName($this->_table->primaryKey).' AS '.$schema->quoteColumnName($this->_pkAlias);
        else if(
is_array($this->_pkAlias))
        {
            foreach(
$this->_table->primaryKey as $name)
                if(!isset(
$selected[$name]))
                    
$columns[]=$prefix.$schema->quoteColumnName($name).' AS '.$schema->quoteColumnName($this->_pkAlias[$name]);
        }
    }

    
$select=implode(', ',$columns);
    if(
$this->relation!==null)
        return 
str_replace($this->relation->aliasToken.'.'$prefix$select);
    else
        return 
$select;
}

Generates the list of columns to be selected. Columns will be properly aliased and primary keys will be added to selection if they are not specified.

getCondition() method
public string getCondition()
{return} string the WHERE clause. Column references are properly disambiguated.
Source Code: framework/db/ar/CActiveFinder.php#896 (show)
public function getCondition()
{
    if(
$this->relation->condition!=='' && $this->tableAlias!==null)
        return 
str_replace($this->relation->aliasToken.'.'$this->tableAlias.'.'$this->relation->condition);
    else
        return 
$this->relation->condition;
}

getGroupBy() method (available since v1.0.4)
public string getGroupBy()
{return} string the GROUP BY clause. Column references are properly disambiguated.
Source Code: framework/db/ar/CActiveFinder.php#919 (show)
public function getGroupBy()
{
    if(
$this->relation->group!=='' && $this->tableAlias!==null)
        return 
str_replace($this->relation->aliasToken.'.'$this->tableAlias.'.'$this->relation->group);
    else
        return 
$this->relation->group;
}

getHaving() method (available since v1.0.4)
public string getHaving()
{return} string the HAVING clause. Column references are properly disambiguated.
Source Code: framework/db/ar/CActiveFinder.php#931 (show)
public function getHaving()
{
    if(
$this->relation->having!=='' && $this->tableAlias!==null)
        return 
str_replace($this->relation->aliasToken.'.'$this->tableAlias.'.'$this->relation->having);
    else
        return 
$this->relation->having;
}

getJoinCondition() method
public string getJoinCondition()
{return} string the join statement (this node joins with its parent)
Source Code: framework/db/ar/CActiveFinder.php#953 (show)
public function getJoinCondition()
{
    
$parent=$this->_parent;
    
$relation=$this->relation;
    if(
$this->relation instanceof CManyManyRelation)
    {
        if(!
preg_match('/^\s*(.*?)\((.*)\)\s*$/',$this->relation->foreignKey,$matches))
            throw new 
CDbException(Yii::t('yii','The relation "{relation}" in active record class "{class}" is specified with an invalid foreign key. The format of the foreign key must be "joinTable(fk1,fk2,...)".',
                array(
'{class}'=>get_class($parent->model),'{relation}'=>$this->relation->name)));

        
$schema=$this->_builder->getSchema();
        if((
$joinTable=$schema->getTable($matches[1]))===null)
            throw new 
CDbException(Yii::t('yii','The relation "{relation}" in active record class "{class}" is not specified correctly: the join table "{joinTable}" given in the foreign key cannot be found in the database.',
                array(
'{class}'=>get_class($parent->model), '{relation}'=>$this->relation->name'{joinTable}'=>$matches[1])));
        
$fks=preg_split('/[\s,]+/',$matches[2],-1,PREG_SPLIT_NO_EMPTY);

        return 
$this->joinManyMany($joinTable,$fks,$parent);
    }
    else
    {
        
$fks=preg_split('/[\s,]+/',$relation->foreignKey,-1,PREG_SPLIT_NO_EMPTY);
        if(
$this->relation instanceof CBelongsToRelation)
        {
            
$pke=$this;
            
$fke=$parent;
        }
        else
        {
            
$pke=$parent;
            
$fke=$this;
        }
        return 
$this->joinOneMany($fke,$fks,$pke,$parent);
    }
}

getOrder() method
public string getOrder()
{return} string the ORDER BY clause. Column references are properly disambiguated.
Source Code: framework/db/ar/CActiveFinder.php#907 (show)
public function getOrder()
{
    if(
$this->relation->order!=='' && $this->tableAlias!==null)
        return 
str_replace($this->relation->aliasToken.'.',$this->tableAlias.'.',$this->relation->order);
    else
        return 
$this->relation->order;
}

getPrimaryKeyRange() method
public string getPrimaryKeyRange()
{return} string the condition that specifies only the rows with the selected primary key values.
Source Code: framework/db/ar/CActiveFinder.php#880 (show)
public function getPrimaryKeyRange()
{
    if(empty(
$this->records))
        return 
'';
    
$values=array_keys($this->records);
    if(
is_array($this->_table->primaryKey))
    {
        foreach(
$values as &$value)
            
$value=unserialize($value);
    }
    return 
$this->_builder->createInCondition($this->_table,$this->_table->primaryKey,$values,$this->getColumnPrefix());
}

getPrimaryKeySelect() method
public string getPrimaryKeySelect()
{return} string the primary key selection
Source Code: framework/db/ar/CActiveFinder.php#862 (show)
public function getPrimaryKeySelect()
{
    
$schema=$this->_builder->getSchema();
    
$prefix=$this->getColumnPrefix();
    
$columns=array();
    if(
is_string($this->_pkAlias))
        
$columns[]=$prefix.$schema->quoteColumnName($this->_table->primaryKey).' AS '.$schema->quoteColumnName($this->_pkAlias);
    else if(
is_array($this->_pkAlias))
    {
        foreach(
$this->_pkAlias as $name=>$alias)
            
$columns[]=$prefix.$schema->quoteColumnName($name).' AS '.$schema->quoteColumnName($alias);
    }
    return 
implode(', ',$columns);
}

getTableNameWithAlias() method
public string getTableNameWithAlias()
{return} string the table name and the table alias (if any). This can be used directly in SQL query without escaping.
Source Code: framework/db/ar/CActiveFinder.php#785 (show)
public function getTableNameWithAlias()
{
    if(
$this->tableAlias!==null)
        return 
$this->_table->rawName ' ' $this->tableAlias;
    else
        return 
$this->_table->rawName;
}

lazyFind() method
public void lazyFind(CActiveRecord $baseRecord)
$baseRecord CActiveRecord the active record whose related object is to be fetched.
Source Code: framework/db/ar/CActiveFinder.php#415 (show)
public function lazyFind($baseRecord)
{
    if(
is_string($this->_table->primaryKey))
        
$this->records[$baseRecord->{$this->_table->primaryKey}]=$baseRecord;
    else
    {
        
$pk=array();
        foreach(
$this->_table->primaryKey as $name)
            
$pk[$name]=$baseRecord->$name;
        
$this->records[serialize($pk)]=$baseRecord;
    }

    foreach(
$this->stats as $stat)
        
$stat->query();

    if(empty(
$this->children))
        return;

    
$child=reset($this->children);
    
$query=new CJoinQuery($child);
    
$query->selects=array();
    
$query->selects[]=$child->getColumnSelect($child->relation->select);
    
$query->conditions=array();
    
$query->conditions[]=$child->getCondition();
    if(!empty(
$child->relation->on))
        
$query->conditions[]=str_replace($child->relation->aliasToken.'.'$child->tableAlias.'.'$child->relation->on);
    
$query->groups[]=$child->getGroupBy();
    
$query->havings[]=$child->getHaving();
    
$query->orders[]=$child->getOrder();
    if(
is_array($child->relation->params))
        
$query->params=$child->relation->params;
    
$query->elements[$child->id]=true;
    if(
$child->relation instanceof CHasManyRelation)
    {
        
$query->limit=$child->relation->limit;
        
$query->offset=$child->relation->offset;
    }

    
$child->applyLazyCondition($query,$baseRecord);

    
$this->_joined=true;
    
$child->_joined=true;

    
$child->buildQuery($query);
    
$child->runQuery($query);
    foreach(
$child->children as $c)
        
$c->find();

    if(empty(
$child->records))
        return;
    if(
$child->relation instanceof CHasOneRelation || $child->relation instanceof CBelongsToRelation)
        
$baseRecord->addRelatedRecord($child->relation->name,reset($child->records),false);
    else 
// has_many and many_many
    
{
        foreach(
$child->records as $record)
        {
            if(
$child->relation->index!==null)
                
$index=$record->{$child->relation->index};
            else
                
$index=true;
            
$baseRecord->addRelatedRecord($child->relation->name,$record,$index);
        }
    }
}

Performs lazy find with the specified base record.

runQuery() method
public void runQuery(CJoinQuery $query)
$query CJoinQuery the query to be executed.
Source Code: framework/db/ar/CActiveFinder.php#698 (show)
public function runQuery($query)
{
    
$command=$query->createCommand($this->_builder);
    foreach(
$command->queryAll() as $row)
        
$this->populateRecord($query,$row);
}

Executes the join query and populates the query results.