Отношение «Один-к-Одному» в Laravel Eloquent

Отношение Один-к-Одному

Одним из основных элементов фреймворка Laravel является Eloquent ORM — система объектно-реляционного отображения. Laravel Eloquent предоставляет очень удобный способ создания отношений между моделями.

В этой статье мы рассмотрим, как мы можем создать отношение «Один-к-Одному» (One To One) в Laravel.

Что такое отношение «Один-к-Одному»?

Это отношение связывает одну запись в таблице с одной записью в другой таблице базы данных. «Один-к-Одному» является фундаментальным и очень простым в использовании.

Например, у нас есть модель User, используемая для аутентификации. И мы хотим добавить раздел управления профилем для хранения социальных ссылок на аккаунты пользователя, даты рождения и тому подобных данных. Мы можем добавить столбцы, связанные с профилем, прямо в таблицу пользователя, но это её усложнит.

Чтобы поддерживать нашу базу данных в чистоте и порядке, данные, относящиеся к аутентификации пользователей, такие как адрес электронной почты, имя пользователя и пароль мы храним в таблице пользователей. А данные, относящиеся к профилям, такие как социальные ссылки, дата рождения — в таблице профилей.

У одного пользователя может быть только один профиль, а профиль принадлежит только одному пользователю, поэтому здесь мы создаем отношения «Один-к-одному». Эта взаимосвязь изображена на диаграмме ниже.
отношение один к одному

 

Создание модели и миграции

Для реализации отношения «Один-к-одному» в Laravel, нам понадобятся две модели: User и Profile.

Примечание: я надеюсь вы уже установили Laravel и настроили базу данных в файле .env.

Как мы знаем, Laravel уже поставляется с моделью User, поэтому нам нужно создать модель Profile, которая будет сопоставлена с таблицей profiles в базе данных.

Чтобы создать модель Profile, используйте команду artisan:

php artisan make:model Profile -m

Эта команда создаст новую модель App\Profile с файлом миграции:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    //
}

и миграционный файл:

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProfilesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('profiles', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('profiles');
    }
}

Сначала мы обновим метод up в файле миграции:

public function up()
    {
        Schema::create('profiles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('user_id')->nullable();
            $table->foreign('user_id')->references('id')->on('users');
            $table->date('dob');
            $table->text('bio');
            $table->string('facebook');
            $table->string('twitter');
            $table->string('github');
            $table->timestamps();
        });
    }

Теперь обновим модель Profile:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    protected $table = 'profiles';

    protected $fillable = ['dob', 'bio', 'facebook', 'twitter', 'github'];
}

Выполните следующую команду, для создания таблиц:

php artisan migrate

 

Определение отношения «Один-к-Одному»

Как только вы создали таблицы, пришло время определить отношение «Один-к-Одному». Откройте файл User.php расположенный в папке app и добавьте новый публичный метод с именем profile в модель User.

public function profile()
{
    return $this->hasOne(Profile::class);
}

Обычно дается такое же имя, как и у привязываемой модели, в данном случае — profile. Эта функция возвращает отношение hasOne.

 

Определение обратного отношения «Один-к-Одному»

Мы также можем добавить обратное отношение один к одному, добавив метод user в модель Profile

namespace App;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    protected $table = 'profiles';

    protected $fillable = ['dob', 'bio', 'facebook', 'twitter', 'github'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Мы добавили метод user, который возвращает отношение belongsTo, поскольку профиль принадлежит пользователю.

 

Получение данных «Один-к-Одному»

После того, как определили данные отношения, вы можете получить доступ к профилю пользователя, вызвав метод profile для объекта пользователя, как показано ниже

$user = User::find(1);
$userDob = $user->profile->dob;
$userBio = $user->profile->bio;

Чтобы получить профиль пользователя, Laravel будет искать внешний ключ в таблице profile под названием user_id, соответствующий идентификатору пользователя.

 

Создание отношений «Один-к-Одному»

Чтобы создать отношение «Один-к-Одному», мы сначала должны создать дочерний объект, являющийся объектом Profile

$profile = new Profile();
$profile->dob = '20-03-1999';
$profile->bio = 'A professional programmer.';

Теперь мы сохраним дочерний объект через родительский

$profile = new Profile();
$profile->dob = '20-03-1999';
$profile->bio = 'A professional programmer.';

$user = User::find(1);
$user->profile()->save($profile);

 

Удаление отношений «Один-к-Одному»

Удаление — это то же самое, что и создание. Сначала мы берем родительский объект $user, а затем вызываем метод delete для метода profile()

$user = User::find(1);
$user->profile()->delete();

А если мы удалим $user перед удалением профиля, то в базе останется потерянный профиль.

Один из подходов — сначала удалить профиль, а затем вызвать метод delete для объекта $user. Иногда вы можете пренебречь этой двухшаговой процедурой и оставить осиротевший профиль в базе данных.

Laravel предоставляет элегантный способ удаления дочерних записей при удалении родительской записи. Вы можете использовать метод onDelete() в своей миграции при определении ключа foriegn

public function up()
{
    Schema::create('profiles', function (Blueprint $table) {
        $table->id();
        $table->unsignedBigInteger('user_id')->nullable();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->date('dob');
        $table->text('bio');
        $table->string('facebook');
        $table->string('twitter');
        $table->string('github');
        $table->timestamps();
    });
}

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

 

Автор: Larashout
Перевод: Алексей Широков

Наш Телеграм-канал — следите за новостями о Laravel.