LaravelEloquentで1対多の関係を構築する方法
このシリーズの前提条件として設定したデモLandingLaravel アプリケーションには、リンクを格納するための単一のデータベーステーブルが含まれています。 このチュートリアルでは、この初期データベース構造を変更して、リンクをリストに編成するために使用する2番目のテーブルを含めます。
このシリーズで使用するリンクとリストの例では、各リンクは1つのリストの一部ですが、各リストには複数のリンクを含めることができます。 この種の関係は、1対多関係とも呼ばれます。
1対多の関係は、タイプ A と呼ばれる1つのアイテムを、タイプ B の複数のアイテムにリンクできる場合に発生しますが、その逆は当てはまりません。 :タイプ B のアイテムは、タイプAのoneアイテムにのみリンクできます。 このシナリオを現在のデモアプリケーションモデルに置き換えると、 Aはlist
タイプであり、Bはlink
タイプです。
LinkList
モデルの作成
開始するには、リンクのリストを表すモデルとデータベーステーブルを作成する必要があります。 次に、既存の Link モデルとテーブルを更新して、両方のモデル間の関係を含めます。 List
という用語はPHP内部用に予約されているため、その用語で新しいモデルに名前を付けることはできません。 代わりに、この新しいモデルをLinkList
と呼ぶことができます。
まず、アプリケーションディレクトリにいることを確認します。
cd ~/landing-laravel
artisan
を使用して新しいモデルを作成します。
docker-compose exec app php artisan make:model LinkList
これにより、app/Model
ディレクトリに新しいモデルクラスが生成されます。
app/Model/LinkList.php
既存のLinkListCLIコマンドの名前を変更する
app/Console/Commands
ディレクトリを見ると、LinkList.php
という名前のクラスファイルがすでに存在することがわかります。 これは、作成したばかりのEloquentモデルと混同しないでください。 このクラスには、artisan
を介してデータベース内のすべてのリンクを一覧表示するCLIコマンドが含まれています。
将来の混乱を避けるために、今がそのクラスとそのコマンドシグネチャの名前を別の名前に変更する良い機会です。 この場合、クラス名LinkShow
を使用します。これは、その名前がクラスの機能も説明しているためです。 app/Console/Commands/LinkList.php
ファイルの名前を別の有効な名前に変更するには、端末で次のコマンドを実行します。
mv app/Console/Commands/LinkList.php app/Console/Commands/LinkShow.php
次に、コードエディタでファイルapp/Console/Commands/LinkShow.php
を開き、クラス名をLinkList
からLinkShow
に変更し、コマンドシグネチャをlink:list
からlink:show
、次のコードリストで強調表示されている行のように。 終了すると、ファイルは次のようになります。
app / Console / Commands / LinkShow.php
<?php namespace App\Console\Commands; use App\Models\Link; use Illuminate\Console\Command; class LinkShow extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'link:show'; /** * The console command description. * * @var string */ protected $description = 'List links saved in the database'; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return int */ public function handle() { $headers = [ 'id', 'url', 'description' ]; $links = Link::all(['id', 'url', 'description'])->toArray(); $this->table($headers, $links); return 0; } }
完了したら、ファイルを保存して閉じます。 すべてが期待どおりに機能したことを確認するには、新しく名前を変更したlink:show
職人コマンドを実行します。
docker-compose exec app php artisan link:show
次のような出力が表示されます。
Output+----+-------------------------------------------------+----------------------------------+ | id | url | description | +----+-------------------------------------------------+----------------------------------+ | 1 | https://digitalocean.com/community | DigitalOcean Community | | 2 | https://digitalocean.com/community/tags/laravel | Laravel Tutorias at DigitalOcean | | 3 | https://digitalocean.com/community/tags/php | PHP Tutorials at DigitalOcean | +----+-------------------------------------------------+----------------------------------+
LinkListモデルの移行の作成
以前のartisan make:model
コマンドで生成した新しいapp/Model/LinkList.php
クラスには、新しいEloquentクラスの汎用コードが含まれています。 Doctrineなどの他のORMとは異なり、Eloquentはデータベース構造を変更せず、データ自体のみを処理します。 Eloquentモデルは通常リーンであり、クラスプロパティはモデルのテーブル構造から自動的に推測されます。
Eloquentでデータのみを処理するこのアプローチは、LinkList
クラスのプロパティを設定する必要がないことを意味します。これは、そのモデルのデータベーステーブル構造から推測されるためです。
構造データベースの操作は通常、データベース移行を介してLaravelで処理されます。 移行により、開発者は、テーブルの作成、変更、削除など、データベースの構造上の変更をプログラムで定義できます。
次に、新しい移行を作成して、データベースにlistsテーブルを設定します。
Laravelにデフォルトで含まれているartisan
コマンドラインツールには、コントローラー、モデル、移行などの新しいコンポーネントをブートストラップするためのいくつかのヘルパーメソッドが含まれています。 artisan
を使用して新しい移行を作成するには、次のコマンドを実行します。
docker-compose exec app php artisan make:migration create_link_lists_table
Output Created Migration: 2021_07_07_152554_create_link_lists_table
このコマンドは、Laravelアプリケーションのdatabase/migrations
ディレクトリの下に、現在の日時に基づいて自動生成された名前と移行名を使用して、新しいファイルを生成します。 このファイルには、listsテーブルを設定するために変更する汎用コードが含まれています。
コードエディタを使用して、生成された移行ファイルを開きます。 現在、ファイルは次のようになっています。
database / migrations / 2021_07_07_152554_create_link_lists_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateLinkListsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('link_lists', function (Blueprint $table) { $table->id(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('link_lists'); } }
移行は、artisan migrate
コマンドで実行されると、up()
メソッドを実行します。 これがテーブル定義の目的であり、デフォルトでは、id
主キーフィールドと、 [で定義された2つのタイムスタンプフィールド(created_at
とupdated_at
)が作成されます。 X172X]スキーマメソッド。 これらのフィールドは、モデルが作成および更新されるときに、それぞれEloquentによって自動的に入力されます。 down()
メソッドは、移行がartisan rollback
コマンドでロールバックされるときに呼び出され、通常、コードを実行してテーブルを削除するか、構造上の変更を元に戻します。
up
メソッドを変更して、次のフィールドを含めます。
title
:このリストのタイトルを表す文字列description
:リストの説明を表す文字列slug
:タイトルに基づく一意の短い文字列で、通常はユーザーフレンドリーなURLを作成するために使用されます
1対多の関係では、 many 側(このシナリオではlinks テーブルに対応)は、列参照(または外部キー)を保持する側です。その他の要素(リストテーブルに対応)。 つまり、リンクテーブルをリストテーブルにリンクする参照フィールドを含めるには、後でリンクテーブルを変更する必要があります。
一方、 lists テーブルには、リンクを参照するための特別なフィールドは必要ありません。
移行ファイルの現在のコンテンツを次のコードに置き換えます。
database / migrations / 2021_07_07_152554_create_link_lists_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateLinkListsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('link_lists', function (Blueprint $table) { $table->id(); $table->timestamps(); $table->string('title', 60); $table->string('slug', 60)->unique(); $table->text('description')->nullable(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('link_lists'); } }
完了したらファイルを保存します。
リンク移行の更新
次に、コードエディタで既存のリンク移行ファイルを開きます。 デモプロジェクトでは、次のパスで移行を見つけることができます。
2020_11_18_165241_create_links_table.php
まず、ファイルの先頭と最後のuse
行の直後に、LinkList
クラスの完全修飾クラス名を指すuse
ディレクティブを含めます。
… use Illuminate\Support\Facades\Schema; use App\Models\LinkList; ...
次に、up
メソッド内で、description
フィールドを設定する行の直後に、テーブル定義に次の行を含めます。
$table->text('description'); $table->foreignIdFor(LinkList::class);
foreignIdFor()
メソッドは、参照されるEloquentモデルへの外部キー列を作成します。 デフォルトの命名法を使用して、参照されるテーブルの主キーフィールドにリンクされているフィールドを設定します。
完了したら、完全な移行クラスは次のようになります。
database / migrations / 2020_11_18_165241_create_links_table.php
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use App\Models\LinkList; class CreateLinksTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('links', function (Blueprint $table) { $table->id(); $table->string('url', 200); $table->text('description'); $table->foreignIdFor(LinkList::class); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('links'); } }
編集が終了したら、ファイルを保存します。 次に、データベースをワイプしてから、移行コマンドを再度実行して、更新された移行ファイルを使用してデータベース構造を再作成します。
docker-compose exec app php artisan db:wipe docker-compose exec app php artisan migrate
Eloquentモデル関係の構成
これでデータベーステーブルが設定されましたが、それらの間の関係を定義するためにEloquentモデルを構成する必要があります。
関係のone側であるList
モデルで、links
という名前の新しいメソッドを設定します。 このメソッドは、親Illuminate\Database\Eloquent\Model
クラスのhasMany
メソッドを使用して、各リストに関連するリンクにアクセスするためのプロキシとして機能します。
コードエディタで、ファイルapp/Model/LinkList.php
を開きます。 現在の汎用コードを次のコンテンツに置き換えます。
app / Model / LinkList.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class LinkList extends Model { use HasFactory; public function links() { return $this->hasMany(Link::class); } }
完了したらファイルを保存します。
次に、関係の many 側を編集して、List
モデルへの参照を含め、リンクがそれぞれのリストにアクセスできるようにします。 これは、親Model
クラスのbelongsTo
メソッドを使用して行われます。 この方法は、1対多の関係の逆辺を定義するために使用されます。
コードエディタでLink
モデルを開きます。
app/Model/Link.php
Link.php
ファイルの現在のコンテンツを次のコードに置き換えます。
app / Model / Link.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Link extends Model { public function link_list() { return $this->belongsTo(LinkList::class); } }
完了したらファイルを保存します。
両方のモデルが更新されると、データベースは完全に構成されますが、現在は空です。 このシリーズの次のセクションでは、Eloquentモデルを使用してデータベースに新しいレコードを挿入する方法を学習します。