Car
Car

Reputation: 13

Order pagination result in Symfony 2

I have a question about the order in the pagination in Symfony 2.7.

Before we used pagination we used the PHP function usort to sort some things. But my question now is how could we implement the usort in the doctrine query with the same order like the usort. Which needs to be working with the Paginator. Since when we use now the query (here under) we don't get the proper results.

usort function:

        usort($result, function ($a, $b) {
        $aBegin = $a->getStartDate() ?: $a->getCreatedDate();
        $bBegin = $b->getStartDate() ?: $b->getCreatedDate();
        if ($aBegin < $bBegin) {
            return -1;
        }
        if ($aBegin == $bBegin) {
            return 0;
        }
        if ($aBegin > $bBegin) {
            return 1;
        }

        return 0;
    });

How could we implemented the usort in the following query:

    $build = $this->createQueryBuilder('building');
    $build
        ->addSelect('users', 'furniture')
        ->join('building.users', 'users')
        ->leftJoin('building.furniture', 'furniture')
        ->where('building.id = :id')
        ->setParameter('id', $id)
        ->orderBy('building.getStartDate', 'ASC')
        ->addOrderBy('building.getCreatedDate', 'DESC');

    $paginator = new Paginator($build->getQuery(), $fetchJoinCollection = true);
    $result = $paginator->getQuery()
        ->setFirstResult($offset)
        ->setMaxResults($limit)
        ->getResult();

Thanks!

Doctrine orm: 2.2.3, Symfony version: 2.7

Upvotes: 0

Views: 1317

Answers (1)

Alan T.
Alan T.

Reputation: 1440

To add such a condition, you can use a CASE expression in your select clause. You can write something like CASE WHEN b.startDate IS NULL THEN b.createdDate ELSE b.startDate END to have the behaviour described in your usort function.

That being said, you can't simply add this to your order by clause. You will need to select this value, give it an alias and then add an order by based on the newly selected value. Since you probably don't want to get a mixed result (where your entities would be mixed with scalar values), you can use the HIDDEN keyword to remove the computed field from the result set.

All put together, it could look like this:

// $qb your query builder with all your other parameters
$qb->addSelect('CASE 
    WHEN building.startDate IS NULL 
        THEN building.createdDate 
        ELSE building.startDate
    END 
    AS HIDDEN beginDate');
$qb->orderBy('beginDate', 'DESC');

Note that while this works, you might encounter performance issues if you have a lot of entries in your table as the whole table is very likely to be scanned entirely for this query to be executed.

Upvotes: 1

Related Questions