LoginSignup
20
22

More than 5 years have passed since last update.

LaravelのEloquentでJSON型の列を取得する

Posted at

LaravelのEloquentで列の型がJSON型の列を取得するときにちょっとハマったので調査しました。

$post = Post::find(1);
echo $post->json_column->col1;  // エラー
echo $post->json_column['col1'] // エラーにならない

TL;DR

結論からいうとJSON型の列を取得する場合は
モデルクラスの$castsにjsonであることを明示しておき、
$model->json_column['property']というように連想配列でアクセスすれば取得できます。

環境

名前 バージョン
PHP 7.1.6
Laravel 5.5.14

配列でのアクセスになるのはなぜか

モデルは以下のとおり。

Models/Post.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model as Eloquent;

class Post extends Eloquent
{
    use \Illuminate\Database\Eloquent\SoftDeletes;

    protected $casts = [
        'json_column' => 'json',  // ★これ
    ];

    protected $fillable = [
        'json_column',
    ];
}

$castsをjsonにしているのでjson_decodeされた結果が返ってくると思ったので
プロパティアクセス($post->json_column->col1)でいけると思ったのですがエラーになります。
配列でアクセス($post->json_column['col1'])するとエラーになりません。

ひょっとしてjson_decode($string, true)で連想配列にしてjsonをパースしてるのではと思ってソースを見てみました。

Illuminate\Database\Eloquent\Concerns\HasAttributes.php
    /**
     * Cast an attribute to a native PHP type.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return mixed
     */
    protected function castAttribute($key, $value)
    {
        if (is_null($value)) {
            return $value;
        }

        switch ($this->getCastType($key)) {
            case 'int':
            case 'integer':
                return (int) $value;
            case 'real':
            case 'float':
            case 'double':
                return (float) $value;
            case 'string':
                return (string) $value;
            case 'bool':
            case 'boolean':
                return (bool) $value;
            case 'object':
                return $this->fromJson($value, true);
            case 'array':
            case 'json':
                return $this->fromJson($value);    // ★ここ
            case 'collection':
                return new BaseCollection($this->fromJson($value));
            case 'date':
                return $this->asDate($value);
            case 'datetime':
                return $this->asDateTime($value);
            case 'timestamp':
                return $this->asTimestamp($value);
            default:
                return $value;
        }
    }

    /**
     * Decode the given JSON back into an array or object.
     *
     * @param  string  $value
     * @param  bool  $asObject
     * @return mixed
     */
    public function fromJson($value, $asObject = false)
    {
        return json_decode($value, ! $asObject); // ★ここでjsonを連想配列にしている
    }

json_decodeの第2引数をtrue、つまりassocがtrueなので連想配列形式で返却されます。
モデルクラスのプロパティで$castsをjsonにしていた場合は連想配列でキャストされたものが返却されます。

参考

PHP.net json_decode

20
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
22