Browse Source

finished draft implementation of new AR.

tags/2.0.0-beta
Qiang Xue 12 years ago
parent
commit
30c52fad96
  1. 21
      framework/db/ar/ActiveQuery.php
  2. 2
      framework/db/ar/ActiveRecord.php
  3. 86
      framework/db/ar/ActiveRelation.php
  4. 2
      framework/test/TestCase.php
  5. 2
      tests/unit/data/ar/Customer.php
  6. 5
      tests/unit/data/ar/Order.php
  7. 57
      tests/unit/framework/base/ObjectTest.php

21
framework/db/ar/ActiveQuery.php

@ -66,14 +66,15 @@ class ActiveQuery extends BaseQuery
{
$command = $this->createCommand();
$rows = $command->queryAll();
if ($rows === array()) {
return array();
}
if ($rows !== array()) {
$models = $this->createModels($rows);
if (!empty($this->with)) {
$this->fetchRelatedModels($models, $this->with);
}
return $models;
} else {
return array();
}
}
/**
@ -86,11 +87,7 @@ class ActiveQuery extends BaseQuery
{
$command = $this->createCommand();
$row = $command->queryRow();
if ($row === false) {
return false;
} elseif ($this->asArray) {
return $row;
} else {
if ($row !== false && !$this->asArray) {
/** @var $class ActiveRecord */
$class = $this->modelClass;
$model = $class::create($row);
@ -100,6 +97,8 @@ class ActiveQuery extends BaseQuery
$model = $models[0];
}
return $model;
} else {
return $row === false ? null : $row;
}
}
@ -126,17 +125,13 @@ class ActiveQuery extends BaseQuery
/**
* Creates a DB command that can be used to execute this query.
* @param Connection $db the database connection used to generate the SQL statement.
* If this parameter is not given, the `db` application component will be used.
* @return Command the created DB command instance.
*/
public function createCommand($db = null)
public function createCommand()
{
/** @var $modelClass ActiveRecord */
$modelClass = $this->modelClass;
if ($db === null) {
$db = $modelClass::getDbConnection();
}
if ($this->sql === null) {
if ($this->from === null) {
$tableName = $modelClass::tableName();

2
framework/db/ar/ActiveRecord.php

@ -878,7 +878,7 @@ abstract class ActiveRecord extends Model
public static function create($row)
{
$record = static::instantiate($row);
$columns = static::model()->getTableSchema()->columns;
$columns = static::getTableSchema()->columns;
foreach ($row as $name => $value) {
if (isset($columns[$name])) {
$record->_attributes[$name] = $value;

86
framework/db/ar/ActiveRelation.php

@ -59,12 +59,21 @@ class ActiveRelation extends ActiveQuery
return $this;
}
public function createCommand($db = null)
public function createCommand()
{
if ($this->primaryModel !== null) {
$this->filterByPrimaryModels(array($this->primaryModel));
if ($this->via !== null) {
/** @var $viaQuery ActiveRelation */
$viaName = $this->via;
$viaQuery = $this->$viaName();
$primaryModels = array($this->primaryModel);
$viaModels = $viaQuery->findWith($viaName, $primaryModels);
$this->filterByModels($viaModels);
} else {
$this->filterByModels(array($this->primaryModel));
}
}
return parent::createCommand($db);
return parent::createCommand();
}
public function findWith($name, &$primaryModels)
@ -74,44 +83,81 @@ class ActiveRelation extends ActiveQuery
}
if ($this->via !== null) {
/** @var $viaQuery ActiveRelation */
$viaName = $this->via;
$viaQuery = $this->$viaName();
$viaModels = $viaQuery->findWith($viaName, $primaryModels);
$this->filterByModels($viaModels);
} else {
$this->filterByModels($primaryModels);
}
$this->filterByPrimaryModels($primaryModels);
if (count($primaryModels) === 1 && !$this->multiple) {
$model = $this->one();
foreach ($primaryModels as $i => $primaryModel) {
$primaryModels[$i][$name] = $this->one();
$primaryModels[$i][$name] = $model;
}
return array($model);
} else {
$models = $this->all();
$this->bindModels($name, $primaryModels, $models);
if (isset($viaModels, $viaQuery)) {
$buckets = $this->buildBuckets($models, $this->link, $viaModels, $viaQuery->link);
} else {
$buckets = $this->buildBuckets($models, $this->link);
}
foreach ($primaryModels as $i => $primaryModel) {
if (isset($viaQuery)) {
$key = $this->getModelKey($primaryModel, array_values($viaQuery->link));
} else {
$key = $this->getModelKey($primaryModel, array_values($this->link));
}
if (isset($buckets[$key])) {
$primaryModels[$i][$name] = $buckets[$key];
} else {
$primaryModels[$i][$name] = $this->multiple ? array() : null;
}
}
return $models;
}
}
protected function bindModels($name, &$primaryModels, $models)
protected function buildBuckets($models, $link, $viaModels = null, $viaLink = null)
{
$buckets = array();
foreach ($models as $i => $model) {
$key = $this->getModelKey($model, array_keys($this->link));
$key = $this->getModelKey($model, array_keys($link));
if ($this->index !== null) {
$buckets[$key][$i] = $model;
} else {
$buckets[$key][] = $model;
}
}
if ($viaModels !== null) {
$viaBuckets = array();
foreach ($viaModels as $viaModel) {
$key1 = $this->getModelKey($viaModel, array_keys($viaLink));
$key2 = $this->getModelKey($viaModel, array_values($link));
if (isset($buckets[$key2])) {
foreach ($buckets[$key2] as $i => $bucket) {
if ($this->index !== null) {
$viaBuckets[$key1][$i] = $bucket;
} else {
$viaBuckets[$key1][] = $bucket;
}
}
}
}
$buckets = $viaBuckets;
}
if (!$this->multiple) {
foreach ($buckets as $i => $bucket) {
$buckets[$i] = reset($bucket);
}
}
foreach ($primaryModels as $i => $primaryModel) {
$key = $this->getModelKey($primaryModel, array_values($this->link));
if (isset($buckets[$key])) {
$primaryModels[$i][$name] = $buckets[$key];
} else {
$primaryModels[$i][$name] = $this->multiple ? array() : null;
}
}
return $buckets;
}
protected function getModelKey($model, $attributes)
@ -128,13 +174,13 @@ class ActiveRelation extends ActiveQuery
}
}
protected function filterByPrimaryModels($primaryModels)
protected function filterByModels($models)
{
$attributes = array_keys($this->link);
$values = array();
if (isset($links[1])) {
// composite keys
foreach ($primaryModels as $model) {
foreach ($models as $model) {
$v = array();
foreach ($this->link as $attribute => $link) {
$v[$attribute] = is_array($model) ? $model[$link] : $model->$link;
@ -144,7 +190,7 @@ class ActiveRelation extends ActiveQuery
} else {
// single key
$attribute = $this->link[$links[0]];
foreach ($primaryModels as $model) {
foreach ($models as $model) {
$values[] = is_array($model) ? $model[$attribute] : $model->$attribute;
}
}

2
framework/test/TestCase.php

@ -10,7 +10,9 @@
namespace yii\test;
require_once('PHPUnit/Runner/Version.php');
spl_autoload_unregister(array('YiiBase','autoload'));
require_once('PHPUnit/Autoload.php');
spl_autoload_register(array('YiiBase','autoload')); // put yii's autoloader at the end
/**
* TestCase is the base class for all test case classes.

2
tests/unit/data/ar/Customer.php

@ -22,7 +22,7 @@ class Customer extends ActiveRecord
* @param ActiveQuery $query
* @return ActiveQuery
*/
public function active($query)
public static function active($query)
{
return $query->andWhere(array('status' => self::STATUS_ACTIVE));
}

5
tests/unit/data/ar/Order.php

@ -22,8 +22,9 @@ class Order extends ActiveRecord
public function items()
{
return $this->hasMany('Item', array('id' => 'item_id'))
->via('orderItems')
->orderBy('id');
->via('orderItems', function($q) {
// additional query configuration
})->orderBy('id');
}
public function books()

57
tests/unit/framework/base/ObjectTest.php

@ -7,7 +7,7 @@ class Foo extends \yii\base\Object
public $prop;
}
class Bar extends \yii\base\Component implements \yii\base\Initable
class Bar extends \yii\base\Component
{
public $prop1;
public $prop2;
@ -41,30 +41,6 @@ class ObjectTest extends \yiiunit\TestCase
$this->object = null;
}
public function testNewInstance()
{
$foo = Foo::newInstance(array(
'prop' => array(
'test' => 'test',
),
));
$this->assertEquals('test', $foo->prop['test']);
$bar = Bar::newInstance(array(), 10, 20);
$this->assertEquals(30, $bar->prop1);
$this->assertEquals(null, $bar->prop2);
$this->assertEquals(3, $bar->prop3);
$bar = Bar::newInstance(array(
'prop2' => 'x',
'prop3' => 400,
), 100, 200);
$this->assertEquals(300, $bar->prop1);
$this->assertEquals('x', $bar->prop2);
$this->assertEquals(3, $bar->prop3);
}
public function testHasProperty()
{
$this->assertTrue($this->object->hasProperty('Text'), "Component hasn't property Text");
@ -88,19 +64,19 @@ class ObjectTest extends \yiiunit\TestCase
public function testGetProperty()
{
$this->assertTrue('default'===$this->object->Text);
$this->setExpectedException('yii\base\Exception');
$value2=$this->object->Caption;
$this->assertTrue('default' === $this->object->Text);
$this->setExpectedException('yii\base\BadPropertyException');
$value2 = $this->object->Caption;
}
public function testSetProperty()
{
$value='new value';
$this->object->Text=$value;
$text=$this->object->Text;
$this->assertTrue($value===$this->object->Text);
$this->setExpectedException('yii\base\Exception');
$this->object->NewMember=$value;
$value = 'new value';
$this->object->Text = $value;
$text = $this->object->Text;
$this->assertTrue($value === $this->object->Text);
$this->setExpectedException('yii\base\BadPropertyException');
$this->object->NewMember = $value;
}
public function testIsset()
@ -112,7 +88,7 @@ class ObjectTest extends \yiiunit\TestCase
$this->assertFalse(isset($this->object->Text));
$this->assertFalse(!empty($this->object->Text));
$this->object->Text='';
$this->object->Text = '';
$this->assertTrue(isset($this->object->Text));
$this->assertTrue(empty($this->object->Text));
}
@ -131,20 +107,19 @@ class NewObject extends \yii\base\Component
public function setText($value)
{
$this->_text=$value;
$this->_text = $value;
}
public function getObject()
{
if(!$this->_object)
{
$this->_object=new self;
$this->_object->_text='object text';
if (!$this->_object) {
$this->_object = new self;
$this->_object->_text = 'object text';
}
return $this->_object;
}
public function exprEvaluator($p1,$comp)
public function exprEvaluator($p1, $comp)
{
return "Hello $p1";
}

Loading…
Cancel
Save