mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-01 11:39:41 +08:00
Merge pull request #19893 from PowerGamer1/fix12743
New methods: BaseActiveRecord::loadRelations() and BaseActiveRecord::loadRelationsFor().
This commit is contained in:
@ -4,7 +4,7 @@ Yii Framework 2 Change Log
|
|||||||
2.0.50 under development
|
2.0.50 under development
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
- no changes in this release.
|
- Enh #12743: Added new methods `BaseActiveRecord::loadRelations()` and `BaseActiveRecord::loadRelationsFor()` to eager load related models for existing primary model instances (PowerGamer1)
|
||||||
|
|
||||||
|
|
||||||
2.0.49.2 October 12, 2023
|
2.0.49.2 October 12, 2023
|
||||||
|
|||||||
@ -1787,4 +1787,57 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
|
|||||||
|
|
||||||
return $newValue !== $oldValue;
|
return $newValue !== $oldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eager loads related models for the already loaded primary models.
|
||||||
|
*
|
||||||
|
* Helps to reduce the number of queries performed against database if some related models are only used
|
||||||
|
* when a specific condition is met. For example:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $customers = Customer::find()->where(['country_id' => 123])->all();
|
||||||
|
* if (Yii:app()->getUser()->getIdentity()->canAccessOrders()) {
|
||||||
|
* Customer::loadRelationsFor($customers, 'orders.items');
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param array|ActiveRecordInterface[] $models array of primary models. Each model should have the same type and can be:
|
||||||
|
* - an active record instance;
|
||||||
|
* - active record instance represented by array (i.e. active record was loaded using [[ActiveQuery::asArray()]]).
|
||||||
|
* @param string|array $relationNames the names of the relations of primary models to be loaded from database. See [[ActiveQueryInterface::with()]] on how to specify this argument.
|
||||||
|
* @param bool $asArray whether to load each related model as an array or an object (if the relation itself does not specify that).
|
||||||
|
* @since 2.0.49
|
||||||
|
*/
|
||||||
|
public static function loadRelationsFor(&$models, $relationNames, $asArray = false)
|
||||||
|
{
|
||||||
|
// ActiveQueryTrait::findWith() called below assumes $models array is non-empty.
|
||||||
|
if (empty($models)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static::find()->asArray($asArray)->findWith((array)$relationNames, $models);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eager loads related models for the already loaded primary model.
|
||||||
|
*
|
||||||
|
* Helps to reduce the number of queries performed against database if some related models are only used
|
||||||
|
* when a specific condition is met. For example:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* $customer = Customer::find()->where(['id' => 123])->one();
|
||||||
|
* if (Yii:app()->getUser()->getIdentity()->canAccessOrders()) {
|
||||||
|
* $customer->loadRelations('orders.items');
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param string|array $relationNames the names of the relations of this model to be loaded from database. See [[ActiveQueryInterface::with()]] on how to specify this argument.
|
||||||
|
* @param bool $asArray whether to load each relation as an array or an object (if the relation itself does not specify that).
|
||||||
|
* @since 2.0.49
|
||||||
|
*/
|
||||||
|
public function loadRelations($relationNames, $asArray = false)
|
||||||
|
{
|
||||||
|
$models = [$this];
|
||||||
|
static::loadRelationsFor($models, $relationNames, $asArray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2225,6 +2225,53 @@ abstract class ActiveRecordTest extends DatabaseTestCase
|
|||||||
$attr = 'model2.doesNotExist.attr1';
|
$attr = 'model2.doesNotExist.attr1';
|
||||||
$this->assertEquals($model->generateAttributeLabel($attr), $model->getAttributeLabel($attr));
|
$this->assertEquals($model->generateAttributeLabel($attr), $model->getAttributeLabel($attr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testLoadRelations()
|
||||||
|
{
|
||||||
|
// Test eager loading relations for multiple primary models using loadRelationsFor().
|
||||||
|
/** @var Customer[] $customers */
|
||||||
|
$customers = Customer::find()->all();
|
||||||
|
Customer::loadRelationsFor($customers, ['orders.items']);
|
||||||
|
foreach ($customers as $customer) {
|
||||||
|
$this->assertTrue($customer->isRelationPopulated('orders'));
|
||||||
|
foreach ($customer->orders as $order) {
|
||||||
|
$this->assertTrue($order->isRelationPopulated('items'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test eager loading relations as arrays.
|
||||||
|
/** @var array $customers */
|
||||||
|
$customers = Customer::find()->asArray(true)->all();
|
||||||
|
Customer::loadRelationsFor($customers, ['orders.items' => function ($query) { $query->asArray(false); }], true);
|
||||||
|
foreach ($customers as $customer) {
|
||||||
|
$this->assertTrue(isset($customer['orders']));
|
||||||
|
$this->assertTrue(is_array($customer['orders']));
|
||||||
|
foreach ($customer['orders'] as $order) {
|
||||||
|
$this->assertTrue(is_array($order));
|
||||||
|
$this->assertTrue(isset($order['items']));
|
||||||
|
$this->assertTrue(is_array($order['items']));
|
||||||
|
foreach ($order['items'] as $item) {
|
||||||
|
$this->assertFalse(is_array($item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test eager loading relations for a single primary model using loadRelations().
|
||||||
|
/** @var Customer $customer */
|
||||||
|
$customer = Customer::find()->where(['id' => 1])->one();
|
||||||
|
$customer->loadRelations('orders.items');
|
||||||
|
$this->assertTrue($customer->isRelationPopulated('orders'));
|
||||||
|
foreach ($customer->orders as $order) {
|
||||||
|
$this->assertTrue($order->isRelationPopulated('items'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test eager loading previously loaded relation (relation value should be replaced with a new value loaded from database).
|
||||||
|
/** @var Customer $customer */
|
||||||
|
$customer = Customer::find()->where(['id' => 2])->with(['orders' => function ($query) { $query->orderBy(['id' => SORT_ASC]); }])->one();
|
||||||
|
$this->assertTrue($customer->orders[0]->id < $customer->orders[1]->id, 'Related models should be sorted by ID in ascending order.');
|
||||||
|
$customer->loadRelations(['orders' => function ($query) { $query->orderBy(['id' => SORT_DESC]); }]);
|
||||||
|
$this->assertTrue($customer->orders[0]->id > $customer->orders[1]->id, 'Related models should be sorted by ID in descending order.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LabelTestModel1 extends \yii\db\ActiveRecord
|
class LabelTestModel1 extends \yii\db\ActiveRecord
|
||||||
|
|||||||
Reference in New Issue
Block a user