Skip to content

Instantly share code, notes, and snippets.

@luckily
Last active November 24, 2015 09:54
Show Gist options
  • Save luckily/fe48cf69216a49dc433f to your computer and use it in GitHub Desktop.
Save luckily/fe48cf69216a49dc433f to your computer and use it in GitHub Desktop.
yii 1.1 CActiveRecord eager load behavior
<?php
class ActiveEagerLoader extends CActiveRecordBehavior
{
private $_relationKeys = array();
public function with($keys = array())
{
if(!is_array($keys))
throw new Exception('Only support array type values');
$this->_relationKeys = $keys;
return $this;
}
public function findAll($condition = '', $params = array())
{
$criteria = $this->owner->getCommandBuilder()->createCriteria($condition, $params);
if(!empty($this->_relationKeys))
return $this->query($criteria, true);
return $this->owner->findAll($condition, $params);
}
public function find($condition = '', $params = array())
{
$criteria = $this->owner->getCommandBuilder()->createCriteria($condition, $params);
if(!empty($this->_relationKeys))
return $this->query($criteria);
return $this->owner->find($condition, $params);
}
protected function query($criteria, $all = false)
{
$this->owner->beforeFindInternal();
$this->owner->applyScopes($criteria);
$finder = $this->getEagerFinder($criteria);
return $finder->query($all);
}
protected function getEagerFinder($criteria)
{
return new EagerFinder($this->owner, $criteria, $this->_relationKeys);
}
}
<?php
class EagerFinder extends CComponent
{
// const BELONGS_TO = 'CBelongsToRelation';
// const HAS_ONE = 'CHasOneRelation';
// const HAS_MANY = 'CHasManyRelation';
// const MANY_MANY = 'CManyManyRelation';
// const STAT = 'CStatRelation';
private $_mainModel = null;
private $_builder = null;
private $_dbCriteria = null;
private $_relationKeys = array();
public function __construct($model, $criteria, $relationKeys)
{
$this->_mainModel = $model;
$this->_builder = $model->getCommandBuilder();
$this->_dbCriteria = $criteria;
$this->_relationKeys = $relationKeys;
}
public function query($all = false)
{
Yii::trace(get_class($this).__METHOD__);
if(($rows = $this->_builder->createFindCommand($this->_mainModel->getTableSchema(), $this->_dbCriteria)->queryAll())!==array())
{
$baseRecords = $this->_mainModel->populateRecords($rows, false);
return $this->populateRecordsWithRelation($baseRecords);
}
else
{
return array();
}
}
public function populateRecordsWithRelation($mainModels)
{
Yii::trace(get_class($this).__METHOD__);
/**
* formula:'VarName'=>array('RelationType', 'ClassName', 'ForeignKey', ...additional options)
*/
$tempData = array();
foreach($this->_relationKeys as $relationAttributeName)
{
if(isset($this->_mainModel->relations()[$relationAttributeName]))
{
$relationSetting = $this->_mainModel->relations()[$relationAttributeName];
switch ($relationSetting[0]) {
case CActiveRecord::BELONGS_TO:
$foreignKey = $relationSetting[2];
$relationConditionIds = array();
foreach($mainModels as $mainModel)
{
$relationConditionIds[] = $mainModel->$foreignKey;
}
$criteria = new CDbCriteria;
$criteria->addInCondition('id', array_unique($relationConditionIds));
$relationModels = $this->getModel($relationSetting[1])->findAll($criteria);
foreach ($mainModels as $mainModel)
{
$populateModel = array_filter($relationModels, function($relationModel) use($mainModel, $foreignKey) {
return $mainModel->$foreignKey == $relationModel->id;
});
$mainModel->addRelatedRecord($relationAttributeName, reset($populateModel), false);
}
break;
case CActiveRecord::HAS_ONE:
var_dump($relationSetting);exit;
break;
case CActiveRecord::HAS_MANY:
var_dump($relationSetting);exit;
break;
case CActiveRecord::MANY_MANY:
var_dump($relationSetting);exit;
break;
default:
throw new Exception("can not find {$relationAttributeName} relation setting.");
break;
}
return $mainModels;
}
throw new Exception("can not find {$relationKey} relation setting.");
}
}
public function getModel($className)
{
return CActiveRecord::model($className);
}
/**
* 1.先趴$with, 存成陣列
* 2.解析陣列with, 然後再一一解析, master-model是否有跟with陣列的值對應到(可能要花時間瞭解model的relations()有哪些規格形式)
* 3.1foreach with, 組成各別的query
* 3.2如果with裡面還有再關連的東西, 就再遞回一次(額外功能,V2版本再做)
* 4.把master跟relation的model的query丟到querybuilder
* 5.把querybuilder的物件's做populate的動作
* 6.回傳master的models
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment