Laravel の Eloquent 検証($dateFormat と $dates)

前回は Laravel の Eloquent を勉強するため、環境構築を行いました。

今回は日付に関する内容で、モデルのプロパティである$dateFormat$datesについて検証を行いました。

yudy1152.hatenablog.com



$dateFormat の検証

参考:Eloquent: Getting Started - Laravel - The PHP Framework For Web Artisans

created_atupdate_atのフォーマットを変更した時の検証を、以下の2パターンで行います。

  • デフォルトの timestamp にミリ秒も利用する(例:2019-05-06 10:10:22.123456)
  • Unix 時間を利用する(例:1557105050)

デフォルトの timestamp にミリ秒も利用する

$dateFormatプロパティにY-m-d H:i:s.uを指定します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public $incrementing = false;

    protected $keyType = 'string';

    protected $guarded = [
        'created_at',
        'updated_at',
    ];

    protected $dateFormat = 'Y-m-d H:i:s.u'; // ← ここを追加
}

デフォルトの$tabe->timestamps();では秒までしか登録されませんが、以下のようにtimestampsに桁数を渡す事で、小数部分も登録されるようになります。

<?php

    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->string('id', 36)->primary();
            $table->string('last_name');
            $table->string('first_name');
            $table->timestamps(6); // ← 桁数を指定
        });
    }
  • データ作成

ユーザーを1件登録します。

<?php
User::create([
    'id' => Uuid::uuid4()->toString(),
    'last_name' => '山田',
    'first_name' => '太郎',
]);

このようにミリ秒も含めて登録される事が確認出来ました。

f:id:yudy1152:20190506111524p:plain

Unix 時間を利用する

  • モデルの設定

$dateFormatプロパティにUを指定します。

<?php

class User extends Model
{
〜 略 〜
    protected $dateFormat = 'U'; // ← ここだけ変更
}

Unix 時間が登録されるように、$tabe->timestamps(); を以下のようにintegerを使って定義するようにします。

<?php

    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->string('id', 36)->primary();
            $table->string('last_name');
            $table->string('first_name');
            $table->integer('updated_at');
            $table->integer('created_at');
        });
    }
  • データ作成

ユーザーを1件登録します。

<?php
User::create([
    'id' => Uuid::uuid4()->toString(),
    'last_name' => '山田',
    'first_name' => '太郎',
]);

このように Unix 時間で登録される事が確認出来ました。

f:id:yudy1152:20190506105029p:plain

感想

外部のサービスと連携する時など、サービスによっては日時のフォーマットが異なる場合もあるかと思います。 そして、外部サービスから受け取ったデータをそのまま DB へ保存したい時などに使えるのではないかと思いました。


$dates の検証

参考:Eloquent: Mutators - Laravel - The PHP Framework For Web Artisans

Eloquent は、データを取得するとデフォルトでcreated_atupdated_atCarbonインスタンスへ変換してくれます。

created_atupdated_at以外に日時を扱うカラムを追加した際に、$datesでそのカラムを指定する事で、その指定したカラムもCarbonインスタンへ変換してくれるようになります。

マイグレーションファイルおよびデータの準備

User のマイグレーションファイルに、以下のようなカラムを追加して検証を行います。

  • カラム名logged_at(Null を許可)
    • ユーザーがログインした日時を保存しておく想定
<?php
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->string('id', 36)->primary();
            $table->string('last_name');
            $table->string('first_name');
            $table->timestamp('logged_at')->nullable(); // ← 追加
            $table->timestamps();
        });
    }

次に、テーブルを作成後、以下のようなレコードを作成しておきます。

f:id:yudy1152:20190506125034p:plain

$dates を設定しなかった場合の挙動

まずは、User モデルに$datesを設定せずにデータを取得してみます。

<?php
$user = User::find('01a2b401-b03b-4471-9fe3-c015e22f0552');

logger($user->logged_at);
logger(gettype($user->logged_at));

出力内容

[2019-05-06 03:33:23] testing.DEBUG: 2019-05-06 03:27:48  
[2019-05-06 03:33:23] testing.DEBUG: string

このようにデフォルトではstringで取得されます。 そのため、例えば2019年05月06日と表示したい場合に、自前でCarbonを使ったりdate関数を駆使してフォーマットの変換を行わなければなりません。

$dates を設定した場合の挙動

それでは、以下のように User モデルに$datesを設定します。

<?php

class User extends Model
{
〜 略 〜
    protected $dates = [
        'logged_at'
    ];
}

再度、出力内容を少し変えて取得してみます。

<?php
$user = User::find('01a2b401-b03b-4471-9fe3-c015e22f0552');

logger($user->logged_at);
logger(get_class($user->logged_at));
logger($user->logged_at->format('Y年m月d日'));

出力内容

[2019-05-06 04:06:02] testing.DEBUG: 2019-05-06 03:27:48  
[2019-05-06 04:06:02] testing.DEBUG: object  
[2019-05-06 04:06:02] testing.DEBUG: Illuminate\Support\Carbon  
[2019-05-06 04:06:02] testing.DEBUG: 2019年05月06日

このようにCarbonインスタンスへ変換されたものが取得され、formatメソッドで簡単に書式を整える事ができました。

感想

正直言いますと、今まで取得したstringの日付を頑張ってフォーマットしていました・・・。 もっと早く知っていれば!と後悔です。

おまけ

プライマリキーは UUID で

検証で使う User モデルの id を、デフォルトのもの(int)ではなく、以前勉強したUUIDで利用できるようにしています。

モデルの置き場所を変更

モデルはapp/Models下に置くように変更しました。

参考:【Laravel】Model ファイルのディレクトリ構成変更時にやること | ブロックチェーンエンジニアのブログ

実行された SQL を確認したい

下記参考サイトを真似させて頂きました。

※ 出力される SQL の実行時間($query->time)の単位はミリ秒です。

<?php

namespace App\Providers;

use Illuminate\Support\Facades\{DB, Log};
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * サービスプロバイダの登録
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * アプリケーションサービスの初期処理
     * 参考サイト:https://daiki-sekiguchi.com/2018/07/26/laravel-sql-log/
     *
     * @return void
     */
    public function boot()
    {
        if (config('app.env') !== 'production') {
            DB::listen(function ($query) {
                Log::info("Query Time:{$query->time}ms] $query->sql");
                Log::info($query->bindings);
            });
        }
    }
}