Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос нашим менторам. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Связи

Сущности предметной области существуют не сами по себе. Они часто зависят друг от друга. На уровне базы данных такие связи задаются через внешние ключи или даже промежуточные таблицы, как в случае связи "многие ко многим". ORM, в свою очередь, используют эти ключи, для работы со связями. Добавляет множество полезных методов, которые упрощают работу с зависимыми сущностями: выборкой, добавлением, модификацией и удалением.

Так как в этом курсе мы делаем блог, нам понадобится сущность Post. Пользователи связаны с постами "один ко многим":

  • Один пользователь может быть автором многих постов
  • У одного поста всегда один автор

Структура

Для поддержки такой связи при создании таблицы постов, нужно добавить внешний ключ на таблицу пользователей:

<?php

Capsule::schema()->create('posts', function ($table) {
    $table->id();
    $table->string('state')->nullable();
    $table->string('title');
    $table->text('body');
    // Поле которое будет внешним ключом
    $table->bigInteger('creator_id');
    // Добавление внешнего ключа (ограничения)
    $table->foreign('creator_id')->references('id')->on('users');
    $table->timestamps();
});

По умолчанию Eloquent не воспринимает внешние ключи как что-то особенное. Она требует (как и большинство ORM) явного указания связи на уровне моделей. Для этого в каждой из моделей определяется специальный метод, через который будет происходить всё взаимодействие между связанными сущностями. Имя этого метода произвольно и выбирается так, чтобы лучше отражать суть связи: У поста есть автор, у каждого автора есть посты. Каждый такой метод должен вернуть вызов другого метода, отвечающего за связь. В примере ниже это belongsTo и hasMany.

<?php

// Post.php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function creator()
    {
        // Принадлежит пользователю
        // belongsTo определяется у модели содержащей внешний ключ
        return $this->belongsTo('App\User');
    }
}

Вторым параметром метод belongsTo ожидает имя внешнего ключа, по которой строится связь: $this->belongsTo('App\User', 'creator_id'). Имя ключа можно (и желательно) не указывать. В таком случае, Eloquent определяет его самостоятельно, используя имя метода связи и добавляя к нему суффикс _id.

<?php

// User.php
namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    // Во множественном числе потому что это коллекция
    public function posts()
    {
        // У каждого пользователя много постов
        // hasMany определяется у модели, имеющей внешние ключи в других таблицах
        return $this->hasMany('App\Post', 'creator_id');
    }
}

Метод hasMany также поддерживает соглашение для определения имени внешнего ключа. Только здесь оно определяется не по имени метода, а по имени модели, в которой описывается связь. Для модели User это будет user_id. В нашем случае такая логика не работает, поэтому имя свойства указано явно.

CRUD

Теперь Eloquent знает о связях и даёт работать с ними напрямую:

<?php

$user = App\User::find(1);
// SELECT * FROM posts WHERE creator_id = 1
foreach($user->posts as $post) {
    echo $post;
}

Обращение к коллекции зависимых сущностей возвращает специальный объект, который может использоваться как массив.

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

<?php

// В пост автоматически устанавливается пользователь
$post = $user->posts()->make(); // Параметры поста можно передать в make
$post->title = 'title';
$post->body = 'body';
$post->save();

$user->posts; // [['id' => 1, 'title' => 'title', 'body' => 'body', 'creator_id' => 1, ...]]

// В WHERE добавится user_id = <идентификатор пользователя>
$post2 = $user->posts()->find(1);

$post->is($post2); // true

// Удаление всех постов одним запросом
$user->posts()->delete();

То же самое происходит и с другой стороны связи:

<?php

$post = App\Post::find(1);
$post->creator->first_name;

// Установка пользователя
$post->creator()->associate($user);
$post->save();

При работе со связями важно переключиться от мышления через таблицы и ключи к сущностям и связям (почему). Технически это значит, что код опирается на сами сущности, а не их идентификаторы:

<?php

// Плохо
$post->user_id = $user->id;

// Хорошо
$post->user->associate($user);

Выборки

Все типы связей в Eloquent поддерживают построение запросов на выборку:

<?php

// В запрос будет включено условие по user_id равным текущему пользователю
// SELECT * FROM posts WHERE user_id = 1 AND state = 'active'
$user->posts()->where('state', 'active')->get();

Самостоятельная работа

  1. Заполните $fillable у Post.
  2. Изучите связи внутри Post.
  3. Откройте REPL и создайте несколько постов.

Дополнительные материалы

  1. Один ко Многим

<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят менторы из команды Хекслета или другие студенты.

Для полного доступа к курсу, нужна профессиональная подписка

Профессиональная подписка откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, даст возможность обращаться за помощью к менторам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

Зарегистрироваться

или войти в аккаунт

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг».

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг».