简体   繁体   中英

Paginate a shuffled array with Pagerfanta

I have a page that displays 6 items (institutions in my case) on each paginated section of the page (therefore each page). I display the items in a random order using shuffle . I use Symfony 4 and Pagerfanta for the pagination. The problem I face is that every time I go to the next page, my query is being shuffled again. Randomizing the order is not the problem, the problem is this happens every time the user goes to the next page. It should only happen on the first page and remain in that order. I have read a similar question here, but the problem is that all solutions seem to imply a completely new paginator. Is there a method to use both pagerfanta and solve my problem?

My code right now:

InstitutionController.php

 // I query for the list of items (institutions)
 $q = $request->query->get('q');
 $query = $institutionRepository->searchAndSortPublished($q);

 // I randomize the order of institutions
 shuffle($query);

 $pagerfanta = $paginationHelper->paginate($request, $query, 6);

 return $this->render('institution/index.html.twig', [ 'paginator' => $pagerfanta, 'institutions' => $query, 'q' => $q]);

PaginationHelper.php

//...
    public function paginate($request, $array, $maxPerPage = 10)
{
    $page = $request->query->get('page', 1);
    $adapter = new ArrayAdapter($array);
    $pagerfanta = new Pagerfanta($adapter);
    $pagerfanta->setMaxPerPage($maxPerPage);
    $pagerfanta->setCurrentPage($page);

    return $pagerfanta;
}

Live example of my problem

If you are randomising the result, then the only real way would be to do your DB call on the first time, then store the rows (or just ids) in a session var or some other storage. Then you can refer to that result each time. Might also actually speed your page up!

Note that even if you had a seeded shuffle, you'd still need to fetch every record first.

I suppose that sometimes institutions repeat themselves several times on different pages and this is the problem.

The ad hoc solution is to shuffle institutions only on the given page. We will avoid repeating institutions on several pages (on the first page will always be the same institutions, but in different order). Users will be able to see all items.

For example, you can do this with the new adapter:

ShuffleArrayAdapter.php

class ShuffleArrayAdapter extends ArrayAdapter
{
    public function getSlice($offset, $length)
    {
        return shuffle(array_slice($this->array, $offset, $length));
    }
}

I am not sure if this solution suits you, but it's the fastest.

I've used Delboy1978uk's suggestion, storing the random order in a session variable. I just wanted to show how this is done for those who are running into this problem as well. PaginationHelper.php is left untouched, the controller now looks like this:

//..

$query = $institutionRepository->findAll();

// set the random order in a session variable if it hasn't been set yet.
if (!$session->has('institution_order')) {
    shuffle($query);

    // set the session variable.
    $session->set('institution_order', $query);
}

// the random order per session per user.
$radomizedOrder = $session->get('institution_order');
$pagerfanta = $paginationHelper->paginate($request, $radomizedOrder, 6);

return $this->render('institution/index.html.twig', [ 'paginator' => $pagerfanta ]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM