在Symfony2中获取控制器操作中的项列表的最佳实践。 见下面的例子

I start to create a RESTFul API using Symfony2 framework. It will return data only in JSON format. I'm trying to create a method in action controller that returns a list of users. The problem is that my code is too excess and is not elegant. I think that I do something wrong because simple SQL queries will be more shorter and be clearer than my code.

My method should get 4 input parameters from URL: limit, offset, sort field and sort direction. The output should be a JSON with array of users. I want to configure the fields in JSON using Symfony2 serializers. And I want to return total quantity of users in "X-Total-Count" header.

As I understood it is better to use FOSRestBundle. So, I tried this:

<?php

namespace AppBundle\Controller;

use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\Annotations;
use FOS\RestBundle\Request\ParamFetcherInterface;

class UserController extends FOSRestController
{
    /**
     * List all notes.
     *
     * @Annotations\QueryParam(name="_page", requirements="\d+", default=1, nullable=true, description="Page number.")
     * @Annotations\QueryParam(name="_perPage", requirements="\d+", default=30, nullable=true, description="Limit.")
     * @Annotations\QueryParam(name="_sortField", nullable=true, description="Sort field.")
     * @Annotations\QueryParam(name="_sortDir", nullable=true, description="Sort direction.")
     *
     * @Annotations\View()
     *
     * @param Request               $request      the request object
     * @param ParamFetcherInterface $paramFetcher param fetcher service
     *
     * @return array
     */
    public function getUsersAction(Request $request, ParamFetcherInterface $paramFetcher)
    {
        $sortField = $paramFetcher->get('_sortField');
        $sortDir = $paramFetcher->get('_sortDir');
        $page = $paramFetcher->get('_page');
        $limit = $paramFetcher->get('_perPage');

        $orderBy = null;
        if ($sortField && $sortDir) {
            $orderBy = [
                $sortField => $sortDir
            ];
        }
        $offset = ($page - 1) * $limit;

        $repository = $this->getDoctrine()
            ->getRepository('AppBundle:User');
        $users = $repository->findBy([], $orderBy, $limit, $offset);

        return $users;
    }
    ...
}

I think that this code is good because it is short and I can use serializer. And I can configure wich fields should be in response. But in this example I don't have a response object and I can't set "X-Total-Count" header. Also I don't know how to get total rows quantity.

I tried another one case:

<?php

namespace AppBundle\Controller;

use Symfony\Component\HttpFoundation\JsonResponse;
use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\Annotations;
use FOS\RestBundle\Request\ParamFetcherInterface;
use Doctrine\ORM\Tools\Pagination\Paginator;

class UserController extends FOSRestController
{
    /**
     * List all users.
     *
     * @Annotations\QueryParam(name="_page", requirements="\d+", default=1, nullable=true, description="Page number.")
     * @Annotations\QueryParam(name="_perPage", requirements="\d+", default=30, nullable=true, description="Limit.")
     * @Annotations\QueryParam(name="_sortField", nullable=true, description="Sort field.")
     * @Annotations\QueryParam(name="_sortDir", nullable=true, description="Sort direction.")
     *
     * @param Request               $request      the request object
     * @param ParamFetcherInterface $paramFetcher param fetcher service
     *
     * @return array
     */
    public function getUsersAction(Request $request, ParamFetcherInterface $paramFetcher)
    {
        $sortField = $paramFetcher->get('_sortField');
        $sortDir = $paramFetcher->get('_sortDir');
        $page = $paramFetcher->get('_page');
        $limit = $paramFetcher->get('_perPage');
        $offset = ($page - 1) * $limit;

        $em = $this->getDoctrine()->getEntityManager();
        $qb = $em->createQueryBuilder();

        $qb->select('u')
            ->from('AppBundle:User', 'u');

        if ($sortField && $sortDir) {
            $qb->orderBy('u.' . $sortField, $sortDir);
        }

        $query = $qb->getQuery();

        $query->setFirstResult($offset)
            ->setMaxResults($limit);

        $paginator = new Paginator($query);
        $totalCount = $paginator->count();

        $users = $query->getResult();

        $response = new JsonResponse($users);
        $response->headers->set('X-Total-Count', $totalCount);
        return $response;
    }
    ...
}

In this case I have a response object, I can set a "X-Total-Count" header. I can get total rows quantity using Paginator. But I can't use serializer like in previous example. And I think that this code is too excess and is not elegant. I use query builder, query, paginator just for getting a list of users.

Please, tell me how to get the list of users using simple, elegant code.

Instead of just returning $users like in the first code sample, you can do it like this:

$view = $this
    ->view($users, 200);
    ->setHeader('X-Total-Count', $totalCount);
return $this->handleView($view);

Also you could create your repository that extends base repository, and move your pagination logic there. That way you controller would be very thin.