概要
Eloquent
Eloquentを使用したデータベースの操作です。
全てをまとめて一つの記事として投稿したかったのですが長くなったため分割しました。
Eloquentの基本的な部分とリレーションについては以下の記事をご参考ください。
【laravel】Eloquentの基本
【laravel】データベースのリレーション:Eloquent ORM編(作成後にリンクします)
コントローラーによるデータベースの操作
モデルクラスではクラス名::メソッド()
のように記述してクリエビルダでデータベースを操作します。
ここではモデルクラス、コントローラー、bladeテンプレートの3つで操作するため、以下のように3つのファイルの中身をタイトルで区別して記述していきます。
また、【laravel】マイグレーションで作成したsampleテーブルの内容を例に作成します。
// モデルクラス
// コントローラー
// bladeテンプレート
全てのレコードを取得
all
で値を取得します。
SELECT* FROM sample
のSQL文と同じ内容です。
public function select(Request $request)
{
$items = sample::all();
return view('sample.index', ['items' => $items]);
}
// 記述方法:クラス名::all();
@foreach ($items as $item)
{{ $items->name }}
{{ $items->tel }}
// 中略...
@endforeach
id(主キー)による検索
主キーで検索する場合はfind()
を使用します。
SELECTION * FROM sample where id =:primary
のSQL文と同じような内容です。
<input type="text" name="primary" id="" value="">
public function find(Request $request)
{
$item = sample::find($request->primary);
return view('sample.index', ['item' => $item]);
}
// 記述方法:クラス名::find('主キー');
{{ $items->name }}
{{ $items->tel }}
// 中略...
findメソッドの注意点
find()
の引数の型によってfirst()
で文字列として値を取得するか、findMany()
で配列として取得するかが変わります。
findMany()
はget()
で配列として値を取得するメソッドです。
長くなるのでコメントは割愛しますが、Builderからfindメソッドを抜粋します。
namespace Illuminate\Database\Eloquent;
public function find($id, $columns = ['*'])
{
if (is_array($id) || $id instanceof Arrayable) {
return $this->findMany($id, $columns);
}
return $this->whereKey($id)->first($columns);
}
複数のidから値を取得する
findメソッドで複数のレコードを取得する場合は引数を配列で記述するか、findメソッドの代わりにfindMany()
で記述します。
また、下記する複数の値を検索対象にする
の段落の書き方で検索する値に主キーを指定する方法でも可能です。
$flights = Sample::find([1, 2, 3,]);
// または
$flights = Sample::findMany([1, 2, 3,]);
特定の値を検索
主キー以外の値で検索する場合はwhere()
を使用します。
SELECTION * FROM samle where name =:'name
のSQL文と同じ内容です。
ここではget()
で全ての値を取得していますが、get('カラム名', '値')
やfirst()
で取得する値を指定することもできます。
<input type="text" name="name" id="" value="">
public function search(Request $request)
{
$items = sample::where($request->name)->get();
return view('sample.index', ['items' => $items]);
}
// 記述方法:クラス名::where('検索値')->取得方法;
@foreach ($items as $item)
{{ $items->name }}
{{ $items->tel }}
// 中略...
@endforeach
複数の値を検索対象にする
複数の値を検索対象とする場合はwhrer()
とorwhere()
をメソッドチェーンしていきます。
SELECTION * FROM samle where name =:name or address = :adrress
のSQL文と同じ内容です。
ここではaddress
をlike %search%
で検索していきます。
<input type="text" name="search" id="" value="">
public function search(Request $request)
{
$items = sample::samplee::where('name', ($request->search)->orwhere('address', 'LIKE', "%{$request->search}%")->get();
return view('sample.index', ['items' => $items]);
}
// 記述方法:クラス名::where('検索値')->取得方法;
@foreach ($items as $item)
{{ $items->name }}
{{ $items->tel }}
// 中略...
@endforeach
レコードの新規登録
NotNullのname、tel、addressを新規登録します。
まずはフォームで新規作成する値をリクエストします。
そしてリクエストした値はインスタンスしたモデルクラスの属性に代入してsave()
で保存されます。
また、idはオートインクリメントでテーブルを作成しているので$guarded
プロパティで保護しますが、当投稿では共通した設定のため以下では省略します。
<input type="text" name="name" id="" value="">
<input type="text" name="tel" id="" value="">
<input type="text" name="address" id="" value="">
// 以下に共通
protected $guarded = array('id');
public function insert(Request $request)
{
$sample = new Smaple;
$sample->name = $request->name;
$sample->tel = $request->tel;
$sample->address = $request->addres;
$sample->save();
}
// 記述方法:属性に登録する値を代入して保存
特定のidのレコードの更新する
新規登録と同じようにNotNullのname、tel、addressを更新します。
順序としては、更新する値の主キー(id)を取得してから、そのidに該当する値のプロパティを更新するという処理です。
更新も新規登録と同じように、リクエストした値をモデルクラスの属性に代入してsave()で保存します。
<input type="text" name="id" id="" value="">
<input type="text" name="name" id="" value="">
<input type="text" name="tel" id="" value="">
<input type="text" name="address" id="" value="">
public function update() {
$sample = Sample::find($request->id);
$sample->name = $request->name;
$sample->tel = $request->tel;
$sample->address = $request->addres;
$sample->save();
}
// 記述方法:検索した属性に更新する値を代入して保存
saveメソッドにおける注意点
save()
は単一のレコードしか更新できないため、複数レコードの値をまとめて更新する場合はupdate()
で保存します。
update()
は指定のフィールドに何かしらの値があれば保存するというメソッドです。
fill()
については後の段落で解説します。
長くなるのでコメントは割愛しますがModelからupdateメソッドを抜粋します。
$this->exists
は初期値がfalseとなっているbool型の変数です。
public function update(array $attributes = [], array $options = [])
{
if (! $this->exists) {
return false;
}
return $this->fill($attributes)->save($options);
}
updateメソッドによる値の更新
例にしているsampleテーブルにis_repeat
という判定の項目があるので、このフィールドが1となっているレコードの値を更新するという例を書きます。
where()
で対象のカラムを検索してupdate('値の配列')
で記述します。
public function update(PersonRequest $request)
{
Sample::where('is_repeat','0')->update(['comment'=>リピーターです,]);
// commentのカラムは存在しませんが追加したと仮定します
}
// 記述方法:Sample::where('検索値')->update([更新する値]);
fillメソッドによるレコードの取得
fill()
は引数に用意された配列の値をモデルのプロパティに代入するメソッドです。
そのため、フォームからリクエストされる値の全てを保存するため不要な情報を削除してから保存します。
エラーにはなりませんが不要な情報は不要です。
public function create(Request $request)
{
$sample = new Smaple;
$form = $request->all();
unset($form['_token']);
$sample->fill($form)->save();
return redirect('/sample');
}
レコードの削除
レコードを削除する場合は、削除するレコードを取得してdelete()
で実行します。
public function remove(Request $request)
{
Person::find($request->id)->delete();
return redirect('/person');
}
レコードの論理削除
Eloquentではテーブルの物理削除と論理削除を設定で変更することができます。
デフォルトでは物理削除となっているので、論理削除をする場合は以下のように設定します。
use SoftDeletes;
論理削除したレコードの確認
論理削除した値はonlyTrashed()
で確認することができます。
また、論理削除されていない値と論理削除された値の全てを確認する場合はwithTrashed()
を使用します。
public function showDel(Request $request)
{
$items = Person::onlyTrashed()->get();
$param = ['items' => $items];
return view('person.find', $param);
}
バリデーションの作成
モデルクラスでバリデーションのルールとメッセージを作成する例を記述します。
コントローラーに全てを記述するとスクリプトが読みづらくなるため、バリデーションのルールとメッセージはモデルに記入しています。
また、バリデーションは\Illuminate\Validation\ValidatesRequests
のvalidateメソッドが使用されています。
validateメソッドについては以下をご参考ください。
[validateメソッドによるバリデーション]
(https://qiita.com/gone0021/items/5699c29c7ce64f08b8d2)
public function insert(Request $request)
{
$this->validate($request, Sample::$rules, Sample::$messages);
}
// 記述方法:$this->validate(検証の値, 検証ルール, エラーメッセージ);
class Sample extends Model
{
public static $rules = array(
'name' => ['regex:/^[a-zA-Z0-9]+$/u' ],
'mail' => 'email',
'age' => 'integer|min:0|max:150',
);
public static $messages = [
'name.regex' => '半角英数字のみ',
'mail.email' => 'メールアドレスが必要です',
'age.numeric' => '整数で入力してください',
'age.between' => '0~150まで',
];
}
モデルクラスにメソッドを作成する
モデルクラスにメソッドを記述してデータベースを操作する方法です。
bladeテンプレートでform入力によるリクエストを行い、コントローラーでリクエストの処理を振り分け、モデルクラスで処理を記述してデータベースを操作していきます。
出力する値のフォーマットを定義する
モデルで出力する値のフォーマットを作成してテンプレートに出力します。
モデルクラスに出力する値を定義したら、テンプレートで定義したメソッドを読み込むという流れです。
ここではname
で検索していることを仮定したコントローラーだけ作成して、リクエストするテンプレートは割愛しています。
public function search(Request $request)
{
$items = sample::where($request->name)->get();
return view('sample.index', ['items' => $items]);
}
public function getData()
{
if (is_repeat != 0) {
$repeat = '再';
} else {
$repeat = '初';
}
return $this->name . ' (' . $repeat . ')';
}
@foreach
{{$item->getData()}}
@endforeach
// 出力例:なまえ (再)
スコープによる検索
モデルクラスでは上記したメソッドの他に、スコープというメソッドの記述方法があります。
スコープとは検索などの際に条件をメソッド化する機能です。
よく使用する条件や煩雑になる条件をスコープとして記述することによって可読性を高められて作業が楽になるというメリットがあります。
またスコープには、Eloquentモデルを使うと自動で条件が追加されるグローバルスコープ
と、条件を追加したい時にだけ使うローカルスコープ
があります。
グローバルスコープの使用例が思いつかなかったので、当投稿ではローカルスコープ
のみ記述します。
ローカルスコープの作成と使用
ローカルスコープを作成するにはモデルクラスにscope◯◯($queru, 引数)
というメソッドを作成します。
第一引数の$query
はWhereで取得されるのと同じようにBuilderのインスタンスが渡れます。
作成したローカルスコープはコントローラーでメソッドとして呼び出すことができます。
public function scopeNameOrAddress($query, $str)
{
return $query->where('name', 'LIKE', "%{$str}%")->orwhere('address', 'LIKE', "%{$str}%");
}
public function search(PersonRequest $request)
{
$items = Person::Name($request->name)->Address($request->address)->get();
$param = ['items' => $items];
return view('person.find', $param);
}
複数のスコープを使用する
上記したスコープにemail
の登録があるかどうかを検索条件に追加してみます。
public function scopeNameOrAddress($query, $str)
{
return $query->where('name', 'LIKE', "%{$str}%")->orwhere('address', 'LIKE', "%{$str}%");
}
public function scopeEmail($query, $str)
{
return $query->where('email', 'LIKE', "%{$str}%");
}
public function search(PersonRequest $request)
{
$items = Person::NameOrAddress($request->input)->Email($request->email)->get();
$param = ['items' => $items];
return view('person.find', $param);
}
参考
[Laravel 6.x Eloquent:利用の開始]
(https://readouble.com/laravel/6.x/ja/eloquent.html)