I just finished the new ActiveRecord design and implementation. Below is a summary of the main features of this new design. Your feedback are greatly appreciated.
[size="4"]Class Declaration[/size]
Please refer to the attached ER diagram for the sample data. We can declare the corresponding AR classes as follows. You may notice they differ from 1.x syntax in several places:
-
No more model() method.
-
tableName(), relations(), scopes() are now static methods. Several other methods are also turned into static.
-
The relation declaration syntax is changed. We now only differentiate two kinds of relations: has one and has many. Foreign key constraints are specified using ‘link’ option. And the ‘via’ option is equivalent to the ‘through’ option in 1.x.
-
Scopes must be declared in scopes() using anonymous functions.
-
The token "@." and "?." can be used in queries and scopes to represent the table alias prefix to columns. The former represents the self table, the latter the foreign table.
class Customer extends ActiveRecord
{
const STATUS_ACTIVE = 1;
const STATUS_INACTIVE = 2;
public static function tableName()
{
return 'tbl_customer';
}
public static function relations()
{
return array(
'orders:Order[]' => array(
'link' => array('customer_id' => 'id'),
),
);
}
public static function scopes()
{
return array(
'active' => function($q) {
return $q->andWhere('@.`status` = ' . self::STATUS_ACTIVE);
},
);
}
}
class Item extends ActiveRecord
{
public static function tableName()
{
return 'tbl_item';
}
}
class OrderItem extends ActiveRecord
{
public static function tableName()
{
return 'tbl_order_item';
}
public static function relations()
{
return array(
'order:Order' => array(
'link' => array('order_id' => 'id'),
),
'item:Item' => array(
'link' => array('item_id' => 'id'),
),
);
}
}
class Order extends ActiveRecord
{
public static function tableName()
{
return 'tbl_order';
}
public static function relations()
{
return array(
'customer:Customer' => array(
'link' => array('id' => 'customer_id'),
),
'orderItems:OrderItem' => array(
'link' => array('order_id' => 'id'),
),
// via another relation
'items:Item[]' => array(
'via' => 'orderItems',
'link' => array(
'id' => 'item_id',
),
'order' => '@.id',
),
// via a join table
'books:Item[]' => array(
'joinType' => 'INNER JOIN',
'via' => array(
'table' => 'tbl_order_item',
'link' => array(
'order_id' => 'id',
),
),
'link' => array(
'id' => 'item_id',
),
'on' => '@.category_id = 1',
),
);
}
}
[size="4"]Query Interface[/size]
Only three methods are directly provided in AR: find(), findBySql() and count(). They all return a new instance of ActiveQuery which provides typical query building methods, such as select(), from(), etc.
Below are some examples:
// equivalent to Customer::model()->find() in 1.x
$customer = Customer::find()->one();
// equivalent to Customer::model()->findAll() in 1.x
$customers = Customer::find()->all();
// same as above except that each customer data is returned as an array
$customers = Customer::find()->asArray()->all();
// equivalent to Customer::model()->findBySql(...) in 1.x
$customer = Customer::findBySql('SELECT * FROM tbl_customer')->one();
// iterator support
foreach (Customer::find() as $customer)
// array access support
// $customers is an ActiveQuery object
$customers = Customer::find(); $customer = $customers[0];
// equivalent to Customer::model()->findByPk(2) in 1.x
$customer = Customer::find(2)->one();
// equivalent to Customer::model()->findAllByAttributes(array('name'=>'customer1')) in 1.x
$customers = Customer::find()->where(array('name'=>'customer1'))->all();
// chained query methods
$customers = Customer::find()
->where('name like :name', array(':name' => '%customer%'))
->order('id')
->all();
// or equivalently:
$customers = Customer::find(array(
'where' => 'name like :name',
'params' => array(':name' => '%customer%'),
'order' => 'id',
))->all();
// equivalent to Customer::model()->count() in 1.x
$count = Customer::count()->value();
// eager relational query
$customers = Customer::find()->with('orders')->all();
// lazy relation query
$orders = $customer->orders;
// scope usage
$customers = Customer::find()->active()->all();