Yii2 populateRecord(). Создание Active Record объекта из обычного sql запроса.
  • 35

Yii2 populateRecord(). Создание Active Record объекта из обычного sql запроса.

Автор: admin | 30 октября (Ср.) 2019г. в 21ч.38м.

Где используется populateRecord() .

В Yii2 имеется метод BaseActiveRecord::populateRecord($record, $row) , который наполняет объект ActiveRecord, используя массив данных. Ключ в данном случае, это название поля, а значение - соответственно значение поля. Данный метод позволяет создавать AR объект из результата sql запроса, который возвращается как результат выборки. Во фреймворке данный метод используется, например в ActiveQuery для преобразования результатов  в методах one() и all() в объект ActiveRecord

Как создать объект ActiveRecord из результата sql запроса.

Зачем вообще может понадобиться создавать AR объект из массива, который мы получили в результате запроса. Предположим, в файлах видов весь контент выводится с помощью AR объектов, например описание материала выводим как $article->descriptions , пост статьи -  $article->content и т.п.
Но по какой-то причине нам нужно сделать выборку с помощью обычного sql запроса. В результате нам нужно массив данных использовать для наполнения AR объекта, и этот объект уже использовать где требуется, а также иметь доступ через него к связям.

Приведу пример, как можно получить массив - результата sql запроса и наполнить данными объект AR модели. Для запроса воспользуюсь 
yii\db\Connection и yii\db\Command :

//Получаем первую строку результата
$row = Yii::$app->db->createCommand(
    'SELECT * FROM `blogArticles`)->queryOne();​

//Создаем объект active record. В данном случае BlogArticles - модель.
$recordArt = BlogArticles::instantiate($row);

//Заполняем объект данными
BlogArticles::populateRecord($recordArt, $row);

//где необходимо выводим данные из объекта
$recordArt->title

//Или связанные данные, если связь объявлена в модели
$recordArt->category->title;
Также имеем доступ к связанным моделям, как обычно, если в классе связи были объявлены.

Рассмотрим более сложный запрос на выборку из двух таблиц. В данном примере я сделаю выборку из таблицы 'articles' для получения статьи и также по внешнему ключу выберем категорию из таблицы 'categories', к которой относится данная статья. Далее создадим два объекта active record - для статьи и категории:
$row = Yii::$app->db->createCommand(
    'SELECT ba.*, 
    bc.id AS category_id, 
    bc.alias AS category_alias,  
    bc.title AS category_title, 
    bc.metaTitle AS category_metaTitle,
    bc.metaDesc AS category_metaDesc,
    bc.sort_order AS category_sort_order,
    bc.metaKeywords AS category_metaKeywords 
    FROM `blogArticles` AS ba 
    LEFT JOIN `blogCategories` AS 
    bc ON ba.idCategory = bc.id'
    )->queryOne();

//Подготавливаем данные для заполнения объекта категории
$rowCat = array(
    'id' => $row['category_id'],
    'title' => $row['category_title'],
    'alias' => $row['category_alias'],
    'metaTitle' => $row['category_metaTitle'],
    'metaDesc' => $row['category_metaDesc'],
    'sort_order' => $row['category_sort_order'],
    'metaKeywords' => $row['category_metaKeywords'],
);

$recordArt = Articles::instantiate($row);
$recordCat = Categories::instantiate($rowCat);

Articles::populateRecord($recordArt, $row);
Categories::populateRecord($recordCat, $rowCat);

//Работаем с данными как обычно
echo $recordArt-title;
echo $recordCat->title;
​
 Таким образом создаем два объекта из результата одного запроса. Созданные и заполненные объекты с помощью ActiveRecord::populateRecord($record, $row); являются такими же, как если бы мы создавали их  с помощью find() .Если в классе объявлены связи, то можем ими пользоваться.
Также можно как обычно использовать save()

Добавление связи с помощью populateRelation($name, $record)

Можем добавить к AR объекту связь и ее результат. Нужно указать в populateRelation() имя связи и данные, которые по данному имени будут храниться:
 
$recordArt = Articles::instantiate($row);
$recordCat = Categories::instantiate($rowCat);

Articles::populateRecord($recordArt, $row);
Categories::populateRecord($recordCat, $rowCat);

$recordArt->populateRelation('category', $recordCat);

//Работаем с данными как обычно
echo $recordArt->categoty->title;​
нужно учесть, что если в классе Articles есть связь с таким же именем 'category' , то в данном случае связь будет перезаписана в методе $recordArt->populateRelation('category', $recordCat) . Но и дополнительного запроса к базе данных не понадобится, как если бы связь подтягивалась из геттера, делая еще один запрос к базе.

Метод populateRelation добавляет именованную связь в массив связей к уже имеющимся. Ключи с одинаковыми именами перезаписываются. Вот, как метод реализован в yii2 BaseActiveRecord:

    public function populateRelation($name, $records)
    {
        foreach ($this->_relationsDependencies as &$relationNames) {
            unset($relationNames[$name]);
        }

        $this->_related[$name] = $records;
    }​


В данной статье мы рассмотрели методы для создания active record объекта, используя данные из базы данных в виде массива или из другого хранилища. 

Читайте также из этой серии:

Приветствую!

Меня зовут Сергей. Я - автор этого блога.

Если Вам был полезен материал на моем сайте, поддержите пожалуйста мой проект, чтобы о нем узнали другие люди - кликните plizz :) на иконку в соц. сети, чтобы поделиться материалом с другими.