【问题标题】:How to fix "laravel pagination NOT updating on search"如何修复“laravel 分页不更新搜索”
【发布时间】:2019-10-17 07:38:44
【问题描述】:

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

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

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

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

还增加了$orders->过滤功能,将不符合过滤条件但没有结果的订单剔除掉……

为了让它暂时易于理解,我在 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() }} 

我希望分页中的 1 页以 orders/nesten?material=Saxony%20Zwart&page=1 作为 url,因为该材料有 9 个订单。

但目前还是有151页,跟去orders/nesten一样。

【问题讨论】:

    标签: php laravel eloquent laravel-6


    【解决方案1】:

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


    更新

    1. 创建抽象过滤器类
    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. 为您的请求扩展该类(注意 - 此处的方法名称是过滤器的请求参数):
    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 类添加更多过滤器参数。

    注意:我写的所有东西都没有测试,所以可能会有一些小错误。此外,我还没有编写没有数据库结构的材料过滤器,但是您的模型方法可能会更好。

    更新

    对于过滤材料方法,我会使用这样的方法(如果有效,则不是 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');
            });
        }
    }
    

    【讨论】:

    • 所以基本上我不能使用我的模型函数,而是更改查询以将它们排除在查询结果之外?
    • 给我大约 30 分钟,我会用我认为最好的来更新我的答案。
    • 代码正在运行,我现在正在尝试弄清楚如何编写材料过滤器。我将如何以更好的方式编写这些模型方法?
    • 添加了一个例子,但我敢打赌它不是 100% 工作的,只是为了给你一个想法。
    • 我得到一个ErrorException,调试后我看到了响应,看截图。我应该改变什么才能不让闭包回来? Closure 类的对象无法转换为字符串gyazo.com/db8cdc13ee82f051928c506b84a304be
    【解决方案2】:

    让您的分页继续,但保持您的搜索

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

    【讨论】:

      猜你喜欢
      • 2020-09-19
      • 2014-11-29
      • 2021-01-10
      • 1970-01-01
      • 2014-11-02
      • 2017-02-24
      • 2015-02-01
      • 2019-05-06
      • 1970-01-01
      相关资源
      最近更新 更多