$authors = Author::find()->with('posts')->all();
вытащит все что нужно 2мя запросами SELECT * FROM author;
SELECT * FROM post WHERE author_id IN (1, 3, 7, 10, ... X);
$authors = Author::find()->all(); //Без with()
и хочется как-бы применить with()
к массиву $authors
?<?php
namespace app\components;
use yii\base\Model;
use yii\db\ActiveQuery;
use yii\db\ActiveQueryInterface;
use yii\db\ActiveRecord;
class Eagerifier
{
/**
* @param $with
* @param Model[] $models
* @param bool $asArray
* @throws \yii\base\InvalidConfigException
*/
public static function populate($with, array &$models, $asArray = false)
{
$modelClass = '';
foreach ($models as $key => $model) {
$modelClass = $model->className();
break;
}
// From ActiveQuery::findWith()
$primaryModel = new $modelClass;
$relations = self::normalizeRelations($primaryModel, $with);
/* @var $relation ActiveQuery */
foreach ($relations as $name => $relation) {
if ($relation->asArray === null) {
// inherit asArray from primary query
$relation->asArray($asArray);
}
$relation->populateRelation($name, $models);
}
}
/**
* Adapted method from ActiveQuery
*
* @param ActiveRecord $model
* @param array $with
* @return ActiveQueryInterface[]
*/
private static function normalizeRelations($model, $with)
{
$relations = [];
foreach ($with as $name => $callback) {
if (is_int($name)) {
$name = $callback;
$callback = null;
}
if (($pos = strpos($name, '.')) !== false) {
// with sub-relations
$childName = substr($name, $pos + 1);
$name = substr($name, 0, $pos);
} else {
$childName = null;
}
if (!isset($relations[$name])) {
$relation = $model->getRelation($name);
$relation->primaryModel = null;
$relations[$name] = $relation;
} else {
$relation = $relations[$name];
}
if (isset($childName)) {
$relation->with[$childName] = $callback;
} elseif ($callback !== null) {
call_user_func($callback, $relation);
}
}
return $relations;
}
}
Eagerifier::populate(['posts'], $authors);
<?
$authors = Author::find()->all();
$authorsIds = ArrayHelper::getColumn($authors, 'id');
$allPosts = Posts::find()->where(['author_id' => $authorsIds])->orderBy('author_id')->all();
##### И далее чтобы вытащить все посты определенного автора
foreach($authors as $author) {
$author_id = $author->id;
$posts = ArrayHelper::getColumn($allPosts, function($element) use ($author_id){
if ($element['author_id'] == $author_id) {
return $element;
}
return false;
});
// Записываем в объект author данные связи с posts
$author->populateRelation('posts', $posts);
}
#### Теперь данные о постах можно спокойно доставать из модели Authors
$author = array_pop($authors);
var_dump($author->posts);
#### Все это можно инкапсулировать за статической функцией, например в классе Authors
public static function fillPosts($authors)
{
$authorsIds = ArrayHelper::getColumn($authors, 'id');
$allPosts = Posts::find()->where(['author_id' => $authorsIds])->orderBy('author_id')->all();
foreach($authors as $author) {
$author_id = $author->id;
$posts = ArrayHelper::getColumn($allPosts, function($element) use ($author_id){
if ($element['author_id'] == $author_id) {
return $element;
}
return false;
});
// Записываем в объект author данные связи с posts
$author->populateRelation('posts', $posts);
}
}
### Ну и вызывать
$authors = Author::find()->all();
Author::fillPosts($authors);