CJoinElement
| Пакет | system.db.ar |
|---|---|
| Наследование | класс CJoinElement |
| С версии | 1.0 |
| Исходный код | framework/db/ar/CActiveFinder.php |
Общественные свойства
| Свойство | Тип | Описание | Определено в |
|---|---|---|---|
| children | массив | список дочерних элементов объединения | CJoinElement |
| id | целое | уникальный идентификатор этого узла дерева | CJoinElement |
| master | CActiveRelation | главное отношение | CJoinElement |
| model | CActiveRecord | модель, связанная с этим узлом дерева | CJoinElement |
| rawTableAlias | строка | цитируемое имя таблицы для этого элемента | CJoinElement |
| records | массив | список записей активных моделей, найденных запросами. Индексируются значениями первичного ключа. | CJoinElement |
| relation | CActiveRelation | отношение, представленное этим узлом дерева | CJoinElement |
| slave | CActiveRelation | ведомое отношение | CJoinElement |
| stats | массив | список элементов статистики | CJoinElement |
| tableAlias | строка | псевдоним таблицы для этого элемента объединения | CJoinElement |
Общественные методы
| Метод | Описание | Определено в |
|---|---|---|
| __construct() | Конструктор. | CJoinElement |
| afterFind() | Вызывает CActiveRecord::afterFind для всех записей. | 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;
уникальный идентификатор этого узла дерева
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) | ||
| $finder | CActiveFinder | поисковик |
| $relation | смешанный тип | отношение (если третий параметр не равен null) или модель (если третий параметр равен null), связанная с этим узлом дерева. |
| $parent | CJoinElement | родительский узел дерева |
| $id | целое | идентификатор этого узла дерева, уникальный среди всех узлов дерева |
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->model=$this->_finder->getModel($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 // root element, the first parameter is the model.
{
$this->model=$relation;
$this->_builder=$relation->getCommandBuilder();
$this->_table=$relation->getTableSchema();
$this->tableAlias=$this->model->getTableAlias();
$this->rawTableAlias=$this->_builder->getSchema()->quoteTableName($this->tableAlias);
}
// 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;
elseif(is_array($table->primaryKey) && in_array($name,$table->primaryKey))
$this->_pkAlias[$name]=$alias;
}
}
Конструктор.
afterFind() метод
public void afterFind() |
public function afterFind()
{
foreach($this->records as $record)
$record->afterFindInternal();
foreach($this->children as $child)
$child->afterFind();
$this->children = null;
}
Вызывает CActiveRecord::afterFind для всех записей.
buildQuery() метод
public void buildQuery(CJoinQuery $query) | ||
| $query | CJoinQuery | запрос, который строится |
public function buildQuery($query)
{
foreach($this->children as $child)
{
if($child->master!==null)
$child->_joined=true;
elseif($child->relation instanceof CHasOneRelation || $child->relation instanceof CBelongsToRelation
|| $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) | ||
| $criteria | CDbCriteria | критерии запроса |
| {return} | строка | количество записей основной таблицы. Примечание: тип является строкой для сохранения максимальной точности. |
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);
$query->limit=$query->offset=-1;
if(!empty($criteria->group) || !empty($criteria->having))
{
$query->orders = array();
$command=$query->createCommand($this->_builder);
$sql=$command->getText();
$sql="SELECT COUNT(*) FROM ({$sql}) sq";
$command->setText($sql);
$command->params=$query->params;
return $command->queryScalar();
}
else
{
$select=is_array($criteria->select) ? implode(',',$criteria->select) : $criteria->select;
if($select!=='*' && preg_match('/^count\s*\(/i',trim($select)))
$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();
$command=$query->createCommand($this->_builder);
return $command->queryScalar();
}
}
Подсчитывает количество записей основной таблицы, возвращаемых оператором объединения.
destroy() метод
public void destroy() |
public function destroy()
{
if(!empty($this->children))
{
foreach($this->children as $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) | ||
| $criteria | CDbCriteria | критерии запроса |
public function find($criteria=null)
{
if($this->_parent===null) // root element
{
$query=new CJoinQuery($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)) // 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();
}
Выполняет рекурсивный поиск с заданными критериями.
findWithBase() метод
public void findWithBase(mixed $baseRecords) | ||
| $baseRecords | смешанный тип | доступные базовые записи. |
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();
}
Выполняет жадный запрос с готовыми базовыми записями.
getColumnPrefix() метод
public string getColumnPrefix() | ||
| {возврат} | строка | префикс столбца для устранения неоднозначности ссылок на столбцы |
public function getColumnPrefix()
{
if($this->tableAlias!==null)
return $this->rawTableAlias.'.';
else
return $this->_table->rawName.'.';
}
getColumnSelect() метод
public string getColumnSelect(mixed $select='*') | ||
| $select | смешанный тип | столбцы для выбора. По умолчанию «*», означающее все столбцы. |
| {возврат} | строка | выбор столбцов |
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;
$key=trim($key,'\'"`');
if($key==='*')
{
foreach($this->_table->columns as $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])) // simple column names
{
$columns[]=$prefix.$schema->quoteColumnName($key).' AS '.$schema->quoteColumnName($this->_columnAliases[$key]);
$selected[$this->_columnAliases[$key]]=1;
}
elseif(preg_match('/^(.*?)\s+AS\s+(\w+)$/im',$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);
elseif(is_array($this->_pkAlias))
{
foreach($this->_pkAlias as $name=>$alias)
if(!isset($selected[$alias]))
$columns[]=$prefix.$schema->quoteColumnName($name).' AS '.$schema->quoteColumnName($alias);
}
}
return implode(', ',$columns);
}
Генерирует список столбцов для выбора. Столбцы будут правильно алиасированы, а первичные ключи будут добавлены к выбору, если они не указаны.
getJoinCondition() метод
public string getJoinCondition() | ||
| {возврат} | строка | запрос объединения (этот узел объединяется со своим родителем) |
public function getJoinCondition()
{
$parent=$this->_parent;
if($this->relation instanceof CManyManyRelation)
{
$schema=$this->_builder->getSchema();
$joinTableName=$this->relation->getJunctionTableName();
if(($joinTable=$schema->getTable($joinTableName))===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}'=>$joinTableName)));
$fks=$this->relation->getJunctionForeignKeys();
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->slave!==null)
{
if($this->relation instanceof CBelongsToRelation)
{
$fks=array_flip($fks);
$pke=$this->slave;
$fke=$this;
}
else
{
$pke=$this;
$fke=$this->slave;
}
}
elseif($this->relation instanceof CBelongsToRelation)
{
$pke=$this;
$fke=$parent;
}
else
{
$pke=$parent;
$fke=$this;
}
return $this->joinOneMany($fke,$fks,$pke,$parent);
}
}
getPrimaryKeyRange() метод
public string getPrimaryKeyRange() | ||
| {возврат} | строка | условие, которое задаёт только строки с выбранными значениями первичного ключа. |
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() метод
public string getPrimaryKeySelect() | ||
| {возврат} | строка | выбор первичного ключа |
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);
elseif(is_array($this->_pkAlias))
{
foreach($this->_pkAlias as $name=>$alias)
$columns[]=$prefix.$schema->quoteColumnName($name).' AS '.$schema->quoteColumnName($alias);
}
return implode(', ',$columns);
}
getTableNameWithAlias() метод
public string getTableNameWithAlias() | ||
| {возврат} | строка | имя таблицы и псевдоним таблицы (если есть). Это можно использовать непосредственно в запросе SQL без экранирования. |
public function getTableNameWithAlias()
{
if($this->tableAlias!==null)
return $this->_table->rawName . ' ' . $this->rawTableAlias;
else
return $this->_table->rawName;
}
lazyFind() метод
public void lazyFind(CActiveRecord $baseRecord) | ||
| $baseRecord | CActiveRecord | активная запись, связанный объект которой требуется получить. |
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(!$this->children)
return;
$params=array();
foreach($this->children as $child)
if(is_array($child->relation->params))
$params=array_merge($params,$child->relation->params);
$query=new CJoinQuery($child);
$query->selects=array($child->getColumnSelect($child->relation->select));
$query->conditions=array(
$child->relation->on,
);
$query->groups[]=$child->relation->group;
$query->joins[]=$child->relation->join;
$query->havings[]=$child->relation->having;
$query->orders[]=$child->relation->order;
$query->params=$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;
$this->_finder->baseLimited=false;
$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);
}
}
}
Выполняет ленивый поиск с указанной базовой записью.
runQuery() метод
public void runQuery(CJoinQuery $query) | ||
| $query | CJoinQuery | запрос, который необходимо выполнить. |
public function runQuery($query)
{
$command=$query->createCommand($this->_builder);
foreach($command->queryAll() as $row)
$this->populateRecord($query,$row);
}
Выполняет запрос объединения и заполняет результаты запроса.
© 2008–2017 by Yii Software LLC
Licensed under the three clause BSD license.
http://www.yiiframework.com/doc/api/1.1/CJoinElement