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(), ще видите, че можете да използвате "seed".

Използвайки семе, винаги ще получавате едни и същи резултати, които са рандомизирани.

Пример:

$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 + chunk + session + lazyload + paginate + eloquent + blade

вземете всички продукти, задайте броя на елемента за всяка част (като пагиниране) и го съхранете в сесия (ние съхраняваме частите в сесия, така че когато влезе 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

font-end ajax call : когато страницата е превъртете до края на страницата, страницата с променливи автоматично ще се увеличи и ще поиска бекенд за повече продукти. ако се върнат повече продукти, той ще добави продуктите към елемент с 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