Tìm Điểm dừng trong đệ quy [Laravel]
Mình có 1 Bảng menu ( id, parent_id) Model
public function showChild()
{
return $this->hasMany('App\Menu', 'parent_id', 'ID')->with('showChild')->select('id', 'parent_id');
}
Nếu chỉ show tất cả ra thì mình dùng
$allChild = Menu::where('id',1)->with('showChild')->select('id', 'parent_id')->get();
$collection = collect($allChild);
$collapsed = $collection->flatten();
echo '<br>Count:'.count($collapsed)/2;
Đã giải quyết được bài toán rồi. Yêu cầu là khi nhập vào 1 ID bất kì phải kiểm tra xem ID đó có đủ điều kiện > 100 menu con ( menu cấp, 2,3,4.. vẫn tính) hay không?
Cách mình đang làm như trên thì nó sẽ đệ quy cho đến hết việc này hoàn toàn đúng và m đã xử lý được tuy nhiên có 1 nhược điểm là nếu menu đó có 10.000 con trong hệ thống thì nó sẽ vẫn đệ quy tìm cho đến hết việc này gây tốn thời gian cũng như ko được tối ưu.
Vậy, mình muốn là nó sẽ chỉ kiểm tra nếu đủ 100 con sẽ dừng ko chạy nữa. Hiện mình đang bế tắc chỗ này mong được giúp đỡ. Thanks
1 CÂU TRẢ LỜI
Mình nghĩ bạn ko nên dùng đệ quy ở ngay trong relationship như thế này.
Tốt nhất với hàm showChild thì chỉ nên lấy ra menu ngay dưới cấp của nó.
// trong model
public function child(){
return $this->hasMany('App\Menu', 'parent_id', 'ID')->select('id', 'parent_id');
}
Tiếp đến viết 1 hàm riêng để lấy tree menu, hàm này dùng đệ quy và thêm điều kiện break vào
// trong model
public function child(){
return $this->hasMany('App\Menu', 'parent_id', 'ID')->select('id', 'parent_id');
}
// helper
function submenu($menu, $limit = 0) {
$subMenuColection = collection();
$subMenu = $menu->child();
$subMenuColection->merge($subMenu)
$limit += $subMenu->count();
if ($limit < 100 && $subMenu->count() > 0) {
$subMenu->each(function($item, $key) use ($limit) {
if ($limit < 100) {
return $subMenuColection->merge(submenu($item, $limit))
} else {
return false;
}
})
}
return $subMenuColection;
}
// sử dụng trong controller...
$parent = Menu::where('id',1)->first();
$parrent ->submenu()
Tư tưởng là vậy, code trên có thể sai thì sửa thêm tị nha :v mình ko có cái để test
Cảm ơn bạn.
Có vẻ vẫn chưa đúng lắm. Mình set giới hạn là 20 con nhưng cho rất nhiều kết quả.
public function test()
{
$menu= Menu::where('id', 2318)->first();
echo '<br>Input: ' . $menu->id;
$gioihan=20;
$this->submenu($menu, $gioihan);
}
function submenu($menu, $gioihan = 0,$limit = 0,$char='',$stt=0) {
$subMenuColection = new collection();
$subMenu = $menu->child;
$subMenuColection->merge($subMenu);
$limit += $subMenu->count();
//echo '<br>Count'.$limit;
if ($limit < $gioihan && $subMenu->count() > 0) {
$subMenu->each(function($item, $key) use ($limit,$subMenuColection,$char,$stt,$gioihan) {
if ($limit < $gioihan) {
echo '<br>'.$stt.$char.$item->affID;
return $subMenuColection->merge($this->submenu($item, $gioihan,$limit,'__|'.$char,++$stt));
} else {
return false;
}
});
}
return $subMenuColection;
}
Kết quả khi chạy.
@tinhtn89 code demo thôi, còn lý do nó ko lấy đc 20 là vì ví dụ thằng 19 nó lại có 100 thằng con thì code trên nó sẽ cộng hết cả 100 thằng con vào.
còn về cơ bản thì bạn nên giới hạn theo độ sâu hơn là giới hạn theo số submenu. ví dụ 1 thằng cha có 100 thằng con, lấy 20 cái chẳng nhẽ lại lấy thằng cha : 19 thằng con thôi?
@le.vinh.thien Menu chỉ là ví dụ cho mn dễ hình dung thôi, còn thực tế bài toán của mình khác một chút. Yêu cầu là phải lấy và kiểm tra được một ID bất kì có đạt điều kiện tổng số menu con của nó đạt ( $gioihan = 20) hay không, Nếu có sẽ xử lý theo 1 hướng và ko thì theo hướng khác. Vậy nên mình mới cần check nó đạt 20 con hay không? còn nếu đếm hết ra thì nó lại như lúc đàu chỉ cần đệ quy là lấy hết được thôi (TH cùi bắp nhất)
@tinhtn89 nếu vậy thì bên trên vấn đề chỉ là phần check để đạt đc 20 phần tử, chứ điểm dừng đệ quy thì bạn đã có rồi nhé, việc check 20 phần tử thì bạn phải tự làm rồi
@le.vinh.thien cái code bên trên chính xác là nó chỉ giới hạn được số tầng thôi, còn số lượng thì nó hoàn toàn ko kiểu soát được.