2017-01-28 19 views
0

この問題はしばらく解決していません。解決策が見つからないので、助けてください。Laravel - ツリー構造のカウントを取得します。ここで、親の数は子供の数の合計です。

私は2つの関連モデルModelOneも持っていて、それ自体に関連しており、子供、孫など無限の数を持つことができ、ModelTwoに関連しています。私のget関数で

class ModelOne extends Model 
{ 
    ... 

    public function model_two() 
    { 
     return $this->hasMany(ModelTwo::class, 'foreign_key'); 
    } 

    //recursively get all children, grandchildren etc. 
    public function children() { 
     return $this->hasMany(ModelOne::class, 'foreign_key')->with('children'); 
    } 

    public function parent() { 
     return $this->belongsTo(ModelOne::class, 'foreign_key'); 
    } 
} 

class ModelTwo extends Model 
{ 
    ... 

    public function model_one() 
    { 
     return $this->belongsTo(ModelOne::class, 'foreign_key'); 
    } 
} 

ModelOneから私が持っている:

public function get($id = null) { 
    return is_null($id) ? 
     ModelOne::withCount('model_two')->get() : 
     ModelOne::withCount('model_two')->where('id', $id)->first(); 
} 

、それは私に素敵な1次元のオブジェクトの配列(または1つのオブジェクト)を与え、私は必要ModelTwo関連カウント形式と、関連するすべてのオブジェクトの個数が個別にカウントされます。

私は必要なもので、そのすべての子、孫など ですから、例えば、もしからカウントの合計と、そのオブジェクトにカウントする子供、孫などを、持っているリターン・アレイ内のすべてのオブジェクトのModelOne id = 2、parent_id = 1、countが3であるオブジェクトと、id = 3、parent_id = 1、countが2のオブジェクトを持つModelOneというオブジェクトが1つあり、id = 1のオブジェクトの場合、カウントは5になります。このロジックは、すべてのノードのツリー内で続けられます。

[ 
    { 
    "id":1 
    "parent_id":"NULL", 
    "model_two_count":5 
    }, 
    { 
    "id":2 
    "parent_id":1, 
    "model_two_count":3 
    }, 
    { 
    "id":3 
    "parent_id":1, 
    "model_two_count":2 
} 

... 

] 

答えて

1

だから、私は解決策を考え出した、とここでは、同じ問題で苦労することができる人あなたのすべてのためです。

まず、ModelOnewithCount('model_two')を追加しました。したがって、私は即座にModelTwoの関係数を持っています。私はまた、すべての子供 - 孫などからのカウントの合計を保持するプロパティ$return_countを追加しました。

class ModelOne extends Model 
{ 

    private $return_count = 0; 

    ... 

    public function model_two() 
    { 
     return $this->hasMany(ModelTwo::class, 'foreign_key'); 
    } 

    //recursively get all children, grandchildren etc. 
    public function children() { 
     return $this->hasMany(ModelOne::class, 'foreign_key')->withCount('model_two')->with('children'); 
    } 

    public function parent() { 
     return $this->belongsTo(ModelOne::class, 'foreign_key'); 
    } 
} 

その後、私は2つのヘルパー関数、再帰的にすべての子 - 孫 - などを取得し、1を追加しました。このように、この関数から

public function get_recursive($parentId = null){ 
    return is_null($parentId) ? 
     ModelOne::with('children')->get() : 
     ModelOne::where('id', $parentId)->with('children')->first(); 
} 

出力:親IDを与えられた、またはテーブルからすべてのレコードをバック与え用

[ 
    { 
    "id":1 
    "parent_id":"NULL", 
    "model_two_count":0. 
    "children": [ 
     { 
      "id":2 
      "parent_id":1, 
      "model_two_count":3 
     }, 
     { 
      "id":3 
      "parent_id":1, 
      "model_two_count":2 
     } 
     ] 
    } 

... 

] 

この例では、2つの次元のネスティングのためですが、それは無限にを行くことができます深い。 この関数で作成された戻りオブジェクトは、2番目の関数の入力パラメーターになります。 2番目の関数は、実際にはすべての子孫からのカウントの再帰的総和を実行しています。指定された親オブジェクトに対してプロパティmodel_two_countは、withCount('model_two')が呼び出されたときに作成されるためアクセスできます。また、with('children')が呼び出されたときにプロパティchildrenが作成されます。

private function count_sum($parentChildren) { 
    foreach ($parentChildren->children as $child) { 
     $this->return_count += $child->model_two_count; 
     $this->count_sum($child); 
    } 
    return $this->return_count; 
} 
私はget関数呼び出し終わり

public function get($id = null) { 
    if(is_null($id = null)) { 
     $data = ModelOne::withCount('model_two')->get();     
     return $data->map(function ($i) {    

      //get all children-grandchildren-etc. for specfic object with id = $i->id 
      $children = $this->get_recursive($i->id); 

      //if object with id = $i->id have children then model_two_count is sum of all model_two_count from all children-grandchildren-etc.      
      if (!empty(array_filter((array)$children->children))) { 
       $i->model_two_count = $this->count_sum($children); 
       //reset the return_count variable for next iteration. If this is not done, then sum from previous object will be added to the next object count 
       $this->return_count = 0; 
      } 
      return $i; 
     }); 
    } else { 
     $data = ModelOne::withCount('model_two')->where('id', $id)->get();     
     return $data->map(function ($i) { 
      $children = $this->get_recursive($i->id); 
      if (!empty(array_filter((array)$children->children))) { 
       $i->model_two_count = $this->count_sum($children);       
       $this->return_count = 0; 
      } 
      return $i; 
     })->first(); 
    } 
} 

そして、それはあなたが素敵な出力たいでしょう:

[ 
    { 
    "id":1 
    "parent_id":"NULL", 
    "model_two_count":5 
    }, 
    { 
    "id":2 
    "parent_id":1, 
    "model_two_count":3 
    }, 
    { 
    "id":3 
    "parent_id":1, 
    "model_two_count":2 
} 

... 

] 
関連する問題