0

I get JSON from API, and I need to convert it to a recursively nested object.

One property of my object is an array with elements of the same type as the parent object.

Here is my Data class:

class Group extends Data
{
    /** @var \App\Data\Group[] **/
    public array $subGroups;

    public function __construct(
        public string $id,
        array $subGroups,
    ) {
        /** @var \App\Data\Group[] */
        $this->subGroups = collect($subGroups)
            ->map(fn (array $group) => Group::from($group))
            ->all();
    }
}

And here is my JSON response:

[
    {
        "id": "1",
        "subGroups": [
            {
                "id": "1-1",
                "subGroups": []
            },
            {
                "id": "1-2",
                "subGroups": [
                    {
                        "id": "1-2-1",
                        "subGroups": []
                    }
                ]
            }
        ]
    },
    {
        "id": "2",
        "subGroups": []
    }
]

Having the following methods:

/**
 * @param array[] $groups
 * @return Group[]
 */
public function toGroups(array $groups): array
{
    return collect($groups)
        ->map(fn (array $group) => Group::from($group))
        ->all();
}

/**
 * @return Group[]
 */
public function toGroupsFromResponse(ResponseInterface $response): array
{
    return $this->toGroups(
        json_decode($response->getBody()->getContents(), true)
    );
}

I wanted for toGroupsFromResponse to return and object with nested Group type objects like so

# Pseudo-code
[
    Group {
        string id = '1'
        Group[] subGroups = [
            Group {
                string id = '1-1'
                Group[] subGroups = []
            },
            Group {
                string id = '1-2'
                Group[] subGroups = [
                    Group {
                        string id = '1-2-1'
                        Group[] subGroups = []
                    },
                ]
            }
        ]
    },
    Group {
        string id = '2'
        Group[] subGroups = []
    }
]

Instead, all subGroups are arrays of array.

# Pseudo-code
[
    Group {
        string id = '1'
        array subGroups = [
            array {
                string id = '1-1'
                array subGroups = []
            },
            array {
                string id = '1-2'
                array subGroups = [
                    array [
                        string id = '1-2-1',
                        array subGroups = []
                    ],
                ]
            }
        ]
    },
    Group {
        string id = '2'
        array subGroups = []
    }
]

It worked when I used Spatie's old DataTransferObject object, but I had trouble using the new Data object.

A broad question, I know, but where have I gone wrong?

s3c
  • 1,481
  • 19
  • 28

1 Answers1

0

You can use Spatie's DataCollection object:

<?php

namespace App\Data;

use Spatie\LaravelData\Attributes\DataCollectionOf;
use Spatie\LaravelData\Data;
use Spatie\LaravelData\DataCollection;

class Group extends Data
{
    public function __construct(
        public string $id,
        #[DataCollectionOf(Group::class)]
        public DataCollection $subGroups,
    ) {
    }
}
s3c
  • 1,481
  • 19
  • 28