15

if I have an Eloquent Model called Post, and the mysql table has:

integer ID, string Text

How do I convert this JSon:

{ post: { text: 'my text' } }

To the relevant Post object that, once received in the controller, I can save to the database like this:

public function store(Post $post)
{
    $post->save();
}

I'm not looking to build the logic that would do that for me, but for the Laravel way (or could it be that there isn't one? I googled it with no relevant results).

2
  • Have you fixed this? Commented Jun 24, 2017 at 1:31
  • Not yet, see comments on reply from @Bartłomiej Sobieszek Commented Jun 24, 2017 at 6:23

6 Answers 6

16
  1. Convert json to array
  2. Hydrate model from array

    $data = '{  
                "unique_id_001":{"name":"John","email":"[email protected]"},
                "unique_id_002":{"name":"Ken","email":"[email protected]"}
              }';
    $object = (array)json_decode($data);
    $collection = \App\User::hydrate($object);
    $collection = $collection->flatten();   // get rid of unique_id_XXX
    
    /*
        Collection {#236 ▼
          #items: array:2 [▼
            0 => User {#239 ▶}
            1 => User {#240 ▶}
          ]
        }
     */
    dd($collection);
    
Sign up to request clarification or add additional context in comments.

5 Comments

I got the collection as you demonstrated, but I need Eloquent objects that I can save. For example like so: $collection[0]->save();
I just had the same issue as Zephram, the Hydrate function works, but Hydrate is for importing arrays that came from the database and thus 'exist'. Calling Save on them will do nothing since they're not dirty: github.com/laravel/framework/issues/14288
Instead of explicitly converting the object from json_decode() to an array, you can pass true as the second argument: json_decode($data, true). Admittedly, it's not as clear what it's doing (how on Earth does true mean "array"?), but it does make the code a little more efficient.
You can make it clearer: json_decode($data, $array = true).
This is exactly what I need. Thanks :)
9

fill looks like the method you want. To avoid adding every attribute to your $filled array, which you would need to do if you wanted to use the fill method, you can use the forceFill method.

It accepts an associative array of attributes, so the JSON will have to be decoded, and we'll have to get the inner post key:

$rawJson = "{ post: { text: 'my text' } }";
$decodedAsArray = json_decode($rawJson, true);
$innerPost = $decodedAsArray['post'];

Once we have the decoded data, we can create an instance of the Post eloquent model and call forceFill on it:

$post = new Post();
$post->forceFill($innerPost);
$post->save();

This is similar to doing:

$post = new Post();
foreach ($innerPost as $key => $value) {
    $post->$key = $value;
}
$post->save();

Comments

5

Just turn it to array and fill an eloquent

$arr = json_decode($json, true);
$post = new Post;
$post->fill($arr);

1 Comment

Model::unguard() before the fill will fill up every property.
4

It's way simple as like followings:

$json_post = { "post": { "text": "my text" } };

$post = new Post(
    json_decode($json_post, true)
);

Now, you can run all eloquent methods on the most $post, ex:

$post->save()

I tested with laravel v7.11.0

Comments

0

Can you try it like this?

public function store($poststuff)
{
    $post = new Post;
    $post->text = $poststuff['text'];
    $post->save();
}

4 Comments

Yes but its not good enough because if I'm going to handle big objects it would mean lots of code for each one.
You do foreach to loop $poststuff
You're right, but this is more suitable for flat objects that don't have arrays or more objects inside them. I could write logic to handle this, but as I mentioned in the original post - I'm looking for a laravel solution to this.
not sure of any laravel way but to do foreach stuff to a var, like $data, then array_push($list,$data).. Then afterwards do ->insert($list);
0

JSON to model helper function

if (!function_exists('jsonToModel')) {
    function jsonToModel(string $jsonFilePath, Model $model)
    {
        $json = file_get_contents($jsonFilePath);
        $data = json_decode($json);

        foreach ($data as $value) {
            $value = (array) $value;
            $model->updateOrCreate(
                ['id' => $value['id']],
                $value
            );
        }
    }
}

use like this

jsonToModel(database_path('json/models.json'), new Model());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.