Flatten laravel nested relationship (parent to descendants)

﹥>﹥吖頭↗ 提交于 2020-04-30 14:08:19

问题


I have a parent children relationship on my model. What I want is to flatten all those collection including all those descendants of parent.

[
   {
      'name': 'Parent',
      'another_array' => [

          {
             'name': 'Another Array Name'
          }
      ],
      'children': [
         {
             'name': 'First Child',
             'address': 'lorem ipsum',
             'contact_no': '92390',


             'another_array' => [

                 {
                    'name': 'Another Array Name'
                 }
             ],
             'children': [
                {
                    'name': 'First Descendant',
                    'address': 'lorem ipsum',
                    'contact_no': '92390',
                    'children': [
                        {
                            'name': 'Descendant Child',
                            'address': 'lorem ipsum',
                            'contact_no': '92390',
                            'children': [
                                {
                                   'name': 'Last Descendant',
                                   'address': '',
                                   'contact_no': '',
                                   'children': []
                                }
                            ]

                        }
                    ]
                }
             ]
         }
      ]
   }
]


I tried the code below. However it only displays the second depth of children. It does not display the next children of the collection.

User.php
public function parent()
{
    return $this->belongsTo(User::class, 'id', 'parent_id');
}

public function children()
{

    return $this->hasMany(User::class,'parent_id', 'id');
}

public function descendants()
{
    return $this->children()->with('descendants');
}

UsersController.php

public function index()
{
    $parent = User::find(1);

    $parent->with('descendants')->find($parent->id);

    $descendants = $this->traverseTree($parent->descendants);

    return response($descendants);
}

protected function traverseTree($subtree)
{
    $descendants = collect([]);

    foreach ($subtree->descendants as $descendant) {

       $descendants->push($descendant);

       if($descendant->descendants instanceof Collection) {

          foreach ($descendant->descendants as $node) {

             $this->traverseTree($node);

             $descendants->push($node);
          }
       }
   }

   return $descendants;
}

Desired Output


    [
        {
            'name': 'Parent',
            'address': 'lorem ipsum',
            'contact_no': '92390'
        },
        {
            'name': 'First Child',
            'address': 'lorem ipsum',
                 'contact_no': '92390'
        },
        {
            'name': 'First Descendant',
            'address': 'lorem ipsum',
                 'contact_no': '92390',
        },
        {
            'name': 'Descendant Child',
            'address': 'lorem ipsum',
                 'contact_no': '92390',
        },
        {
            'name': 'Last Descendant' ,
            'address': '',
                 'contact_no': '',
        }

    ]

I am looking forward for your help.


回答1:


from your collection response convert it to an array by chaining the toArray() method so you output becomes and a multi-dimensional array instead of nested objects as shown below...

       $my_array = [
            'name' => 'Parent',
            'children' => [
                 'name' => 'First Child',
                 'address' => 'lorem ipsum',
                 'contact_no' => '234',
                 'children' => [
                    'name' => 'First Descendant',
                     'address' => 'lorem ipsum',
                     'contact_no' => '567',
                    'children' => [
                        'name' => 'Descendant Child',
                        'address' => 'lorem ipsum',
                        'contact_no' => '8890',
                        'children' => [
                            'name' => 'Last Descendant',
                            'address' => '',
                            'contact_no' => '',
                            'children' =>  []
                        ]
                    ]
                 ]
            ]
        ];

then you can use this helper function below:

protected function _flattened($array)
    {
        $flatArray = [];

        if (!is_array($array)) {
            $array = (array)$array;
        }

        foreach($array as $key => $value) {
            if (is_array($value) || is_object($value)) {
                $flatArray = array_merge($flatArray, $this->_flattened($value));
            } else {
                $flatArray[0][$key] = $value;
            }
        }

        return $flatArray;
    }

when you dump the $result = $this->_flattened($my_array);, you will have output like...

       [
            0 => [
                "name" => "Parent"
            ],
            1 => [
                "name" => "First Child",
                "address" => "lorem ipsum"
                "contact_no" => "234"
            ],
            2 => [
                "name" => "First Descendant"
                "address" => "lorem ipsum"
                "contact_no" => "567"
            ],
            3 => [
                "name" => "Descendant Child"
                "address" => "lorem ipsum"
                "contact_no" => "8890"
            ],
            4 => [
                "name" => "Last Descendant"
                "address" => ""
                "contact_no" => ""
            ],
        ];


来源:https://stackoverflow.com/questions/57039677/flatten-laravel-nested-relationship-parent-to-descendants

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!