2

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

Dirk J. Faber
  • 4,360
  • 5
  • 20
  • 58
  • Possible duplicate of [Randomize a PHP array with a seed?](https://stackoverflow.com/questions/6557805/randomize-a-php-array-with-a-seed) – Matt Raines Oct 06 '18 at 14:24
  • 1
    You could use the link above to check how to randomize an array using seed and for seed use the `$request->getClientIp()` assuming the IP is the only thing that remains relatively the same with each request for each client. Also, but probably a worse solution, is to map your array to a new one where you would also use some sort of seed (again, client's IP address) but to generate an index of an element, check if that element exist, modify the seed and try again, repeat until the index is unoccupied, set the value to that index. – domagoj Oct 09 '18 at 20:48
  • Show me the code snippet (view) where you iterate through the institutions. – AleX Oct 10 '18 at 15:58

3 Answers3

0

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.

delboy1978uk
  • 12,118
  • 2
  • 21
  • 39
  • I understand what you are saying at I will look into it. Do you have any advice on how to store it in a session var like you mentioned? – Dirk J. Faber Oct 13 '18 at 15:02
  • just store the results array, or maybe serialize it? When you pull it out the session pass the array into your ArrayAdapter – delboy1978uk Oct 15 '18 at 10:06
0

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.

AleX
  • 399
  • 3
  • 10
  • I see your point and thank you, but the problem is I do not want to display the same institutions on page 1 every single time. Even though they are in a different order, I want other institutions also to be displayed there. – Dirk J. Faber Oct 13 '18 at 15:00
0

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 ]);
Dirk J. Faber
  • 4,360
  • 5
  • 20
  • 58