Symfony Doctrine 分页

10

我有实体用户,例如数量为90355,我需要每次获取100个用户并对这些用户进行某些逻辑操作。然后获取下一个100个用户,这是我的需求。但当我在服务器中查找所有用户时,如何解决这个问题?

public function find()
{
    $developers = $this->em->getRepository('ArtelProfileBundle:Users')->findBy(array(), array('id' => 'desc'));
    foreach ($developers as $developer) {
       $this->getApiFullContact($developer);
    }
    return true;
}

我认为这个函数很好,但是setFirstResult和setMaxResults是动态变量?

    public function getPaginationUser()
{
    $qb = $this->getEntityManager()->createQueryBuilder('d');
    $qb
        ->select('d')
        ->from('ArtelProfileBundle:Users', 'd')
        ->setFirstResult(0)
        ->setMaxResults(100)
        ->orderBy('d.id', 'DESC')
        ->getQuery()
        ->getResult()
    ;
    $query = $qb->getQuery();
    $results = $query->getResult();

    return $results;
}

如何进行这种迭代?


1
只需执行 ($page-1) * 100;,其中 $page 是所请求的页码,并将其替换为 setFirstResult 中的 0。此外,没有必要两次执行 getQuery / getResult。只需删除您那里的前两个调用即可。 - JimL
我如何知道如何调用函数,以及可能的第一个结果和最大结果动态变量?我更新了我的问题。 - shuba.ivan
请查看 https://github.com/KnpLabs/KnpPaginatorBundle。 - Frank B
不需要渲染模板,我使用计划任务运行命令,并对用户执行一些逻辑操作,KnpPaginatorBundle 能帮助我实现这个吗? - shuba.ivan
3个回答

16
我从我找到的一些东西中组合了这个例子,看起来似乎可以工作。这很基础,但这是一个开始。
SO答案:Doctrine2 Paginator获取总结果 Symfony文档:使用Doctrine的查询构建器查询对象
/**
 * @Route("/users/{page}", name="user_list", requirements={"page"="\d+"})
 */
public function getUsersByPage($page = 1)
{
    // get entity manager
    $em = $this->getDoctrine()->getManager();
    
    // get the user repository
    $developers = $em->getRepository(Users::class);
    
    // build the query for the doctrine paginator
    $query = $developers->createQueryBuilder('u')
                        ->orderBy('u.id', 'DESC')
                        ->getQuery();

    //set page size
    $pageSize = '100';
    
    // load doctrine Paginator
    $paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($query);

    // you can get total items
    $totalItems = count($paginator);

    // get total pages
    $pagesCount = ceil($totalItems / $pageSize);

    // now get one page's items:
    $paginator
        ->getQuery()
        ->setFirstResult($pageSize * ($page-1)) // set the offset
        ->setMaxResults($pageSize); // set the limit

    foreach ($paginator as $pageItem) {
        // do stuff with results...
        dump($pageItem);
    }

    // return stuff..
    return [$userList, $totalItems, $pageCount];
}

2
在查询中,orderBy键应该是u.id而不是d.id $query = $developers->createQueryBuilder('u') ->orderBy('u.id', 'DESC') ->getQuery(); - Saviour Dela

5
完全工作的示例在这里->使用Doctrine查询构建器中的限制和偏移量进行手动分页。我只是给你需要先了解的代码。
这就是它的工作原理,对我来说这是最佳实践!也许并不适用于其他人!
1.请求发送到控制器 2.控制器调用服务 3.服务使用Trait规范化请求参数 4.服务从仓库中提取数据 5.仓库将结果返回给服务 6.服务将结果传递给工厂 7.工厂创建结果模型 8.工厂将结果模型返回给服务 9.服务将结果模型返回给控制器 仓库(REPO)
namespace Application\BackendBundle\Repository;

use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query;

class StudentRepository extends EntityRepository
{
    /**
     * @param string|null $name
     * @param int         $limit
     * @param int         $offset
     *
     * @returns array
     */
    public function findPaginatedByName($name, $limit, $offset)
    {
        $qb = $this->createQueryBuilder('s');

        if ($name) {
            $qb->where('s.name = :name')->setParameter('name', $name);
        }

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

        return $qb->getQuery()->getResult(Query::HYDRATE_SIMPLEOBJECT);
    }

    /**
     * @param string|null $name
     *
     * @return int
     */
    public function findPaginatedByNameCount($name)
    {
        $qb = $this->createQueryBuilder('s')->select('COUNT(s)');

        if ($name) {
            $qb->where('s.name = :name')->setParameter('name', $name);
        }

        return $qb->getQuery()->getResult(Query::HYDRATE_SINGLE_SCALAR);
    }
}

PAGER TRAIT

namespace Application\BackendBundle\Util;

trait PagerTrait
{
    public function getPage($page = 1)
    {
        if ($page < 1) {
            $page = 1;
        }

        return floor($page);
    }

    public function getLimit($limit = 20)
    {
        if ($limit < 1 || $limit > 20) {
            $limit = 20;
        }

        return floor($limit);
    }

    public function getOffset($page, $limit)
    {
        $offset = 0;
        if ($page != 0 && $page != 1) {
            $offset = ($page - 1) * $limit;
        }

        return $offset;
    }
}

服务

namespace Application\BackendBundle\Service;

use Application\BackendBundle\Factory\StudentFactoryInterface;
use Application\BackendBundle\Model\Student\Result;
use Application\BackendBundle\Repository\StudentRepository;
use Application\BackendBundle\Util\PagerTrait;

class StudentService implements StudentServiceInterface
{
    use PagerTrait;

    private $studentRepository;
    private $studentFactory;

    public function __construct(
        StudentRepository $studentRepository,
        StudentFactoryInterface $studentFactory
    ) {
        $this->studentRepository = $studentRepository;
        $this->studentFactory = $studentFactory;
    }

    /**
     * @param string $name
     * @param int    $page
     * @param int    $limit
     *
     * @return Result
     */
    public function get($name, $page, $limit)
    {
        $page = $this->getPage($page);
        $limit = $this->getLimit($limit);
        $offset = $this->getOffset($page, $limit);
        $total = 0;

        $result = $this->studentRepository->findPaginatedByName($name, $limit, $offset);
        if ($result) {
            $total = $this->studentRepository->findPaginatedByNameCount($name);
        }

        return $this->studentFactory->createStudentResult($result, $name, $page, $limit, $total);
    }
}

-4

如何在Symfony上进行分页

/**
 * @Route("", name="admin_number_pool", methods={"GET"})
 */
public function index(NumberPoolRepository $repo, NumberPoolCategoryRepository $categories, Request $request): Response
{
    $page = $request->query->get('page', 1);
    $limit = 10;
    $pagesCount = ceil(count($repo->findAll()) / $limit);
    $pages = range(1, $pagesCount);
    $pools = $repo->findBy([], [], $limit, ($limit * ($page - 1)));


    return $this->render('admin/number-pool/index.html.twig', [
        'numberPools' => $pools,
        'categories' => $categories->findAll(),
        'pages' => $pages,
        'page' => $page,
    ]);
}

4
请分享更多细节。通过 $repo->findAll() 读取 所有 实体看起来有些过度,因为这会加载所有实体以计数。 - Nico Haase
1
@NicoHaase 是的,你说得对。我在这里有点匆忙。确实,如果数据库中有大量数据,那么这将是不切实际的。感谢您的评论。 - pohape

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接