如何修复 "laravel pagination NOT updating on search"

How to fix "laravel pagination NOT updating on search"

我正在制作一个 table 具有特定当前步骤的订单,在这种情况下,该步骤是 'NESTEN' 和一些其他 where 语句来取回我需要的订单。

因为我不想要一个单页超过 400 个订单的列表,所以我想使用 laravels 分页功能,该功能还可以提高超过 100.000 条记录的列表的性能。 laravel 分页按原样工作,但当我想使用我制作的过滤器时,问题就来了。

我制作了一个下拉列表,需要根据列表中的 material 个订单进行过滤。在 table 中,我看到过滤后的订单,但分页的页数和订单数与以前相同。因此,问题在于从查询中过滤集合后分页没有更新。

我已经尝试过一些谷歌搜索并找到了几个没有解决我的问题甚至导致更多问题的解决方案...

还添加了一个 $orders->filter 函数来删除不符合过滤要求但没有结果的订单...

现在为了让它易于理解,我在 Route 文件中添加了代码。

我的路线如下

Route::get('orders/nesten', function(Request $request) {
    $orders = ShopOrder::where([
        ['ItemCode', 'LIKE', 'CM%'],
        ['Exact', '=', null],
        ['Nesting', '=', null],
        ['IsOnHold', '!=', 1],
        ['ShopOrderRoutingStepPlanCount', '!=', 0]
    ])->paginate(50);

    $filteredCollection = $orders->filter(function ($order) use($request) {
        if($request->exists('material')) {
            return $order->getCurrentStep() == 'Nesten' 
                   && $order->getMaterial() == $request->get('material');
        }
        return $order->getCurrentStep() == 'Nesten';
    });

    $orders->setCollection($filteredCollection);
    return view('dashboard/actions/Nesten')->with('shopOrders', $orders);
});

在 ShopOrder 模型中,我将函数 ->getMaterial() 和 ->getCurrentStep() 声明为

    public function routingStepPlans() {
        return $this->hasMany('App\Models\Exact\ShopOrder\RoutingStepPlan', 'ShopOrder', 'ID');
    }

    public function materialPlans() {
        return $this->hasMany('App\Models\Exact\ShopOrder\MaterialPlan', 'ShopOrder', 'ID');
    }

    public function getCurrentStep() {
        $current = $this->routingStepPlans()->where('LineNumber', ($this->timeTransactions()->count() + 1))->first();

        if(isset($current->Description)) {
            return $current->Description;
        }

        return 'Afgerond';
    }

    public function getMaterial() {
        $material = $this->materialPlans()->where('ItemCode', 'LIKE', 'TAP%')->first();

        if(isset($material->Description)) {
            return $material->Description;
        }
        return '-';
    }

和最后一个视图

        <table class="table table-striped table-bordered no-width">
            <thead>
                <tr>
                    <th>Order nummer</th>
                    <th>SKU</th>
                    <th>Omschrijving</th>
                    <th>Aantal</th>
                    <th>Datum</th>
                    <th>Deadline</th>
                    <th>Materiaal</th>
                    <th>DXF?</th>
                </tr>
            </thead>
            <tbody>
                @foreach($shopOrders as $shopOrder)
                    <tr>
                        <td>{{ $shopOrder->ShopOrderNumber }}</td>
                        <td>{{ $shopOrder->ItemCode }}</td>
                        <td>{{ str_replace('Car Mats', '',$shopOrder->Description) }}</td>
                        <td>{{ $shopOrder->PlannedQuantity }}</td>
                        <td>{{ $shopOrder->PlannedStartDate }} </td>
                        <td>{{ $shopOrder->PlannedDate }}</td>
                        <td>{{ $shopOrder->getMaterial() }}</td>
                        <td>{{ $shopOrder->hasDxf() }}</td>
                    </tr>
                @endforeach
            </tbody>
        </table>
        {{ $shopOrders->total() }}
        {{ $shopOrders->appends(['material' => Request::get('material')])->render() }} 

我希望使用 orders/nesten?material=Saxony%20Zwart&page=1 作为 url 分页 1 页,因为 material 有 9 个订单。

但目前它还有151页,和刚去orders/nesten一样。

以便您的分页继续,但保留您的搜索

{{ $shopOrders->appends(Request::except('page'))->links() }}

据我所知,您正在从数据库中获取所有记录,然后使用 Collection 过滤器对其进行过滤。分页是根据数据库查询结果构建的,因此您应该更新查询以进行过滤。


更新

  1. 创建抽象过滤器class
namespace App\Http\Filters;

use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Builder;

class AbstractFilter
{
    protected $builder;

    protected $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function apply(Builder $builder)
    {
        $this->builder = $builder;

        foreach($this->filters() as $name => $value) {
            if(method_exists($this, $name)) {
                call_user_func_array([$this, $name], array_filter([$value]));
            }
        }

        return $this->builder;
    }

    public function filters()
    {
        return $this->request->all();
    }
}
  1. 根据您的请求扩展 class(注意 - 这里的方法名称是过滤器的请求参数):
namespace App\Http\Filters;

class OrdersFilter extends AbstractFilter
{
    public function material($value = null)
    {
        if (!is_null($value)) {
            // return modified query here (return $this->builder->where....) 

        }
    }
}

  1. 为您的模型添加范围(在 ShopOrder 模型中):
public function scopeFilter($query, OrderFilters $filter) {
    return $filter->apply($query);
}
  1. 像这样更新您的查询:
$orders = ShopOrder::whereLike('ItemCode', 'CM%')
    ->whereNull('Exact')
    ->whereNull('Nesting')
    ->where('IsOnHold', '!=', 1)
    ->where('ShopOrderRoutingStepPlanCount', '!=', 0)
    ->filter(new OrdersFilter($request))
    ->paginate(50);

并且您可以跳过所有的集合过滤。您还可以向 OrdersFilter class.

添加更多过滤器参数

注意:我在没有测试的情况下编写了所有内容,因此可能存在一些小错误。此外,我还没有编写没有数据库结构的材料过滤器,但您的模型方法可能会更好。

更新

对于过滤材料方法,我会使用这样的方法(如果有效,则不是 100%,尚未测试):

public function material($value = null) {
    if (!is_null($material)) {
        return $this->builder->having('', function($query) use ($value) {
            return $query->where('ItemCode', 'LIKE', 'TAP%')
                ->where('description', '=', $value);
        })
        ->having('routingStepPlans', function($query) {
            return $query->where('LineNumber', ShopOrder::timeTransactions()->count() + 1)
               ->where('description', '=', 'Nesten');
        });
    }
}