Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] How to include tree relationships? #23

Closed
juliomotol opened this issue Jan 25, 2023 · 7 comments
Closed

[Question] How to include tree relationships? #23

juliomotol opened this issue Jan 25, 2023 · 7 comments
Labels
question Further information is requested

Comments

@juliomotol
Copy link

We have a Menu and Node models where a Menu has many Nodes and a Node also has many child Nodes.

class Menu extends Model
{
    /** @return HasMany<Node> */
    public function nodeTrees(): HasMany
    {
        return $this->nodes()
            ->whereNull('parent_id') // ensure only root nodes will be fetched
            ->with('children');
    }
}

// and 

class Node extends Model implements Sortable
{
    /** @return HasMany<Node> */
    public function children(): HasMany
    {
        return $this->hasMany(self::class, 'parent_id')
            ->ordered() // scope from `spatie/eloquent-sortable`
            ->with('children');
    }
}

Then our controller action:

public function show($menu): MenuResource
{
    return MenuResource::make(
        QueryBuilder::for(Menu::find($menu))
            ->allowedIncludes(['nodeTrees'])
            ->firstOrFail()
    );
}

Now, when we try to /menus/9999?include=nodeTree, it only responds with the root nodes and doesn't show the child nodes nested in them. When try to inspect the model before MenuResource::make(), we do see whole node tree.

Any ideas on how this could be done?

@timacdonald
Copy link
Owner

Can you please show me the MenuResource implementation?

@timacdonald timacdonald added the question Further information is requested label Jan 26, 2023
@juliomotol
Copy link
Author

Here you go

class MenuResource extends JsonApiResource
{
    public function toAttributes($request): array
    {
        return  [
            'name' => $this->name,
        ];
    }

    public function toRelationships($request): array
    {
        return [
            'nodeTrees' => fn () => NodeResource::collection($this->nodeTrees),
        ];
    }
}

// and 

class NodeResource extends JsonApiResource
{
    public function toAttributes($request): array
    {
        return  [
            'label' => $this->label,
            'url' => $this->url,
            'target' => $this->target,
        ];
    }

    public function toRelationships($request): array
    {
        return [
            'children' => fn () => NodeResource::collection($this->children),
        ];
    }
}

@timacdonald
Copy link
Owner

Does the following result in the expected relationships,..

/menus/9999?include=nodeTree.children

@juliomotol
Copy link
Author

Tried that but it only responds with up to the second level of the tree:

array:6 [ // app/HttpTenantApi/Controllers/Menu/MenuController.php:30
  "id" => 1
  "name" => "Menu"
  "node_trees" => array:1 [
    0 => array:10 [
      "id" => 1
      "label" => "Node 1 "
      "menu_id" => 1
      "parent_id" => null
      "order" => 1
      "children" => array:1 [ // included in the response
        0 => array:10 [
          "id" => 2
          "label" => "Nested Node 1"
          "menu_id" => 1
          "parent_id" => 1
          "order" => 1
          "children" => array:1 [ // not returned in the response
            0 => array:10 [
              "id" => 3
              "label" => "Deeply Nested Node"
              "menu_id" => 1
              "parent_id" => 2
              "order" => 1
              "children" => []
            ]
          ]
        ]
      ]
    ]
  ]
]

@timacdonald
Copy link
Owner

So the issue here is that your model relationships are not setup to return all of the tree.

I recommend using this package to add a relationship to your model that may be included and will return all of the expected results: https://github.com/staudenmeir/laravel-adjacency-list

@juliomotol
Copy link
Author

I initially tried that, but gave up halfway. I'll try to fiddle with it more and get back to you. Thanks!

@timacdonald
Copy link
Owner

Sounds good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants