CJoinElement

优质
小牛编辑
138浏览
2023-12-01
所有包 | 属性 | 方法
system.db.ar
继承class CJoinElement
源自1.0
版本$Id: CActiveFinder.php 3562 2012-02-13 01:27:06Z qiang.xue $
源码framework/db/ar/CActiveFinder.php
CJoinElement表示一个在关联树中由CActiveFinder创建的子树节点。

公共属性

隐藏继承属性

属性类型描述定义在
childrenarray子关联元素列表CJoinElement
idinteger树节点的唯一IDCJoinElement
masterCActiveRelation主关系CJoinElement
modelCActiveRecord与树节点关联的模型CJoinElement
rawTableAliasstring此元素的引用表的别名CJoinElement
recordsarray此查询找到的活动记录列表,它们按主键值索引。CJoinElement
relationCActiveRelation此树节点表示的关系CJoinElement
slaveCActiveRelation从关系CJoinElement
statsarray元素列表CJoinElement
tableAliasstring关联元素的表别名CJoinElement

公共方法

隐藏继承方法

方法描述定义在
__construct()构造函数。CJoinElement
afterFind()调用所有记录的 CActiveRecord::afterFind .CJoinElement
beforeFind()调用 CActiveRecord::beforeFind.CJoinElement
buildQuery()建立关联查询并带有所有的依赖 HAS_ONE 和 BELONGS_TO 结点.CJoinElement
count()返回关联语句查询出来的主记录的数目。CJoinElement
destroy()删除引用的子元素和查询,以避免循环引用。CJoinElement
find()根据查询实体执行循环轮询查找。CJoinElement
findWithBase()当基本记录可用的时候,执行预先加载。CJoinElement
getColumnPrefix()返回关联的字段前缀以用来消除歧义。CJoinElement
getColumnSelect()生成要查询的字段列表。CJoinElement
getJoinCondition()返回返回关联语句(这个结点与它的父结点连接)CJoinElement
getPrimaryKeyRange()返回根据查询的主键值指定行的条件。CJoinElement
getPrimaryKeySelect()返回返回主键的选择CJoinElement
getTableNameWithAlias()返回返回表名和表别名(若有),这个可以无须转义直接在SQL查询中使用。CJoinElement
lazyFind()根据指定的基记录来执行延迟查找。CJoinElement
runQuery()执行关联查询并填充查询结果。CJoinElement

属性详细

children 属性 public array $children;

子关联元素列表

id 属性 public integer $id;

树节点的唯一ID

master 属性 public CActiveRelation $master;

主关系

model 属性 public CActiveRecord $model;

与树节点关联的模型

rawTableAlias 属性 public string $rawTableAlias;

此元素的引用表的别名

records 属性 public array $records;

此查询找到的活动记录列表,它们按主键值索引。

relation 属性 public CActiveRelation $relation;

此树节点表示的关系

slave 属性 public CActiveRelation $slave;

从关系

stats 属性 public array $stats;

元素列表

tableAlias 属性 public string $tableAlias;

关联元素的表别名

方法详细

__construct() 方法
public void __construct(CActiveFinder $finder, mixed $relation, CJoinElement $parent=NULL, integer $id=0)
$finderCActiveFinder查询对象
$relationmixed关联到这个树节点的关系(如果第三个参数不为 null), 或者是模型(如果第三个参数为 null)。
$parentCJoinElement父树节点
$idinteger此树结点的ID,在所有树结点中是唯一的
源码: framework/db/ar/CActiveFinder.php#386 (显示) publicfunction__construct($finder,$relation,$parent=null,$id=0)
{
$this->_finder=$finder;
$this->id=$id;
if($parent!==null)
{
$this->relation=$relation;
$this->_parent=$parent;
$this->model=CActiveRecord::model($relation->className);
$this->_builder=$this->model->getCommandBuilder();
$this->tableAlias=$relation->alias===null?$relation->name:$relation->alias;
$this->rawTableAlias=$this->_builder->getSchema()->quoteTableName($this->tableAlias);
$this->_table=$this->model->getTableSchema();
}
else//rootelement,thefirstparameteristhemodel.
{
$this->model=$relation;
$this->_builder=$relation->getCommandBuilder();
$this->_table=$relation->getTableSchema();
$this->tableAlias=$this->model->getTableAlias();
$this->rawTableAlias=$this->_builder->getSchema()->quoteTableName($this->tableAlias);
}

//setupcolumnaliases,suchast1_c2
$table=$this->_table;
if($this->model->getDbConnection()->getDriverName()==='oci')//Issue482
$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;
elseif(is_array($table->primaryKey)&&in_array($name,$table->primaryKey))
$this->_pkAlias[$name]=$alias;
}
}

构造函数。

afterFind() 方法
public void afterFind()
源码: framework/db/ar/CActiveFinder.php#781 (显示) publicfunctionafterFind()
{
foreach($this->recordsas$record)
$record->afterFindInternal();
foreach($this->childrenas$child)
$child->afterFind();

$this->children=null;
}

调用所有记录的 CActiveRecord::afterFind .

beforeFind() 方法
public void beforeFind(boolean $isChild=true)
$isChildboolean是否作为一个子节点调用
源码: framework/db/ar/CActiveFinder.php#769 (显示) publicfunctionbeforeFind($isChild=true)
{
if($isChild)
$this->model->beforeFindInternal();

foreach($this->childrenas$child)
$child->beforeFind(true);
}

调用 CActiveRecord::beforeFind.

buildQuery() 方法
public void buildQuery(CJoinQuery $query)
$queryCJoinQuery此查询被建立
源码: framework/db/ar/CActiveFinder.php#795 (显示) publicfunctionbuildQuery($query)
{
foreach($this->childrenas$child)
{
if($child->master!==null)
$child->_joined=true;
elseif($child->relationinstanceofCHasOneRelation||$child->relationinstanceofCBelongsToRelation
||$this->_finder->joinAll||$child->relation->together||(!$this->_finder->baseLimited&&$child->relation->together===null))
{
$child->_joined=true;
$query->join($child);
$child->buildQuery($query);
}
}
}

建立关联查询并带有所有的依赖 HAS_ONE 和 BELONGS_TO 结点.

count() 方法
public string count(CDbCriteria $criteria=NULL)
$criteriaCDbCriteria查询条件
{return}string返回主记录的数量。 注意: 类型为字符串保持最大精度。
源码: framework/db/ar/CActiveFinder.php#738 (显示) publicfunctioncount($criteria=null)
{
$query=newCJoinQuery($this,$criteria);
//ensureonlyonebigjoinstatementisused
$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);
elseif(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();
}

返回关联语句查询出来的主记录的数目。

destroy() 方法
public void destroy()
源码: framework/db/ar/CActiveFinder.php#430 (显示) publicfunctiondestroy()
{
if(!empty($this->children))
{
foreach($this->childrenas$child)
$child->destroy();
}
unset($this->_finder,$this->_parent,$this->model,$this->relation,$this->master,$this->slave,$this->records,$this->children,$this->stats);
}

删除引用的子元素和查询,以避免循环引用。 这个方法是内部使用。

find() 方法
public void find(CDbCriteria $criteria=NULL)
$criteriaCDbCriteriathe query criteria
源码: framework/db/ar/CActiveFinder.php#444 (显示) publicfunctionfind($criteria=null)
{
if($this->_parent===null)//rootelement
{
$query=newCJoinQuery($this,$criteria);
$this->_finder->baseLimited=($criteria->offset>=0||$criteria->limit>=0);
$this->buildQuery($query);
$this->_finder->baseLimited=false;
$this->runQuery($query);
}
elseif(!$this->_joined&&!empty($this->_parent->records))//notjoinedbefore
{
$query=newCJoinQuery($this->_parent);
$this->_joined=true;
$query->join($this);
$this->buildQuery($query);
$this->_parent->runQuery($query);
}

foreach($this->childrenas$child)//findrecursively
$child->find();

foreach($this->statsas$stat)
$stat->query();
}

根据查询实体执行循环轮询查找。

findWithBase() 方法
public void findWithBase(mixed $baseRecords)
$baseRecordsmixed可用的基本记录。
源码: framework/db/ar/CActiveFinder.php#702 (显示) publicfunctionfindWithBase($baseRecords)
{
if(!is_array($baseRecords))
$baseRecords=array($baseRecords);
if(is_string($this->_table->primaryKey))
{
foreach($baseRecordsas$baseRecord)
$this->records[$baseRecord->{$this->_table->primaryKey}]=$baseRecord;
}
else
{
foreach($baseRecordsas$baseRecord)
{
$pk=array();
foreach($this->_table->primaryKeyas$name)
$pk[$name]=$baseRecord->$name;
$this->records[serialize($pk)]=$baseRecord;
}
}

$query=newCJoinQuery($this);
$this->buildQuery($query);
if(count($query->joins)>1)
$this->runQuery($query);
foreach($this->childrenas$child)
$child->find();

foreach($this->statsas$stat)
$stat->query();
}

当基本记录可用的时候,执行预先加载。

getColumnPrefix() 方法
public string getColumnPrefix()
{return}string关联的字段前缀以用来消除歧义。
源码: framework/db/ar/CActiveFinder.php#1028 (显示) publicfunctiongetColumnPrefix()
{
if($this->tableAlias!==null)
return$this->rawTableAlias.'.';
else
return$this->_table->rawName.'.';
}
getColumnSelect() 方法
public string getColumnSelect(mixed $select='*')
$selectmixed要查询的字段,默认值为 '*', 指示所有的字段。
{return}string返回字段选择
源码: framework/db/ar/CActiveFinder.php#919 (显示) publicfunctiongetColumnSelect($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($selectas$name)
{
$name=trim($name);
$matches=array();
if(($pos=strrpos($name,'.'))!==false)
$key=substr($name,$pos+1);
else
$key=$name;
$key=trim($key,''"`');

if($key==='*')
{
foreach($this->_table->columnsas$name=>$column)
{
$alias=$this->_columnAliases[$name];
if(!isset($selected[$alias]))
{
$columns[]=$prefix.$column->rawName.'AS'.$schema->quoteColumnName($alias);
$selected[$alias]=1;
}
}
continue;
}

if(isset($this->_columnAliases[$key]))//simplecolumnnames
{
$columns[]=$prefix.$schema->quoteColumnName($key).'AS'.$schema->quoteColumnName($this->_columnAliases[$key]);
$selected[$this->_columnAliases[$key]]=1;
}
elseif(preg_match('/^(.*?)s+ASs+(w+)$/im',$name,$matches))//ifthecolumnisalreadyaliased
{
$alias=$matches[2];
if(!isset($this->_columnAliases[$alias])||$this->_columnAliases[$alias]!==$alias)
{
$this->_columnAliases[$alias]=$alias;
$columns[]=$name;
$selected[$alias]=1;
}
}
else
thrownewCDbException(Yii::t('yii','Activerecord"{class}"istryingtoselectaninvalidcolumn"{column}".Note,thecolumnmustexistinthetableorbeanexpressionwithalias.',
array('{class}'=>get_class($this->model),'{column}'=>$name)));
}
//addprimarykeyselectioniftheyarenotselected
if(is_string($this->_pkAlias)&&!isset($selected[$this->_pkAlias]))
$columns[]=$prefix.$schema->quoteColumnName($this->_table->primaryKey).'AS'.$schema->quoteColumnName($this->_pkAlias);
elseif(is_array($this->_pkAlias))
{
foreach($this->_table->primaryKeyas$name)
if(!isset($selected[$name]))
$columns[]=$prefix.$schema->quoteColumnName($name).'AS'.$schema->quoteColumnName($this->_pkAlias[$name]);
}
}

returnimplode(',',$columns);
}

生成要查询的字段列表。 字段会正确处理别名,如果没有指定主键,那么会自动将主键加到查询语句。

getJoinCondition() 方法
public string getJoinCondition()
{return}string返回关联语句(这个结点与它的父结点连接)
源码: framework/db/ar/CActiveFinder.php#1039 (显示) publicfunctiongetJoinCondition()
{
$parent=$this->_parent;
if($this->relationinstanceofCManyManyRelation)
{
if(!preg_match('/^s*(.*?)((.*))s*$/',$this->relation->foreignKey,$matches))
thrownewCDbException(Yii::t('yii','Therelation"{relation}"inactiverecordclass"{class}"isspecifiedwithaninvalidforeignkey.Theformatoftheforeignkeymustbe"joinTable(fk1,fk2,...)".',
array('{class}'=>get_class($parent->model),'{relation}'=>$this->relation->name)));

$schema=$this->_builder->getSchema();
if(($joinTable=$schema->getTable($matches[1]))===null)
thrownewCDbException(Yii::t('yii','Therelation"{relation}"inactiverecordclass"{class}"isnotspecifiedcorrectly:thejointable"{joinTable}"givenintheforeignkeycannotbefoundinthedatabase.',
array('{class}'=>get_class($parent->model),'{relation}'=>$this->relation->name,'{joinTable}'=>$matches[1])));
$fks=preg_split('/s*,s*/',$matches[2],-1,PREG_SPLIT_NO_EMPTY);

return$this->joinManyMany($joinTable,$fks,$parent);
}
else
{
$fks=is_array($this->relation->foreignKey)?$this->relation->foreignKey:preg_split('/s*,s*/',$this->relation->foreignKey,-1,PREG_SPLIT_NO_EMPTY);
if($this->relationinstanceofCBelongsToRelation)
{
$pke=$this;
$fke=$parent;
}
elseif($this->slave===null)
{
$pke=$parent;
$fke=$this;
}
else
{
$pke=$this;
$fke=$this->slave;
}
return$this->joinOneMany($fke,$fks,$pke,$parent);
}
}
getPrimaryKeyRange() 方法
public string getPrimaryKeyRange()
{return}string根据查询的主键值指定行的条件。
源码: framework/db/ar/CActiveFinder.php#1012 (显示) publicfunctiongetPrimaryKeyRange()
{
if(empty($this->records))
return'';
$values=array_keys($this->records);
if(is_array($this->_table->primaryKey))
{
foreach($valuesas&$value)
$value=unserialize($value);
}
return$this->_builder->createInCondition($this->_table,$this->_table->primaryKey,$values,$this->getColumnPrefix());
}
getPrimaryKeySelect() 方法
public string getPrimaryKeySelect()
{return}string返回主键的选择
源码: framework/db/ar/CActiveFinder.php#994 (显示) publicfunctiongetPrimaryKeySelect()
{
$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);
elseif(is_array($this->_pkAlias))
{
foreach($this->_pkAliasas$name=>$alias)
$columns[]=$prefix.$schema->quoteColumnName($name).'AS'.$schema->quoteColumnName($alias);
}
returnimplode(',',$columns);
}
getTableNameWithAlias() 方法
public string getTableNameWithAlias()
{return}string返回表名和表别名(若有),这个可以无须转义直接在SQL查询中使用。
源码: framework/db/ar/CActiveFinder.php#905 (显示) publicfunctiongetTableNameWithAlias()
{
if($this->tableAlias!==null)
return$this->_table->rawName.''.$this->rawTableAlias;
else
return$this->_table->rawName;
}
lazyFind() 方法
public void lazyFind(CActiveRecord $baseRecord)
$baseRecordCActiveRecord要被获取活动记录的相关对象
源码: framework/db/ar/CActiveFinder.php#474 (显示) publicfunctionlazyFind($baseRecord)
{
if(is_string($this->_table->primaryKey))
$this->records[$baseRecord->{$this->_table->primaryKey}]=$baseRecord;
else
{
$pk=array();
foreach($this->_table->primaryKeyas$name)
$pk[$name]=$baseRecord->$name;
$this->records[serialize($pk)]=$baseRecord;
}

foreach($this->statsas$stat)
$stat->query();

switch(count($this->children))
{
case0:
return;
break;
case1:
$child=reset($this->children);
break;
default://bridge(s)inside
$child=end($this->children);
break;
}

$query=newCJoinQuery($child);
$query->selects=array();
$query->selects[]=$child->getColumnSelect($child->relation->select);
$query->conditions=array();
$query->conditions[]=$child->relation->condition;
$query->conditions[]=$child->relation->on;
$query->groups[]=$child->relation->group;
$query->joins[]=$child->relation->join;
$query->havings[]=$child->relation->having;
$query->orders[]=$child->relation->order;
if(is_array($child->relation->params))
$query->params=$child->relation->params;
$query->elements[$child->id]=true;
if($child->relationinstanceofCHasManyRelation)
{
$query->limit=$child->relation->limit;
$query->offset=$child->relation->offset;
}

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

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

$this->_finder->baseLimited=false;
$child->buildQuery($query);
$child->runQuery($query);
foreach($child->childrenas$c)
$c->find();

if(empty($child->records))
return;
if($child->relationinstanceofCHasOneRelation||$child->relationinstanceofCBelongsToRelation)
$baseRecord->addRelatedRecord($child->relation->name,reset($child->records),false);
else//has_manyandmany_many
{
foreach($child->recordsas$record)
{
if($child->relation->index!==null)
$index=$record->{$child->relation->index};
else
$index=true;
$baseRecord->addRelatedRecord($child->relation->name,$record,$index);
}
}
}

根据指定的基记录来执行延迟查找。

runQuery() 方法
public void runQuery(CJoinQuery $query)
$queryCJoinQuery要被执行的查询。
源码: framework/db/ar/CActiveFinder.php#815 (显示) publicfunctionrunQuery($query)
{
$command=$query->createCommand($this->_builder);
foreach($command->queryAll()as$row)
$this->populateRecord($query,$row);
}

执行关联查询并填充查询结果。