Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Связи между моделями

Таблицы связаны между собой: у статьи есть автор, у статьи много комментариев. Связь в Yii — метод модели, который объясняет, как найти связанные строки. После этого к ним обращаются как к обычному свойству.

Подготовка

Нужна вторая таблица. Создайте миграцию php yii migrate/create create_comment_table со столбцами id, post_id (целое число) и text (текст), выполните её и создайте модель:

// models/Comment.php
namespace app\models;
 
use yii\db\ActiveRecord;
 
class Comment extends ActiveRecord
{
}

Метод tableName() здесь не нужен: имя таблицы comment совпадает с именем класса.

Один ко многим: hasMany

Связь описывают в классе модели методом, имя которого начинается с get. Добавьте в models/Post.php:

// models/Post.php
public function getComments()
{
    return $this->hasMany(Comment::class, ['post_id' => 'id']);
}

В массиве слева — столбец связанной таблицы (comment.post_id), справа — столбец текущей (post.id). К связи обращаются как к свойству, без get и без скобок:

$post = Post::findOne(1);
 
foreach ($post->comments as $comment) {
    echo $comment->text;
}

Код выведет тексты всех комментариев первой статьи. Запрос к таблице comment выполняется при первом обращении к свойству.

Обратная связь: hasOne

У комментария одна статья. Добавьте в models/Comment.php:

// models/Comment.php
public function getPost()
{
    return $this->hasOne(Post::class, ['id' => 'post_id']);
}

Теперь $comment->post->title вернёт заголовок статьи. Точно так же в Post описывают автора: hasOne(User::class, ['id' => 'user_id']).

Загрузка заранее

Список из ста статей, где для каждой выводится число комментариев, выполнит сто один запрос: один за статьями и по одному на каждую. Метод with() загружает связь одним дополнительным запросом:

// controllers/PostController.php
$posts = Post::find()->with('comments')->all();

Запросов станет два при любом числе статей. Несколько связей перечисляют массивом: with(['comments', 'author']).

Условие по связанной таблице

$posts = Post::find()
    ->joinWith('comments')
    ->where(['like', 'comment.text', 'спасибо'])
    ->all();

joinWith() соединяет таблицы в одном запросе, поэтому в условии можно использовать столбцы комментариев. Результат — статьи, где есть комментарий со словом «спасибо».

Сохранение связанной записи

$comment = new Comment();
$comment->text = 'Отличная статья';
$comment->link('post', $post);

Метод link() записывает в post_id номер статьи и сохраняет комментарий. Первый аргумент — имя связи.

Частая ошибка

$post->comments и $post->getComments() — не одно и то же. Свойство возвращает готовый массив объектов, а метод — запрос, который можно уточнить: $post->getComments()->orderBy(['id' => SORT_DESC])->limit(5)->all(). Попытка перебрать в цикле результат метода без all() не даст комментариев.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.