bunty's blog

ググったこととか勉強したことのメモ

Laravel の Model で配列に cast させる際に文字化けさせないようにする

日本語のエラーメッセージなどを扱う際に、PHPjson_encode を使用する場合には、第二引数に JSON_UNESCAPED_UNICODE を指定する必要があります。

<?php

php > echo json_encode(['あ', 'い']);
["\u3042","\u3044"]
php > echo json_encode(['あ', 'い'], JSON_UNESCAPED_UNICODE);
["あ","い"]

www.php.net

定義済み定数の詳細についてはこちら

www.php.net

Model の $cast で array を指定する場合

日本語をそのまま保存しようとする場合には同様の対応が必要になります。これも内部的には保存時に json_encode を実行していて、取得時に json_decode を実行するようになるからです。

User クラスは適当なのであしからず。

<?php

>>> factory(App\Models\User::class)->create(['some_list' => ['あ', 'い']])
=> App\Models\User {#4716
     some_list: "["\u3042","\u3044"]",
     updated_at: "2021-08-02 14:47:01",
     created_at: "2021-08-02 14:47:01",
     id: 191,
   }

これは Medel 内で asJson を指定して、下記のようにすることで保存できるようになる。

都度定義するのは手間なので、親クラス側で定義しても良いかと思う。

<?php

class User extends Model
{
    // 省略

    protected $casts = [
        'some_list' => 'array',
    ];

    // Model 内にこれを指定
    protected function asJson($value)
    {
        return json_encode($value, JSON_UNESCAPED_UNICODE);
    }
}

// 再度 tinker から検証
>>> factory(App\Models\User::class)->create(['some_list' => ['あ', 'い']])
=> App\Models\User {#3785
     some_list: "["", ""]",
     updated_at: "2021-08-02 14:47:38",
     created_at: "2021-08-02 14:47:38",
     id: 192,
   }

Collectionでも同様

ちなみに、collection の toJson も同様です。内部で json_encode を実行しているだけなので引数に JSON_UNESCAPED_UNICODE を指定する必要があります。

<?php

>>> User::first()->toJson()
=> "{"id":1,"name":"\u3042","created_at":"2021-07-21 10:09:53","updated_at":"2021-07-21 10:09:53"}"
>>> User::first()->toJson(JSON_UNESCAPED_UNICODE)
=> "{"id":1,"name":"","created_at":"2021-07-21 10:09:53","updated_at":"2021-07-21 10:09:53"}"