テーブル名をrenameした後、php artisan migrate:refresh系のコマンドをうったときに出るエラーを迅速に解決するには
php artisan migrate:refreshをすると、
英語のサイトを大量に巡回するハメになるような、エラーが出てくる場合があります。
巡回した方法を試しまくるうちに、これをしておけば、エラーが減るという注意点をまとめました。
チェックするポイント
マイグレーションファイルのdown関数内と、外部キー制約の部分をチェックします。
特に、renameしたときや、カラムをaddしたときのマイグレーションファイルを要チェックします。
例:favorite から favorites に変更した時
例えば、最初はfavoriteだったが、favoritesにするパターンで、
renameのとき、以下のように、downに何も書いてないパターン
<?php public function up() { Schema::rename('favorite', 'favorites'); } public function down() { }
migrate:refleshなどをすると、テーブルがないですよっというエラーが出る。
そりゃそうですね…。downにロールバック時の処理が書き忘れているから、ちゃんとロールバックできずに終わってしまいます。
down()に処理を書く
downにも名前を戻す処理を書いてあげます。
<?php public function down() { Schema::rename('favorites', 'favorite'); }
外部キー制約をつけている場合
さらに、favoriteの user_id と photo_id には外部キー制約を付けている場合は、
ここに、外部キーも、付け直す処理を入れてあげます。
<?php public function up() { //old_table Schema::table('favorite', function (Blueprint $table) { $table->dropForeign(['user_id']); $table->dropForeign(['photo_id']); }); Schema::rename('favorite', 'favorites'); //new_table Schema::table('favorites', function (Blueprint $table) { $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('photo_id')->references('id')->on('photos')->onDelete('cascade'); }); } public function down() { //new_table Schema::table('favorites', function (Blueprint $table) { $table->dropForeign(['user_id']); $table->dropForeign(['photo_id']); }); Schema::rename('favorites', 'favorite'); //old_table Schema::table('favorite', function (Blueprint $table) { $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('photo_id')->references('id')->on('photos')->onDelete('cascade'); }); }
以上でおしまい。
けっこうはまってしまったため、次からはこのポイントに注意していきたいと思います。
リレーションをページネーションするには
リレーションをページネーションするには
完成形はこのような感じで、20件ごとに1ページを表示できるようにします。
リレーションからページネーション関数を呼ぶとエラー!?
<?php $photos = $user->photos->paginate(20);
上のコードでエラーが出てしまったためメモします。
解決:photosにカッコをつけるだけでOKでした
<?php $photos = $user->photos()->paginate(20);
参考サイト
factoryで流し込んだダミーデータでログイン -> 認証情報が記録と一致しません!?
factoryで流し込んだダミーデータでログインすると「認証情報が記録と一致しません」と出る場合
原因
パスワードはハッシュ関数を通してから、入れないとダメだったようです。
認証不一致のエラーが出たfactoryはこんな感じです。
<?php $factory->define(User::class, function (Faker $faker) { return [ ~省略~ 'password' => '12345678', // password ~省略~ ]; });
ハッシュ関数を通すよう修正
<?php $factory->define(User::class, function (Faker $faker) { return [ ~省略~ 'password' => Hash::make('12345678'), // password ~省略~ ]; });
無事完了!
Laravelで、いいねした写真の一覧を表示するには
写真素材:
pixabay.com
上のようないいねをした画像を取得して、表示する部分について解説します。
取りたい情報
・写真がいいねされた数
・写真のコメントの数
3つのテーブルを用意
まず、3つのテーブルを使用します。
ユーザーテーブル、写真テーブル、いいねテーブル
カラムは必要なところだけをかくと
●ユーザーテーブル
・id (これが他のテーブルと紐づくuser_id)
・他、nameなどのカラム
●写真テーブル
・id (これが他のテーブルと紐づくphoto_id)
・user_id
・他、titleなどのカラム
●いいねテーブル
・user_id (これが他のテーブルと紐づくuser_id)
・photo_id
※user_idとphoto_idは組み合わせが重複しないように複合キーにする。
マイグレーションファイル一部
<?php ... Schema::create('skill_user', function (Blueprint $table) { $table->unsignedInteger('skill_id'); $table->unsignedInteger('user_id'); $table->primary(['skill_id', 'user_id']);//複合キー ...
SQLからデータを取得
例えば、ユーザー1が、いいねをした写真一覧を取得するということなので、
内部結合で表すと
INNAR JOIN SELECT photos.id FROM photos INNER JOIN favorites ON photos.id = favorites.photo_id and favorites.user_id = $user_id;
Laravelでは
<?php $photos = DB::table('photos') ->join('favorites', 'photos.id', '=', 'favorites.photo_id') ->where('favorites.user_id', '=', $user_id) ->get(); return view('mypage')->with([ 'photos' => $photos, ... ]);
となりますが、
これだと、viewの方で、photosをforeachで回したとき、
子要素のphotoでリレーションを使う時にエラーが出ました。
まぁ…配列のデータしか取れてないことが原因なわけですが…
hasManyThroughを使おう
よってそのため、以下のように【hasManyThrough】を使って、3つのテーブルをまたぐリレーションを行います。
<?php ... class User extends Authenticatable{ //~省略~ public function join_favorites_photos() { return $this->hasManyThrough( 'App\Photo', //リレーションして取りたいテーブル「photos」 'App\Favorite', //経由するテーブル「favorites」 'user_id', //favoritesテーブルをusersテーブルと結ぶための外部キー 'id', // photosテーブルの外部キー null, // usersテーブルのローカルキー 'photo_id' //favoritesとphotosを結ぶために使うキー ); } }
リレーション先テーブル「posts」
rolesテーブルのidとmembersテーブルのroles_idを結合
membersテーブルのidとPostsテーブルのmembers_idを結合
bladeでいいねの数とコメントの数を表示する部分を作成
これをすると、2つのテーブルで行うhasManyなどのリレーションと同じように
子要素のリレーションもビューでデータを取得できます。
実際に、いいねの数と、コメントの数をビューで表示してみましょう。
<?php // いいねの数 $photo->favorites->count(); // コメントの数 $photo->comments->count();
ビューの部分
<div class="gallery flex border mb-4 p-2"> @foreach ($photos as $photo) <div class="photo border mb-4 p-2"> <a href="/photo/{{ $photo->id }}"> <div class="img_cover"> <img src="/storage/thumbnail_images/{{ $photo->image_name }}" /> </div> </a> <div class="flex space-between bottom-imginfo"> <div> <img src="/img/heart-regular.svg" width="20"> <u><b>{{ $photo->favorites->count() }}</b></u> ←ここでしっかりデータが取得できる <img src="/img/comment-dots-regular.svg" width="20"> <u><b>{{ $photo->comments->count() }}</b></u> ←ここでしっかりデータが取得できる </div> <div> <form method="POST" action="{{ action('FavoriteController@destroy_redirect', ['photo_id' => $photo->id]) }}"> @csrf @if ($page_kind === 'mypage') <button type="button" class="btn btn-primary btn-sm">編集</button> @endif <button type="submit" class="btn btn-danger btn-sm"> @if ($page_kind === 'favorite') 解除 @else 削除 @endif </button> </form> </div> </div> </div> @endforeach </div>
これで完成です。
参考サイト
qiita.com
Laravelでテーブル名をリネームするには
このupload_imagesをphotosという名前に変更しようと思って、
探していましたが、具体的な方法がようやく見つかったため、メモしておきます。
まずは、リネーム用のマイグレーションファイルを新たに作成します。
[vagrant@localhost nekopic_website]$ php artisan make:migration rename_upload_images_to_photos_table Created Migration: 2019_06_20_145539_rename_upload_images_to_photos_table
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class RenameUploadImagesToPhotosTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { //ここをリネーム処理に ←が元の名前、→がリネーム後 Schema::rename('upload_images', 'photos'); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('photos', function (Blueprint $table) { // }); } }
最後にマイグレーションを反映させる。
[vagrant@localhost nekopic_website]$ php artisan migrate Migrating: 2019_06_20_145539_rename_upload_images_to_photos_table Migrated: 2019_06_20_145539_rename_upload_images_to_photos_table
リネームが完了しました。
参考サイト:
busy.org
Laravelでの開発時に個人的にAtomやコマンドラインツールのおすすめの配置
まずはAtomの配置について
Atomを三分割して、
左にphpファイル、中央にbladeファイル、右にcssやjavascriptファイルを
配置するします。
いろんな種類のファイルがあるため、ごちゃごちゃしにくくて、なにより探しやすかったです。
例えば、さっき編集してた〇〇.phpはどこだっけな…というときは、PHPファイルは左に全部あるので、左を探すだけでいい。というような感じです。
コマンドラインツール
私はPuttyを使っているのですが、
これも3つ画面を出しておきます。
1つはMySQLにログインしておき、
2つ目はビルドインウェブサーバ(php artisan serve)用のウィンドウにします。
最後に、php artisanでモデルやマイグレーションいしたり、gitコマンドなどを使うためのウィンドウを配置します。
以上になります。
個人的にけっこうこのスタイルはプログラミングしやすいな~と思います。
Laravelでお気に入り機能を追加しよう
お気に入り機能のために、お気に入りテーブルfavoriteを作ります。
投稿した写真をお気に入りする機能には、
「お気に入りテーブル」に以下の情報が必要です。
・ユーザーテーブルのid
・投稿した写真のid
つまり、どのユーザーの、どの写真か?という情報でDBから抽出する必要があります。
ここで、もし、ユーザーが退会したときや、写真が削除された場合を考えてみましょう。
その際、「お気に入りテーブル」に、お気に入りした写真のidやユーザーidが、残り続けることになります。
これを防ぐために、外部キー制約を使って、
userや投稿写真が削除されたとき、自動的に「お気に入りテーブル」内のそれに関連したユーザーID、写真IDも全て削除しておきます。
LaravelにはonDelete('cascade');という機能があり、これで外部キー制約をつけます。
現在のテーブル構成は以下になります。
・upload_images - 投稿した写真
・users - 登録ユーザー
・favorite - お気に入りした投稿した写真のidを格納
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateFavoriteTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('favorite', function (Blueprint $table) { $table->increments('id'); $table->integer('user_id'); $table->integer('photo_id'); $table->timestamps(); // userが削除されたとき、関係しているお気に入りも全て削除 $table->foreign('user_id') ->references('id') ->on('users') ->onDelete('cascade'); // upload_imagesの写真(photo)が削除されたとき、関係しているお気に入りも全て削除 $table->foreign('photo_id') ->references('id') ->on('upload_images') ->onDelete('cascade'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('favorite'); } }