From c9b104f0a1e935b0f0a66a831128386e9692c6b1 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 9 Jan 2013 16:50:17 -0500 Subject: [PATCH] refactored AR relation. --- framework/db/ActiveQuery.php | 19 +++++--- framework/db/ActiveRecord.php | 66 +++++++++++----------------- framework/db/ActiveRelation.php | 46 ++++++++++--------- tests/unit/data/ar/Customer.php | 2 +- tests/unit/data/ar/Order.php | 8 ++-- tests/unit/data/ar/OrderItem.php | 4 +- tests/unit/framework/db/ActiveRecordTest.php | 2 +- 7 files changed, 71 insertions(+), 76 deletions(-) diff --git a/framework/db/ActiveQuery.php b/framework/db/ActiveQuery.php index 813936b..0810620 100644 --- a/framework/db/ActiveQuery.php +++ b/framework/db/ActiveQuery.php @@ -251,16 +251,21 @@ class ActiveQuery extends Query $childName = null; } - if (!isset($relations[$name])) { - if (!method_exists($model, $name)) { + $t = strtolower($name); + if (!isset($relations[$t])) { + $getter = 'get' . $name; + if (!method_exists($model, $getter)) { + throw new Exception("Unknown relation: $name"); + } + $relation = $model->$getter(); + if ($relation instanceof ActiveRelation) { + $relation->primaryModel = null; + $relations[$t] = $relation; + } else { throw new Exception("Unknown relation: $name"); } - /** @var $relation ActiveRelation */ - $relation = $model->$name(); - $relation->primaryModel = null; - $relations[$name] = $relation; } else { - $relation = $relations[$name]; + $relation = $relations[$t]; } if (isset($childName)) { diff --git a/framework/db/ActiveRecord.php b/framework/db/ActiveRecord.php index 5075fae..0a3bbe3 100644 --- a/framework/db/ActiveRecord.php +++ b/framework/db/ActiveRecord.php @@ -284,18 +284,17 @@ abstract class ActiveRecord extends Model return $this->_attributes[$name]; } elseif (isset($this->getTableSchema()->columns[$name])) { return null; - } elseif (method_exists($this, $name)) { - // related records - if (isset($this->_related[$name]) || isset($this->_related) && array_key_exists($name, $this->_related)) { - return $this->_related[$name]; + } else { + $t = strtolower($name); + if (isset($this->_related[$t]) || $this->_related !== null && array_key_exists($t, $this->_related)) { + return $this->_related[$t]; + } + $value = parent::__get($name); + if ($value instanceof ActiveRelation) { + return $this->_related[$t] = $value->multiple ? $value->all() : $value->one(); } else { - // lazy loading related records - /** @var $relation ActiveRelation */ - $relation = $this->$name(); - return $this->_related[$name] = $relation->multiple ? $relation->all() : $relation->one(); + return $value; } - } else { - return parent::__get($name); } } @@ -309,8 +308,6 @@ abstract class ActiveRecord extends Model { if (isset($this->getTableSchema()->columns[$name])) { $this->_attributes[$name] = $value; - } elseif (method_exists($this, $name)) { - $this->_related[$name] = $value; } else { parent::__set($name, $value); } @@ -325,11 +322,13 @@ abstract class ActiveRecord extends Model */ public function __isset($name) { - if (isset($this->_attributes[$name]) || isset($this->_related[$name])) { - return true; - } elseif (isset($this->getTableSchema()->columns[$name]) || method_exists($this, $name)) { - return false; + if (isset($this->getTableSchema()->columns[$name])) { + return isset($this->_related[$name]); } else { + $t = strtolower($name); + if (isset($this->_related[$t])) { + return true; + } return parent::__isset($name); } } @@ -344,10 +343,13 @@ abstract class ActiveRecord extends Model { if (isset($this->getTableSchema()->columns[$name])) { unset($this->_attributes[$name]); - } elseif (method_exists($this, $name)) { - unset($this->_related[$name]); } else { - parent::__unset($name); + $t = strtolower($name); + if (isset($this->_related[$t])) { + unset($this->_related[$t]); + } else { + parent::__unset($name); + } } } @@ -399,30 +401,12 @@ abstract class ActiveRecord extends Model } /** - * Initializes the internal storage for the relation. - * This method is internally used by [[ActiveQuery]] when populating relation data. - * @param ActiveRelation $relation the relation object + * @param string $name + * @param mixed $value */ - public function initRelation($relation) + public function populateRelation($name, $value) { - $this->_related[$relation->name] = $relation->hasMany ? array() : null; - } - - /** - * @param ActiveRelation $relation - * @param ActiveRecord $record - */ - public function addRelatedRecord($relation, $record) - { - if ($relation->hasMany) { - if ($relation->indexBy !== null) { - $this->_related[$relation->name][$record->{$relation->indexBy}] = $record; - } else { - $this->_related[$relation->name][] = $record; - } - } else { - $this->_related[$relation->name] = $record; - } + $this->_related[$name] = $value; } /** diff --git a/framework/db/ActiveRelation.php b/framework/db/ActiveRelation.php index c654f89..f6d5683 100644 --- a/framework/db/ActiveRelation.php +++ b/framework/db/ActiveRelation.php @@ -51,17 +51,23 @@ class ActiveRelation extends ActiveQuery * @param string $relationName * @param callback $callback * @return ActiveRelation + * @throws Exception */ public function via($relationName, $callback = null) { - /** @var $relation ActiveRelation */ - $relation = $this->primaryModel->$relationName(); - $relation->primaryModel = null; - $this->via = array($relationName, $relation); - if ($callback !== null) { - call_user_func($callback, $relation); + $getter = 'get' . $relationName; + if (method_exists($this->primaryModel, $getter)) { + $relation = $this->primaryModel->$getter(); + if ($relation instanceof ActiveRelation) { + $relation->primaryModel = null; + $this->via = array($relationName, $relation); + if ($callback !== null) { + call_user_func($callback, $relation); + } + return $this; + } } - return $this; + throw new Exception('Unknown relation: ' . $relationName); } /** @@ -106,9 +112,11 @@ class ActiveRelation extends ActiveQuery list($viaName, $viaQuery) = $this->via; $viaQuery->primaryModel = $this->primaryModel; if ($viaQuery->multiple) { - $this->primaryModel->$viaName = $viaModels = $viaQuery->all(); + $viaModels = $viaQuery->all(); + $this->primaryModel->populateRelation($viaName, $viaModels); } else { - $this->primaryModel->$viaName = $model = $viaQuery->one(); + $model = $viaQuery->one(); + $this->primaryModel->populateRelation($viaName, $model); $viaModels = $model === null ? array() : array($model); } $this->filterByModels($viaModels); @@ -144,7 +152,11 @@ class ActiveRelation extends ActiveQuery if (count($primaryModels) === 1 && !$this->multiple) { $model = $this->one(); foreach ($primaryModels as $i => $primaryModel) { - $primaryModels[$i][$name] = $model; + if ($primaryModel instanceof ActiveRecord) { + $primaryModel->populateRelation($name, $model); + } else { + $primaryModels[$i][$name] = $model; + } } return array($model); } else { @@ -158,10 +170,11 @@ class ActiveRelation extends ActiveQuery $link = array_values(isset($viaQuery) ? $viaQuery->link : $this->link); foreach ($primaryModels as $i => $primaryModel) { $key = $this->getModelKey($primaryModel, $link); - if (isset($buckets[$key])) { - $primaryModels[$i][$name] = $buckets[$key]; + $value = isset($buckets[$key]) ? $buckets[$key] : ($this->multiple ? array() : null); + if ($primaryModel instanceof ActiveRecord) { + $primaryModel->populateRelation($name, $value); } else { - $primaryModels[$i][$name] = $this->multiple ? array() : null; + $primaryModels[$i][$name] = $value; } } return $models; @@ -262,11 +275,4 @@ class ActiveRelation extends ActiveQuery $sql = $db->getQueryBuilder()->build($this); return $db->createCommand($sql, $this->params)->queryAll(); } - - public function link($model) - { - /** - * 1. Set models - */ - } } diff --git a/tests/unit/data/ar/Customer.php b/tests/unit/data/ar/Customer.php index 5c42ecf..5464fc7 100644 --- a/tests/unit/data/ar/Customer.php +++ b/tests/unit/data/ar/Customer.php @@ -13,7 +13,7 @@ class Customer extends ActiveRecord return 'tbl_customer'; } - public function orders() + public function getOrders() { return $this->hasMany('Order', array('customer_id' => 'id')); } diff --git a/tests/unit/data/ar/Order.php b/tests/unit/data/ar/Order.php index 52645de..eb3462d 100644 --- a/tests/unit/data/ar/Order.php +++ b/tests/unit/data/ar/Order.php @@ -9,17 +9,17 @@ class Order extends ActiveRecord return 'tbl_order'; } - public function customer() + public function getCustomer() { return $this->hasOne('Customer', array('id' => 'customer_id')); } - public function orderItems() + public function getOrderItems() { return $this->hasMany('OrderItem', array('order_id' => 'id')); } - public function items() + public function getItems() { return $this->hasMany('Item', array('id' => 'item_id')) ->via('orderItems', function($q) { @@ -27,7 +27,7 @@ class Order extends ActiveRecord })->orderBy('id'); } - public function books() + public function getBooks() { return $this->hasMany('Item', array('id' => 'item_id')) ->viaTable('tbl_order_item', array('order_id' => 'id')) diff --git a/tests/unit/data/ar/OrderItem.php b/tests/unit/data/ar/OrderItem.php index 27e1c7e..f879749 100644 --- a/tests/unit/data/ar/OrderItem.php +++ b/tests/unit/data/ar/OrderItem.php @@ -9,12 +9,12 @@ class OrderItem extends ActiveRecord return 'tbl_order_item'; } - public function order() + public function getOrder() { return $this->hasOne('Order', array('id' => 'order_id')); } - public function item() + public function getItem() { return $this->hasOne('Item', array('id' => 'item_id')); } diff --git a/tests/unit/framework/db/ActiveRecordTest.php b/tests/unit/framework/db/ActiveRecordTest.php index b918953..a1edbd5 100644 --- a/tests/unit/framework/db/ActiveRecordTest.php +++ b/tests/unit/framework/db/ActiveRecordTest.php @@ -105,7 +105,7 @@ class ActiveRecordTest extends \yiiunit\MysqlTestCase $orders = $customer->orders; $this->assertEquals(2, count($orders)); - $orders = $customer->orders()->where('id=3')->all(); + $orders = $customer->getOrders()->where('id=3')->all(); $this->assertEquals(1, count($orders)); $this->assertEquals(3, $orders[0]->id); }