【问题标题】:Is there a way to define first item of pagination results?有没有办法定义分页结果的第一项?
【发布时间】:2019-02-01 20:57:01
【问题描述】:

我正在建立一个 Symfony 项目,显示带有管理界面的分页博客文章来管理所有这些内容。在此管理员上,还可以“突出显示”其中一个公共博文,以便突出显示的博文仅显示在第一页的第一个位置。

我需要每个页面上的项目数相同,这就是我要处理的问题。

我正在使用PagerFanta,所以我创建了一个带有“分页”功能的 AbstractRepository。

protected function paginate(QueryBuilder $qb, $limit = 20, $offset = 0)
{
    if ($limit == 0) {
        throw new \LogicException('$limit must be greater than 0.');
    }

    //Instantiates the pagination object with the result of the query
    $pager = new Pagerfanta(new DoctrineORMAdapter($qb));

    //Sets max data per page
    $pager->setMaxPerPage($limit);

    //Sets the current page
    $pager->setCurrentPage($offset);

    return $pager;
}

在我的博文存储库中,我创建了一个查询构建器来获取所有公共博文,但突出显示的博文除外,因为我可以通过另一种方式将其显示在第一页的顶部。

public function findAllVisible($id, $limit = 3, $offset = 1, $order = 'DESC')
{
    $qb = $this
        ->createQueryBuilder('a')
        ->select('a')
        ->where('a.website = :website')
        ->setParameter('website', 'blog')
        ->andWhere('a.public = :public')
        ->setParameter('public', true)
        ->andWhere('a.id != :id')
        ->setParameter('id', $id)

        ->orderBy('a.dateInsert', $order)
    ;

    return $this->paginate($qb, $limit, $offset);
}

所以我首先尝试根据当前页面更改限制和偏移量,但逻辑上我在第一页和第二页之间丢失了一个项目。

然后我尝试在 querybuilder 中包含突出显示的博客文章,但如果当前页面是第一个页面,我不知道如何将其定义为第一个结果。

您知道如何强制第一个结果仅在首页上突出显示吗?还是按预期显示结果的另一种干净且适当的方式?

【问题讨论】:

    标签: symfony doctrine-orm


    【解决方案1】:

    我回答自己是因为我设法做我需要做的事。如果有人正在处理同样的问题,我就是这样做的。

    我不再使用 PagerFanta,而是使用 Doctrine Paginator 工具。 我没有从我的查询中排除我突出显示的文章,而是用a.id = :highlightedId DESC, a.dateInsert DESC 替换了我最初的ORDER BY。 现在它按预期工作。

    这是我的新存储库函数:

    /**
     * Finds all visible articles
     *
     * @param int $highlightedTipId the highlighted tip id
     * @param int $page current page
     * @param int $limit max items per page
     *
     * @throws InvalidArgumentException
     * @throws NotFoundHttpException
     *
     * @return Paginator
     */
    public function findAllVisible($highlightedTipId, $limit = 3, $page)
    {
        if (!is_numeric($page)) {
            throw new InvalidArgumentException('$page value is incorrect (' . $page . ').');
        }
    
        if ($page < 1) {
            throw new NotFoundHttpException('Page not found');
        }
    
        if (!is_numeric($limit)) {
            throw new InvalidArgumentException('$limit value is incorrect (' . $limit . ').');
        }
    
        $entityManager = $this->getEntityManager();
    
        $query = $entityManager->createQuery(
            "SELECT
                a,
                CASE WHEN a.id = :id THEN 1 ELSE 0 END AS HIDDEN sortCondition
            FROM App\Entity\Item a
            WHERE
               a INSTANCE OF App\Entity\TipArticle
            AND
                a.website = :website
            AND
                a.public = :public
            ORDER BY
                sortCondition DESC,
                a.dateInsert DESC
            "
        );
    
        $query->setParameter(':website', 'blog');
        $query->setParameter(':public', true);
        $query->setParameter(':id', $highlightedTipId);
    
        $firstResult = ($page - 1) * $limit;
        $query
           ->setFirstResult($firstResult)
           ->setMaxResults($limit);
        $paginator = new Paginator($query);
    
        if (($paginator->count() <= $firstResult) && $page != 1) {
            throw new NotFoundHttpException('Page not found');
        }
    
        return $paginator;
    }
    

    关于 CASE WHEN a.id = :id THEN 1 ELSE 0 END AS HIDDEN sortCondition 这一行的一句话:这是我发现用 Doctrine 写 ORDER BY a.id = :highlightedId DESC 的唯一方法。如您所见,我制作了 DQL,但也可以使用 QueryBuilder。

    希望它会有所帮助! :)

    【讨论】:

    • 很高兴你弄清楚了。您还可以发布您的答案代码吗?只是更改分页器并不能在代码问答网站上真正涵盖它;-) 谢谢
    • 嗨,发布了一些 cmets 但删除了它们以支持答案。如果您愿意,请随意使用它。我认为您的答案相当混乱,因为您混淆了“正常”位置。例如,您不需要在 Repo 中使用 EntityManager,并且您真的不应该手动构建查询(提供了 QueryBuilder 和 Criteria 来处理这个问题)。所以我想我会给你我的答案。不过坚持下去;-)
    【解决方案2】:

    Nice, well done。如果我可以提供一些建议。在 repo 中,您不需要获取 ObjectManager ($this-&gt;getEntityManager()),因为 repo 已经用于一种实体,在这种情况下为 Item。您应该改用Criteriapractical example docs

    你应该在你拥有的任何控制器中都有 ObjectManager,所以你会这样做:

    $items = $this-getObjectManager()->getRepository(Item::class)->findAllVisible($params)
    

    要使用分页器,您应该使用QueryBuilder,带有表达式,like here

    作为一个实际的例子,我的一个 indexAction:

    use Doctrine\ORM\QueryBuilder;
    use Doctrine\ORM\Tools\Pagination\Paginator as OrmPaginator;
    use DoctrineORMModule\Paginator\Adapter\DoctrinePaginator as OrmAdapter;
    use Zend\Paginator\Paginator;
    
    public function indexAction()
    {
        // get current page, defaults to 1
        $page           = $this->params()->fromQuery('page', 1);
        // get current page size, defaults to 10
        $pageSize       = $this->params()->fromQuery('pageSize', 10);
        // get ordering, defaults to 'createdAt'
        $orderBy        = $this->params()->fromQuery('orderBy', 'createdAt');
        // get order direction, defaults to Criteria::DESC
        $orderDirection = ($this->params()->fromQuery('orderDirection') === Criteria::ASC)
            ? Criteria::ASC
            : Criteria::DESC;
    
        $criteria = new Criteria();
        $criteria->setFirstResult($page * $pageSize);
        $criteria->setMaxResults($pageSize);
        $criteria->orderBy([$orderBy => $orderDirection]);
    
        /** @var QueryBuilder $queryBuilder */
        $queryBuilder = $this->getObjectManager()->createQueryBuilder();
        $queryBuilder->select('a')->from(Article::class, 'a');
        $queryBuilder->addCriteria($criteria);
    
        $paginator = new Paginator(new OrmAdapter(new OrmPaginator($queryBuilder)));
        $paginator->setCurrentPageNumber($page);     // set current page
        $paginator->setItemCountPerPage($pageSize);  // set item count per page
    
        return [
            'paginator' => $paginator,
            'queryParams' => $this->params()->fromQuery(), // pass these for your pagination uri's
        ];
    }
    

    注意:在上面$this 是 Zend Framework 控制器的一个实例,其中 -&gt;fromQuery 如果是 URI,则从 Query 位返回(如果存在)给定键,否则返回第二个参数默认值(或 @ 987654332@)。你应该做类似的事情。

    【讨论】:

      猜你喜欢
      • 2020-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-23
      • 1970-01-01
      • 2020-10-16
      • 1970-01-01
      • 2018-09-15
      相关资源
      最近更新 更多