phplaravel

Merge Laravel Resources into one


I have two model resources and I want to be merged into a flat array without having to explicitly define all the attributes of the other resource.

Model 1:

id
name
created_at

Model 2:

id
alternate_name
child_name
parent_name
sibling_name
created_at

Model1Resource

public function toArray($request)
{
    return [
        id => $this->id,
        name => $this->name,
    ]
}

Model 2 Resource

public function toArray($request)
{
    return [
        alternate_name => $this->alternate_name, 
        child_name => $this->child_name, 
        parent_name => $this->parent_name, 
        sibling_name => $this->sibling_name
    ]
}

I want Model1Resource to contain Model2Resource in a flat structure. I can easily get the Model 2 resource in a sub array by adding in another attribute to the resource like so:

Model2 => new Model2Resource($this->model2);

But this is not the flat structure. Ideally I would want to be returned a structure like this.

[id, name, alternate_name, child_name, parent_name, sibling_name]

I could do this by redefining all the attributes of Model2Resource in the Model1Resource but this seems unnecessary.

To clarify I am referring to https://laravel.com/docs/5.5/eloquent-resources#writing-resources. Under the relationships section a one to many relationship is demonstrated using posts. However if the structure is one to one I would expect to be able to make this a flat array instead of having an array in one of the properties.

What's an easy way to merge these two resources into one with a flat structure?


Solution

  • So after some digging this doesn't seem to be easily possible. I've decided the easiest way is to just redefine the outputs in the first model and use the mergeWhen() function to only merge when the relationship exists.

    return [
        'id' => $this->id,
        'name' => $this->name,
        // Since a resource file is an extension
        // we can use all the relationships we have defined.
        $this->mergeWhen($this->Model2()->exists(), function() {
            return [
                // This code is only executed when the relationship exists.
                'alternate_name' => $this->Model2->alternate_name, 
                'child_name' => $this->Model2->child_name, 
                'parent_name' => $this->Model2->parent_name, 
                'sibling_name' => $this->Model2->sibling_name,
            ];
        }
    ]