Laravel 7.xの新しいキャスト(データ変換)機能!実例

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、前回はLaravel 7.xの新機能のHTTPクライアントの話題をお届けしましたがいかがだったでしょうか。

さて、今回は引き続きLaravel 7.xの新しい機能紹介【第4弾】として、

新しいキャスト(データ変換)機能

をご紹介したいと思います。

「キャスト機能」とは、例えばpostsというテーブルにverified_at(承認された日時)というフィールドがあるとします。

この場合、verified_atはそのままだと「2020-01-31 08:26:16」というような文字列として取得されることになりますが、毎回この文字列をnew Carbon()などでデータ変換するのはめんどうです。

そこで登場するのが「キャスト機能」で、以下のように指定するだけで自動的にデータ変換を行ってくれます。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $casts = [
        'verified_at' => 'date' // 日付(Carbonインスタンス)に自動変換
    ];
}

※詳しいキャスト機能については、過去記事のキャスト(型変換)実例をご覧ください。

ただし、Laravelにはじめから用意されているキャスト機能は以下のように基本的なものだけです。

  • 日付、日付&時間
  • JSON(array)

【追記:2020.3.7】間違いがありましたので修正しました。m(_ _)m

そこで!

今回は、このキャスト機能を独自につくることができるLaravel 7.xの新機能「カスタムキャスト」機能をご紹介したいと思います。

ぜひ皆さんのお役に立てると嬉しいです😊✨

開発環境: Laravel 7.x

やりたいこと

今回は、暗号化された「ワンタイムパスワード」をusersテーブルで管理する例をつくります。

つまり、やりたいことは次の2つです。

  • DBに保存する場合、暗号化する
  • DBから取得する場合、復号する

(先ほどの日付変換の例が、暗号化&復号になっただけですね)

なお、フィールド名は分かりやすくone_time_passwordとします。

では、実際の作業に移りましょう!

専用のキャスト・クラスをつくる

では、まずは暗号化&復号するクラスをつくります。
場所は「/app/Casts/Encrypt.php」です。

そして、中身は以下のようにします。

<?php

namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class Encrypt implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return decrypt($value); // データ取得する場合:復号する
    }

    public function set($model, $key, $value, $attributes)
    {
        return encrypt($value); // データ保存する場合:暗号化する
    }
}

内容としては、get()がデータ取得する場合で、set()がデータを保存する場合に実行されるコードになります。

なお、get()set()内で利用できる値は以下のとおりです。

  • $model ・・・ モデルの本体(※1)
  • $key ・・・ フィールド名(今回だと “one_time_password”)
  • $value ・・・ 取得、もしくはセットする値
  • $attributes ・・・ その他のフィールドの値(配列)

※1: つまり、$model->nameのような使い方ができます。

使い方

では、先ほど使ったカスタムキャスト・クラスを実際に使ってみましょう。
今回はusersテーブルのデータ変換なので、「app/User.php」を開いてください。

そして、以下のように$castsを使って設定します。

<?php

// 省略

class User extends Authenticatable
{
    // 省略

    protected $casts = [
        // 省略
        'one_time_password' => Encrypt::class
    ];
}

これで、次のようにすると「secret」という文字列は自動的に暗号化されることになります。

$user = new \App\User();
$user->name = '山田太郎';
$user->email = 'taro.yamada@example.com';
$user->password = bcrypt('xxxxxxxx');
$user->one_time_password = 'secret'; // 自動的に暗号化される
$user->save();

逆にデータを取得すると自動的に復号され、「secret」が取得できます。

$user = \App\User::find(1);
echo $user->one_time_password; // "secret" が取得できる

パラメータを使う場合

次にカスタムキャストでパラメータを使う場合です。

例えば、先ほどつくったEncryptクラスに、さらに「Base64形式の文字列に変換する/しない」を決めるパラメータを追加してみましょう。

先に使い方です。通常のキャスト機能と同じく:に続いてパラメータを繋げます。(複数の場合は:true,1,testなどのようにカンマでつないでください)

protected $casts = [
    'one_time_password' => Encrypt::class .':true',
];

では、app/Casts/Encrypt.phpの中身を変更してパラメータに対応させます。

<?php

namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class Encrypt implements CastsAttributes
{
    private $is_base64;

    public function __construct($is_base64 = false)
    {
        $this->is_base64 = filter_var($is_base64, FILTER_VALIDATE_BOOLEAN);
    }

    public function get($model, $key, $value, $attributes)
    {
        if($this->is_base64) {

            $value = base64_decode($value);

        }

        return decrypt($value);
    }

    public function set($model, $key, $value, $attributes)
    {
        $value = encrypt($value);

        if($this->is_base64) {

            $value = base64_encode($value);

        }

        return $value;
    }
}

この中で重要なのは、パラメータで指定した値はコンストラクタで取得できるという点です。

また、このとき取得される値は文字列なのでBoolean型として使いたい方は、filter_var()、数値の場合はintval()などで適宜型の変換しておいてください。

開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ

おわりに

ということで、今回はLaravel 7.xの新しい「カスタムキャスト」機能をご紹介しました。

この機能を使えば、これまでAccessorMutatorで1つずつデータ変換していたものをクラス化することができ、さらにこのクラスは使い回しができるので1度作っておけば別の場所でも同じようにキャスティングすることができます。

ぜひ有効に活用してコード量を減らしてみてくださいね。

ではでは〜!

このエントリーをはてなブックマークに追加       follow us in feedly