Phân trang trong laravel ( có sử dụng đệ quy)
Chào ace Viblo , Mình đang gặp một vấn đề phân trang với đệ quy. mình có 1 bảng Daily ( id, title, affID,nguoigt ) Bây giờ nhiệm vụ mình cần liệt kê ra tất cả các đại lý con của 1 đại lý bất kỳ ( trường hợp nhiều hơn 10 con thì phân trang ) . Nếu list tất cả các con thì mình dùng đệ quy đã lấy ra được nhưng ngặt nỗi là không thể phân trang TH nếu dữ liệu có đến hàng nghìn, triệu con thì có vẻ không ổn. đây là code mình đang dùng.
- Trong model DaiLy
public function categories()
{
return $this->hasMany('App\DaiLy', 'nguoigt', 'affID');
}
public function childrenCategories()
{
return $this->hasMany('App\DaiLy', 'nguoigt', 'affID')->with('childrenCategories');
}
- Controller
public function getDaiLyChild()
{
$daily = DaiLy::where('affID',2)->with('childrenCategories')->paginate(2);
return view('view.daily', compact('daily'));
}
- View.daily
<ul>
@foreach ($daily as $category)
<li>{{ $category->name }}</li>
<ul>
@foreach ($category->childrenCategories as $childCategory)
@include('view.child', ['child_category' => $childCategory])
@endforeach
</ul>
@endforeach
</ul>
- view.child
<li>{{ $child_category->name }}- {{ $child_category->affID }}</li>
@if ($child_category->categories)
<ul>
@foreach ($child_category->categories as $childCategory)
@include('view.child', ['child_category' => $childCategory])
@endforeach
</ul>
@endif
Cảm ơn mọi người!
1 CÂU TRẢ LỜI
hàng triệu daily thì mình nghĩ hệ thống ko đạt đến ngướng đó đâu.
còn cả khi khi nhiều như vậy
hàm paginate của laravel đã tự lấy request->page để làm pagination ví dụ somehost?page=2
và số item perpage là 10
thì query tương đương với select * from daily... limit 10 offset 10
nếu bạn đánh index nguoigt và affID thì mình nghĩ tốc độ ko đến nỗi nào đâu
Cảm ơn bạn, có vẻ bạn chưa hiểu ý của mình lắm. Cái mình cần là phân trang mà chưa phân trang được. Nó có 1 điểm khù khoằm ở đây là khi dùng paginate(10) thì nó lấy đủ 10 cái và phân trang nhưng ở đây lại sử dụng đệ quy gọi ngược trở lại và như thế thì những thằng gọi đến child đó nó lại không nằm trong truy vấn nên paginate not work.
@tinhtn89 Bạn thử sửa
public function childrenCategories()
{
return $this->hasMany('App\DaiLy', 'nguoigt', 'affID')->with('childrenCategories');
}
--->
public function childrenCategories()
{
return $this->categories->with('childrenCategories');
}
số query sẽ không tăng theo số record mà sẽ tăng theo deep của tree, thử check xem kết quả DaiLy::where('affID',2)->with('childrenCategories')->get()
có là 1 collection không ? ok rồi thì làm bước tiếp theo
bạn muốn paginate list bao gồm con nó, con của con nó .... đúng không ?
vậy thì phải map lại kết quả, ở đây bạn xử lý ở server, nên bạn có thể viết 1 hàm để map lại nó, trong model hay helper hay gì tùy bạn
pseudocode
function mapDailyChildrenRecursiveToFlatList(Collection $collection, Array $arr = []): Collection {
if (!empty($collection->categories)) {
foreach($collection->categories as $cate) {
// u can exclude some keys u dont want
$arr[] = $cate;
$this->mapDailyChildrenRecursiveToFlatList($cate, $arr);
}
} else {
return collect($arr);
}
}
// in controller
$daily = DaiLy::where('affID',2)->with('childrenCategories')->paginate(2);
$childrenFlatList = mapDailyChildrenRecursiveToFlatList($daily);
return view('view.daily', ['daily' => $childrenFlatList ]);
@Plumpboy Mình đã test thì nó không chạy và báo lỗi ở Model
Model:
public function categories()
{
return $this->hasMany('App\DaiLy', 'nguoigt', 'affID');
}
public function childrenCategories()
{
return $this->categories->with('childrenCategories');
}
Mình có thử một cách khác lấy ra được các mảng con của nó, nhưng dưới dạng mảng trong mảng, không biết từ đó có lấy ra được danh sách ID không.
Controller:
$daily = DaiLy::where('affID',5)->select('id','affID','nguoigt')->with('childrenCategories')->get()->toArray();
$collection = collect($daily);
$collapsed = $collection->collapse();
$d = $collapsed->all();
dd($d);```
Mình đã giải quyết được bài toàn, nhưng không biết đã tối ưu hoặc có cách nào hay hơn không?
Model:
class DaiLy extends Model
{
protected $table ='daily';
public function categories()
{
return $this->hasMany('App\DaiLy', 'nguoigt', 'affID');
}
public function childrenCategories()
{
return $this->hasMany('App\DaiLy', 'nguoigt', 'affID')->with('childrenCategories')->select('id','affID','nguoigt');
}
}
Controller:
public function getTree()
{
$daily = DaiLy::where('affID',8)->with('childrenCategories')->select('id','affID','nguoigt')->get()->toArray();
$collection = collect($daily);
$collapsed = $collection->flatten();
$arr = array();
foreach($collapsed as $key=>$v) { if($key%3 ==0) { $arr[]=$v; } }
$dailyChild = DaiLy::whereIn('id',$arr)->select('id','affID','nguoigt','name','diachi')->Orderby('id','ASC')->paginate(5);
return view('tinh', compact('dailyChild'));
}
View
<ul> {{ $stt =0 }}
@foreach ($daily as $category)
<li>{{ $category->name }}</li>
<ul>
@foreach ($category->categories as $childCategory)
@include('child_category', ['child_category' => $childCategory,'stt'=>$stt])
@endforeach
</ul>
@endforeach
</ul>
<div class="paginate">{!--{$daily->links()}--}</div>
Cảm ơn @Plumpboy .
@tinhtn89 cho mình xem chỗ view child_category bạn viết như thế nào được không ạ
Bạn viết code vào trong cặp dấu như này để nó có màu mè cho dễ nhìn nhé:
```php
public function hello($name) { echo 'Hello '$name; }
```
Khi hiển thị trông nó sẽ như này:
@huukimit
@tinhtn89 Trông đẹp hơn hẳn