タグアーカイブ laravel

著者:杉浦

laravelのEloquentクラスのbootメソッド

 laravelはモデルの基盤をEloquentというクラスで定義しています。boot()はこのEloquentが呼び出されたときに走ることになる関数です。laravel5.6のソースコード(vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php)には次の様にあります。

    /**
     * The "booting" method of the model.
     * モデルの「初期起動」メソッド
     *
     * @return void
     */
    protected static function boot()
    {
        static::bootTraits();
    }

    /**
     * Boot all of the bootable traits on the model.
     * モデル上の起動可能なすべてのtraitを起動します
     *
     * @return void
     */
    protected static function bootTraits()
    {
        $class = static::class;

        $booted = [];

        foreach (class_uses_recursive($class) as $trait) {
            $method = 'boot'.class_basename($trait);

            if (method_exists($class, $method) && ! in_array($method, $booted)) {
                forward_static_call([$class, $method]);

                $booted[] = $method;
            }
        }
    }

 これにある様にbootはbootTraitsを呼びだしbootTraitsは頭にbootクラス名とあるtraitのメソッドを呼び出します。bootメソッドに追記する事、bootトレイトを作ることでモデル呼び出し時に様々なことが出来ます。特に便利な使い方はグローバルスコープです。グローバルスコープは次の様に記述する事でクエリビルダを呼び出す際に必ず記述したクエリがつくというものです。

    protected static function boot()
    {
        parent::boot();
        static::addGlobalScope('auth_post', function (Builder $builder) {
            $post_key = Users::findOrFail(auth()->id())->post_key;

            $builder->where('post.primary_key', $post_key);
        });
    }

 上記のコードでは今ログインしているuserに関連するpostでwhereをかけています。ログインしているユーザに関してのみのデータを扱う、という処理は頻繁に現れます。このようなほぼ必ずするべき記述をモデルクラス内の各メソッドで何度も記述することは無駄であり、bootメソッドの利用はこれを解決します。

  • この記事いいね! (0)
著者:杉浦

laravelのモデルであるEloquent ORMのCRUDに使うための便利な機能

Eloquent:利用の開始 5.6 Laravel
 Eloquent ORM(Object Relational Mapping)はPHPのフレームワークlaravelで実装されているSQLによるデータ操作をするモデル部分のことです。laravelでモデルを記述する際、多くの場合で以下の様に継承をします。

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    //
}

 このIlluminate\Database\Eloquent\Model;の中にあるCRUDに使える特に便利な機能を少し紹介します。少し詳しくは冒頭のリンクの説明書、とても詳しくはソースコード参照です。laravelのソースコードはとても丁寧で読みやすいためソースコードだけでも理解が進みます。
 全件取得をする時は次の様に記述できます。

$flights = Flight::all();

 これでSELECT * FROM Flights;の結果をCollection(配列の拡張形式)に変換した相当です。カラムを絞ることも簡単です。

$flights = Flight::all('primary_key', 'created_at');

 これでSELECT primary_key,created_at FROM Flights;の結果をCollection(配列の拡張形式)に変換した相当です。この様によく使われるパターンにはシンプルな回答が大体用意されています。
 ある1件を主キーを頼りに取得する時は次の様に記述できます。

$flight = Flight::find(1);

 これでSELECT * FROM Flights WHERE id = 1;の結果をモデルクラスFlightに変換した相当です。findした場合、対象が存在しないことも考えられます。そのためfindOr***の形で処理が用意されています。

$flight = Flight::findOrFail(2);
$flight = Flight::findOrNew(2);

 前者は見つからなかった場合、404エラーがユーザに返されます。後者は見つからなかった場合、新たにレコードを作成します。
 レコードを作成する時は次の様に記述できます。

$new_flight = [
    'name' => 'hoge',
    'mail' => 'fuga@example.com'
];
Flight::create($new_flight);

 create([‘カラム名’=>値の連想配列])これだけで新たにレコードがFlightsテーブルに追加されます。
 更新する時は次の様に記述できます。

$update_data = [
    'name' => 'fuga',
];
$flight = Flight::findOrFail(1);
$flight->fill($update_data)->save();

 これもcreateに似ています。fillでは渡されたカラム名のデータのみを更新します。createと違ってこちらはより複雑な操作を繰り替えすことも考えられており、save()と命令する必要があります。
 論理削除をする時はモデルにtraitを増やす必要があります。増やさない場合は物理削除です。

class Flight extends Model
{
    use SoftDeletes;
}

 実際に削除する時は次です。

$flight = Flight::findOrFail(1);
$flight->delete();

 これで作成、読み取り、更新、削除でCRUD制覇です。いずれも非常にシンプルに記述でき、大変便利です。

  • この記事いいね! (0)
著者:杉浦

laravelのエラー画面

 laravelのエラー画面は単なるエラーメッセージのみならず、詳細にエラーが起こるまでの実行過程と実行環境を示してくれます。この記事ではこのエラー画面の説明をします。
 エラーを起こした画面が次です。左上のエラーメッセージと右側のエラーが起きたコードが目につきます。どういうエラーかもわからないニッチなエラーが出たときは左上の赤丸で囲ってある部分の出番です。ここをクリックするとgoogleなどでエラーメッセージをググってくれます。

 手作業でエラーの内容を調べる際には次の画像の赤丸で囲ってある部分、Application framesとAll framesを使い分けるとよいです。通常laravelプロジェクトのフォルダ構成で/vendor以下の内容を改変する事はありません。All frameは/vedor以下も含んだスタックトレース、Application framesは/vendor以下を含まないスタックトレースです。Application framesで異常な値になった部分を大雑把に見つけ出し、All frameでより詳細に絞りこむ方法はよくとります。

 値を見つけ、追っていくと先に述べました。エラー画面で値の中身を追うには下の画像の赤丸部です。次の関数に値を渡すコードの行部分と引数の中身を見ることが出来ます。

 GET、POSTなどの通信に用いた値も右下部に格納されています。あまり見せるべき情報でないので隠してありますが、更に下の方にはサーバの情報も記述されてあります。

  • この記事いいね! (0)
著者:杉浦

チートシートとしてのresources/lang/ja/validation.php

 laravelには多彩なバリデーションルールが用意されています。記述も次の様に|区切りで羅列されたルールを持つ配列と同じキーを持つ配列を二つ使うのみで簡単です。

$rules = [
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
];
//Request $request Requestはlaravel内でarrayをラッピングした高級クラス
$validatedData = $request->validate($rules);
//もしくは単に配列で
$input = [
    'title' => 'hoge'
    'body' => 'hogehoge'
];
Validator::make($input, $rules);

 ここまで簡単な記述だと適したバリデーションルールをなるべく使いたいものです。しかしrequiredやmaxの様に頻繁に使うもののみならず全てのバリデーションルールを覚えようとした場合、それは一苦労です。バリデーションルール一覧の日本語訳は丁寧に正確にしてあるのですが詳細すぎるのか長大すぎるのかあまりやりたいことではありません。
 laravelには言語設定というものがあります。これはresources/lang/以下に配置するもので、設定されたlocalに合った言語設定が適宜読み込まれます。この言語設定にはテンプレートが出回っており日本語もご多分に漏れません。次のリンクはバリデーションに用いる日本語版言語設定ファイルへのリンクです。
validation.php言語ファイル 5.6 Laravel
 このファイルにはバリデーションのエラーメッセージが含まれています。例えば次です。

'digits_between' => ':attributeは:min桁から:max桁の間で指定してください。',

 これと同様にルール名=>日本語のエラーメッセージの配列の形で様々なルールとその対応が羅列されています。エラーメッセージはユーザに伝えるためのメッセージだけあってルールの内容を簡潔に教えてくれます。このためvalidation.php言語ファイル 5.6 Laravelでざっくりバリデーションルールを読んで詳細をバリデーション 5.6 Laravelで確認するというやり方がバリデーションの処理をコーディングする際に有効です。

  • この記事いいね! (0)
著者:杉浦

Laravelのデバッグ用関数dd()

 dd()はdump and dieの略です。何をやるかというとLaravel用の便利なvar_dump();exit;です。
 dd()の使い方はシンプル。Laravelフレームワークのphpコード内で次の様に記述するのみです。

dd(変数名A,変数名B,..)

 これを実行した場合、次の図の様に渡した変数を読みやすい形で表示するhtmlコードが返されます。
 
 特に便利なのは図にあるquery builderの様な巨大な構造体を読みたい時です。通常のvar_dump()で表示しようとした場合、とても読めたものではありません。var_dumpでは常に全展開の為、長いkeyと深いネストを持ってしまった場合、表示すら難しいです。
 dd()の定義はvendor/laravel/framework/src/Illuminate/Support/helpers.phpにあります。

    /**
     * Dump the passed variables and end the script.
     *
     * @param  mixed  $args
     * @return void
     */
    function dd(...$args)
    {
        foreach ($args as $x) {
            (new Dumper)->dump($x);
        }

        die(1);
    }

 dieはexitと同じなので読み飛ばしです。Dumperの中を追うとvendor/laravel/framework/src/Illuminate/Support/Debug/Dumper.phpを読むことになります。

use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;

class Dumper
{
    /**
     * Dump a value with elegance.
     *
     * @param  mixed  $value
     * @return void
     */
    public function dump($value)
    {
        if (class_exists(CliDumper::class)) {
            $dumper = in_array(PHP_SAPI, ['cli', 'phpdbg']) ? new CliDumper : new HtmlDumper;

            $dumper->dump((new VarCloner)->cloneVar($value));
        } else {
            var_dump($value);
        }
    }
}

 ここでSymfonyのvar_dumperに渡してLaravel自身のコードは終わります。Symfonyのvar_dumperの中は満足いくeleganceな表示を行うためにいくらか大きな処理をしています。CliDumper.phpだけで600行程、htmlDumperは900行程で記事に書き起こす程読み込む気力はありませんでした。

  • この記事いいね! (0)