メモ > 技術 > フレームワーク: Laravel > データベース
データベース
■マイグレーションとモデルの作成
php artisan make:migration create_articles_table ... 「create_articles_table」というマイグレーションクラスを作る
php artisan make:migration create_articles_table --table=articles ... 「articles」テーブルを作成するカラのコードを追加する
php artisan make:migration create_articles_table --create=articles ... 「articles」テーブルを作成・削除するコードを追加する
php artisan make:model Article ... 「Article」というモデルを作成
php artisan make:model Person -m ... Personモデルとpeopleテーブルのマイグレーションをセットで作成。Person は people になる
Model created successfully.
Created Migration: 2016_12_05_151532_create_people_table
※コマンドラインで操作
※artisan=職人
■マイグレーションでエンジンを設定
$table->engine = 'InnoDB';
■マイグレーションで真偽値を設定
available TINYINT(1) NOT NULL COMMENT '有効',
MySQLでこのような定義を行いたい場合、以下のように指定する
$table->boolean('available')->comment('有効');
■マイグレーションでコメントを設定
[Laravel]マイグレーションでテーブルにコメントを入れる|atuweb - ヒーローになるIT人材育成研究室
https://ameblo.jp/atuweb/entry-12204289098.html
Laravel - Laravel のマイグレーションでテーブルカラムにコメントを設定する(91732)|teratail
https://teratail.com/questions/91732
■既存のテーブル定義からマイグレーションを作成
Laravelで既存のDBからmigrationsファイルを作成する「migrations-generator」 - Qiita
https://qiita.com/busyoumono99/items/a7173ad6b9b041da09dd
■基本的なリレーション
モデルで以下のようなメソッドを定義
class User extends Authenticatable
{
public function entries()
{
return $this->hasMany('App\Entry');
}
コントローラで以下のようにして取得
$users = App\User::get();
foreach ($users as $user) {
$result .= $user->id . ' | ' . $user->name . ' | ' . $user->email . '<br>';
foreach ($user->entries as $entry) {
$result .= $entry->id . ' | ' . $entry->title . '<br>';
}
$result .= '<br>';
}
Eloquent:リレーション 5.4 Laravel
https://readouble.com/laravel/5.4/ja/eloquent-relationships.html
親子関係のテーブルでのクエリーの作成(Eloquent編) - ララジャパン
https://www.larajapan.com/2016/07/09/%E8%A6%AA%E5%AD%90%E9%96%A2%E4%BF%82%E3%81%AE%E3%83%86%E3%83%BC...
■リレーション先の情報で検索
【Laravel・whereHas】リレーション先でクエリ実行 | とものブログ
https://se-tomo.com/2018/10/06/laravel%E3%81%A7%E3%81%AE%E3%83%AA%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A...
Laravelでリレーション先の条件で検索 | webOpixel
https://www.webopixel.net/php/1412.html
以下、リポジトリ内での検索例
if (isset($conditions['staff_company_number'])) {
$query->whereHas('staffCompanies', function($query) use($conditions) {
$query->where('company_number', $conditions['staff_company_number']);
});
}
■N+1問題
以下のように with を使うと、あらかじめ関連するデータを取得する
$users = App\User::get();
↓
$users = App\User::with('entries')->get();
Eloquent:リレーション 5.4 Laravel
https://readouble.com/laravel/5.4/ja/eloquent-relationships.html
「Eagerローディング」の項目を参照
width で読み込んだデータを対象に、whereで絞り込みを行うこともできる
「Eagerロードへの制約」の項目を参照
Laravel|STEP UP BLOG
http://capella.3rin.net/Category/2/
■記事とカテゴリ、記事とタグなど多対多のリレーション
「(33) 多対多のリレーション モデル/DB編」の解説によると、
・「記事が複数のタグを持てる」のようなリレーションを行う場合は中間テーブルを使う
・中間テーブルは、テーブル名を関連するモデル名をアルファベット順で並べた名前にする(デフォルトの規約)
・中間テーブルのタイムスタンプを更新したい場合、withTimestamps() を指定する
・中間テーブルにオートインクリメントな主キーは、あっても無くてもいい
みたい
Eloquent:リレーション 5.4 Laravel
https://readouble.com/laravel/5.4/ja/eloquent-relationships.html#many-to-many
初めてのLaravel 5.1 : (33) 多対多のリレーション モデル/DB編 - ララ帳
https://laravel10.wordpress.com/2015/03/30/%E5%88%9D%E3%82%81%E3%81%A6%E3%81%AElaravel-5-33-%E5%A4%9...
初めてのLaravel 5.1 : (34) 多対多のリレーション UI編 - ララ帳
https://laravel10.wordpress.com/2015/03/31/%e5%88%9d%e3%82%81%e3%81%a6%e3%81%aelaravel-5-34-%e5%a4%9...
Laravel5.4で基本的なリレーションを学んでみる | webOpixel
http://www.webopixel.net/php/1261.html
Laravel5.2で多対多(BelongsToMany)のリレーション | will STYLE Inc.|神戸にあるウェブ制作会社
https://www.willstyle.co.jp/blog/353/
■外部キー制約
要検証
以下のようにすれば、entriesテーブルやtagsテーブルのデータが削除された時、自動でentry_tagのデータも削除される
が、代理キーで管理するなら原則として削除されないことになる
「想定外のidが入らないように」という点では有効だが、外部キー制約を使うか否かは要検討
また、外部キー制約を付けるとしても、マイグレーションでは行わずにシーダーで行うほうがいい?
Schema::create('entry_tag', function(Blueprint $table)
{
$table->integer('entry_id')->unsigned()->index();
$table->integer('tag_id')->unsigned()->index();
$table->foreign('entry_id')->references('id')->on('entries')->onDelete('cascade');
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
});
■子モデル更新時に親モデルのタイムスタンプを更新
未検証
子モデル側の $touches プロパティにリレーション先を設定する
protected $touches = ['post'];
Eloquent:リレーション 5.4 Laravel
https://readouble.com/laravel/5.4/ja/eloquent-relationships.html
■主キーをUUIDにする
LaravelでUUIDを使う際の設定 - Qiita
https://qiita.com/NewBieChan/items/3d0f8025accd770bd6d3
UUID - Qiita
https://qiita.com/hththt/items/801bf4664332a0346650
UUIDはなぜ、分散環境で好き勝手に生成しても衝突しないのか。RFC4122規格とUUIDの性質。 | 三度の飯とエレクトロン
http://blog.katty.in/5124
■主キーを複合主キーにする
代理キーで管理するのが前提となっているみたい。
複合主キーに対応できないわけではないみたいだが、代理キーを使っておくのが無難
他の主要フレームワークも代理キー前提が基本なので、
「複合主キーを使いたいからLaravelは採用しない」とはならなさそう
複合主キーにしてリレーションに問題が起きないかは要検証
[Laravel]Eloquent ORMで複合主キーはオススメしない
http://atuweb.net/201610_laravel-eloquent-orm-id-agreement/
PHP - Laravelで複合主キーを使ったモデルを更新できない(36627)|teratail
https://teratail.com/questions/36627
Laravel5で複合キーを扱う - KaokenとLaravel
https://laravel.cg0.xyz/handle-compound-keys-with-laravel-5/
LaravelのEloquentを使って複合主キーを使用したテーブルを操作する方法 - Qiita
http://qiita.com/wrbss/items/7245103a5fef88cbdde9
Eloquentで多対多のリレーション - Laravel Room
https://laravel-room.com/many-to-many-relationshop
■ユニークな複合キー
$table->unique(['first', 'last']);
データベース:マイグレーション 5.4 Laravel
https://readouble.com/laravel/5.4/ja/migrations.html
■データを検索して一覧表示
検索機能の作成 - Laravel学習帳
http://laraweb.net/tutorial/607/
■操作したユーザの自動記録
Laravelのeloquentのeventでcreated_byとかupdated_byとか更新するobserverとtrait - Qiita
https://qiita.com/maimai-swap/items/6597c04721adbc48fec2
Soft delete: "deleting" event does not automatically update the model before it is soft deleted - Issue #4990 - laravel/framework
https://github.com/laravel/framework/issues/4990
Eloquent: Getting Started - Laravel - The PHP Framework For Web Artisans
https://laravel.com/docs/5.3/eloquent#events
Eloquent:利用の開始 5.4 Laravel
https://readouble.com/laravel/5.4/ja/eloquent.html#events
各テーブルで
created_by_user_id, updated_by_user_id, deleted_by_user_id
これらの値を更新する必要があるが、都度コントローラから指定すると更新し忘れが発生する
自動で更新する仕組みを導入するといい
各モデルで必要に応じて以下のtraitを宣言すれば、自動で更新されるようにしている
use RegisterAuthor;
■トランザクション
以下のように記述すると、ロールバックやコミットを自動で制御してくれる
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
});
もしくは以下を個別に呼び出す
DB::beginTransaction();
DB::rollBack();
DB::commit();
データベース:利用開始 5.4 Laravel
https://readouble.com/laravel/5.4/ja/database.html
Laravel5.3でselect for update する方法 - Qiita
https://qiita.com/taichi_akippa/items/465e986462be05a3ae42
Laravelで行ロックとテーブルロックする方法【lockForUpdate】 | みんたく
https://mintaku-blog.net/laravel-lockforupdate/
■生SQLの指定
Laravel5のアーキテクチャから学ぶより良いクラス設計 - Qiita
http://qiita.com/nunulk/items/2c637d3952096ef74677
$users = DB::table('users')
->join('contracts', 'contracts.user_id', '=', 'users.id')
->select('users.id', DB::raw('count(*) as contract_count'))
->orderBy('users.id')
->groupBy('users.id')
->having(DB::raw('count(*)'), '>', $count)
->get()
;
↓
$sql =<<<EOQ;
SELECT u.id, count(*) as contract_count
FROM users
INNER JOIN contracts c
ON c.user_id = u.id
GROUP BY u.id
HAVING count(*) > ?
ORDER BY u.id
EOQ;
$users = DB::select($sql, [$count]);
■ソフトデリート
マイグレーションを作成
php artisan make:migration alter_articles_table
マイグレーションを修正
public function up()
{
Schema::table('articles', function (Blueprint $table) {
$table->softDeletes();
//$table->timestamp('deleted_at')->nullable()->after('updated_at');
});
}
public function down()
{
Schema::table('articles', function (Blueprint $table) {
$table->dropColumn('deleted_at');
});
}
マイグレーションを実行
php artisan migrate
モデルを修正
C:\localhost\home\test\public_html\laravel\test\app\Article.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Article extends Model
{
use SoftDeletes;
/**
* 日付へキャストする属性
*
* @var array
*/
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
}
データベース:マイグレーション 5.4 Laravel
https://readouble.com/laravel/5.4/ja/migrations.html
Eloquent:利用の開始 5.4 Laravel
https://readouble.com/laravel/5.4/ja/eloquent.html
削除処理の流れ
データ削除時、通常は
\test\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php
内の delete() が呼ばれる
その中で performDeleteOnModel() が呼ばれており、これにより削除処理が走る
SoftDeletesトレイトでこのメソッドを上書きしているので、これにより削除時の挙動が変わる
取得処理の流れ
Laravelの機能で、モデルは「boot + トレイト名」を最初に実行する
よって bootSoftDeletes() が最初に実行される
このメソッド内でスコープを渡し、データ取得時はそれによって構築されるクエリが変化する
http://qiita.com/niisan-tokyo/items/d3be588b53df8fa0278c
■複数代入
\test\app\Article.php
/**
* 複数代入する属性
*
* @var array
*/
protected $fillable = ['subject', 'detail'];
\test\app\Http\Controllers\ArticleController.php
// 通常の代入
$article = new Article;
$article->subject = $request->subject;
$article->detail = $request->detail;
$article->save();
// 複数代入
$article = new Article;
$article->fill($request->all())->save();
// このようにも書ける
Article::create($request->all());
複数代入を使用する場合、意図しない代入を防ぐためあらかじめモデルで
$fillable で代入を許可する項目を指定するか
$guarded で代入を許可しない項目を指定するか
を定義しておく必要がある。原則として $fillable での指定で良さそう
// 編集ならこのように書けば良さそう
Article::find(15)->update($request->all());
// 削除ならこのように書けば良さそう
Article::find(15)->delete();
Article::findOrFail(15)->delete();
【Laravel:Eloquentクラス】fillableとguardedの指定はどちらかだけでいい - Qiita
http://qiita.com/kk_take/items/3e0639ed605f74c34619
Article::findOrFail(15)
の書き方については、以下の「Not Found例外」を参照
Eloquent:利用の開始 5.4 Laravel
https://readouble.com/laravel/5.4/ja/eloquent.html
■モデルの型キャスト
【Laravel】DBから取得した値を$castsで型変換する【Attribute Casting】 - Qiita
http://qiita.com/amymd/items/7cba844b03754f9c849b