Laravel — Разбить случайные записи на страницы

Как мы можем разбить на страницы случайные записи в laravel? Например:

$products = Product::all()->orderBy(DB::raw('RAND()'));
$products->paginate(4);
$products->setPath('products');

Вышеупомянутые записи будут дублироваться из-за случайного порядка. Как я могу сохранить объект $products, чтобы при запросе новой страницы он фильтровался через тот же/фиксированный случайный набор записей?


person dang    schedule 31.05.2016    source источник
comment
Пожалуйста, расскажите нам, что вы уже пробовали и что не работает   -  person Alexandre Cartapanis    schedule 31.05.2016
comment
@AlexandreCartapanis - нумерация страниц дает повторяющиеся записи. Мы использовали приведенный выше код.   -  person dang    schedule 31.05.2016


Ответы (3)


Когда вы погрузитесь в документацию по mysql и найдите функциональность RAND(), вы увидите, что можете использовать «начальное число».

Используя семя, вы всегда будете получать те же результаты, что и рандомизированные.

Пример:

$products = Product

    ::all()

    ->orderBy(DB::raw('RAND(1234)'))

    ->paginate(4);

Вы можете сгенерировать свое собственное семя и сохранить его в сеансе или что-то, чтобы запомнить его.

Обновить

В построителе запросов Laravel теперь есть функция, которая точно выполняет одинаковый:

$products = Product

    ::all()

    ->inRandomOrder('1234')

    ->paginate(4);
person Thomas Van der Veen    schedule 31.05.2016
comment
+1. Поскольку я не использую Eloquent, мне повезло, что я обнаружил, что, по-видимому, вспомогательная функция перемешивания коллекции также допускает начальный параметр, который полезен, если вы используете нумерацию страниц и хотите предотвратить дублирование в последующих страницы: github.com/illuminate/support/blob/5.6/Collection. php#L1380 - person Ryan; 24.06.2018

Решение с помощью Laravel + Eloquent

Перед запросом Eloquent установите переменную сеанса. Я использовал time() для значения сеанса, поэтому я могу сохранять тот же порядок в течение определенного периода времени. Например, 3600 секунд (1 час).

if ($request->session()->has('session_rand')) {

    if((time() - $request->session()->get('session_rand')) > 3600){
        $request->session()->put('session_rand', time());
    }
}else{
    $request->session()->put('session_rand', time());
}

Добавьте ->orderBy() в запрос Eloquent, используя DB::raw() и переменную сеанса, которую мы установили выше:

->orderBy(DB::raw('RAND('.$request->session()->get('session_rand').')'))
person Darren Murphy    schedule 14.09.2018

Решение Ajax + фрагмент + сеанс + отложенная загрузка + разбиение на страницы + красноречивый + блейд

получить все продукты, установить количество элементов для каждого фрагмента (например, разбить на страницы) и сохранить его в сеансе (мы сохраняем фрагменты в сеансе, поэтому, когда приходит запрос ajax, он не будет снова вызывать $products = Product::inRandomOrder()->get();), первый фрагмент будет первой разбивкой на страницы

когда ajax запрашивает больше продуктов, он получает продукты из сеанса и получает правильную часть продуктов на основе запрошенного ajax номера страницы.

если кусков больше нет, просто вернитесь без каких-либо продуктов

    if(!$request->ajax()){

        $products = Product::inRandomOrder()->get();
        $chunks = $products->chunk(4);

        \Session::put('chunks',$chunks);
        $products = $chunks[0];
    }else{
        $page = $request->all()['page'];                
        $chunks = \Session::get('chunks');

        if(count($chunks)<$page){
            \Session::forget('chunks');
            return;
        }else{
            $products = $chunks[$page-1];
        }
    }

   if ($request->ajax()) {
        $view =  view('product_lazyLoad',compact('products'))->render();
        return response()->json(['html'=>$view]);
   }

   return view('products',compact('products'));

products.blade.php : главная страница

@if($products)
    <ul class="row" id="productLists">
        @include('product_lazyLoad')
    </ul>
@endif

<!-- load records -->

<div class="col-12 ajax-load text-center" style="display:none">
    <p><img src="/images/loader.gif">Loading More Products</p>
</div>

product_lazyload.blade.php : отображать продукты

@foreach($products as $product)
    <div>
        <p>Display your products here</p>
    </div>
@endforeach

ajax-вызов font-end: когда страница прокручивается до нижней части страницы, переменная page будет автоматически увеличиваться и запрашивать у бэкэнда больше продуктов. если возвращается больше продуктов, он добавит продукты к элементу с id = "productlist" в products.blade.php

    //lazy load
    var page = 1;
    $(window).scroll(function() {
        if($(window).scrollTop() + $(window).height() >= $(document).height()) 
        {
            page++;
            loadMoreData(page);
        }
    });

  function loadMoreData(page){
        $.ajax({
            url: '?page=' + page,
            type: "get",
            beforeSend: function(){
                $('.ajax-load').show();
            }
        }).done(function(data){
            if(!data.html){
                $('.ajax-load').html("No more records found");
                $('.ajax-load').show();
                return;
            }

            $('.ajax-load').hide();
            $("#productLists").append(data.html);

        }).fail(function(jqXHR, ajaxOptions, thrownError){
             //error handle
        });
    }
person Jason    schedule 17.12.2018