动态排序和自定义分页

问题描述 投票:0回答:1

我找不到类似的帖子,所以我会尝试一下。我目前正在开发一个 Fullstack Symfony 6 项目(利用 React 和 Symfony 6),主要专注于 API 开发。然而,我遇到了障碍。我已经使用 Doctrine 实现了自定义分页(避免使用其他捆绑包)。当尝试通过单击前端对列进行排序时会出现此问题;它只影响当前页面的数据。目标是按所有条目对其进行排序。在这种情况下,最佳实践是什么?我应该调用另一个 API 来检索所有条目吗?能举个例子吗

存储库(查询生成器)

class CustomerRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Customer::class);
    }

    public function getCustomers(
        string $column,
        string $type,
        int    $page = 1,
        int    $entriesPerPage = 10): array
    {
        $query = $this->createQueryBuilder('d')
            ->orderBy("d.$column", $type)
            ->getQuery();
        $query->setFirstResult($entriesPerPage * ($page - 1))
            ->setMaxResults($entriesPerPage);

        $paginator = new Paginator($query);
        $total = $paginator->count();
        $lastPage = (int)ceil($total / $entriesPerPage);

        return [
            'customers' => $paginator,
            'lastPage' => $lastPage,
            'total' => $total
        ];

    }
}

控制器(API)

    #[Route(path: "/api/customers/{column}/{type}/{page}", name: "customer_get", methods: ["GET"])]
    public function getCustomers(
        CustomerService $customerService,
        string $column,
        string $type,
        int $page=1
    ): JsonResponse
    {
        return $this->json($customerService->getCustomers($column, $type, $page));
    }

响应(调用路由:api/customers/created_at/asc/3)

{
  "customers": [
    {
      "id": 156,
      "name": "Test",
      "created_at": "2024/03/07",
      "updated_at": null
    },
    {
      "id": 157,
      "name": "Test",
      "created_at": "2024/03/07",
      "updated_at": null
    }
  ],
  "lastPage": 3,
  "total": 11
}

反应

    const [sortBy, setSortBy] = useState({field: "name", order: "ASC"});
    const [sortByCreatedAt, setSortByCreatedAt] = useState(null);

    const fetchCustomers = () => {
        const sortField = sortByCreatedAt ? 'created_at' : sortBy.field;
        const sortOrder = sortByCreatedAt ? sortByCreatedAt.order : sortBy.order;


        axios.get(`/api/customers/${sortField}/${sortOrder}/${currentPage}`)
            .then(response => {
                setCustomers(response.data.departments);
                setLastPage(response.data.lastPage)
            })
            .catch(error => {
                console.error(error);
            });
    };

问题2: 是否有可能改进查询生成器中的“Order By”子句?能不能让它更有活力,或者就这样就可以了?

php symfony symfony6
1个回答
0
投票

尝试通过单击前端对列进行排序时会出现此问题;它只影响当前页面的数据。目标是按所有条目对其进行排序。

是的,这是合乎逻辑的,因为每次您向 API 发送相同的

sortField
sortOrder
值时,当用户更改排序顺序或用于排序的列。
相反,每当用户更改排序行为时,您都需要更新这些值,例如,如果我想按电子邮件列降序排序,则 

sortBy

对象应如下所示:

sortBy

我不是 React 开发人员,我不确定这种情况的最佳实践,但从逻辑上讲,您需要在进行客户端排序的函数内调用 
{ field: "email", order: "DESC" }

函数,然后您之后需要调用

setSortBy()
函数,例如:
fetchCustomers()

并禁用任何客户端排序。所以我建议让整个排序过程由服务器来处理,而不是在客户端上做任何事情。

是否有可能改进查询生成器中的“Order By”子句?能不能让它更有活力,或者就这样就可以了?

您可以允许具有不同方向的多个排序条件,例如,您可以允许按名称列按降序排序,按created_at列按升序排序。这样,如果多行在名称列中具有相同的值,它们将按created_at升序排序。

在您的

setSortBy(...); fetchCustomers();

课程中,您可能需要执行以下操作:

CustomerRepository

但是,这段代码是危险的:

class CustomerRepository extends ServiceEntityRepository { public function getCustomers( array $columns, // <--- becomes an array of columns array $types, // <--- becomes an array of sorting directions int $page = 1, int $entriesPerPage = 10): array { $builder = $this->createQueryBuilder('d'); // add sorting criteria to the code for ($i = 0; $i < count($columns); $i++) { $column = $columns[$i]; $type = $types[$i]; $builder->orderBy("d.$column", $type); } $query = $builder->getQuery(); $query->setFirstResult($entriesPerPage * ($page - 1)) ->setMaxResults($entriesPerPage); $paginator = new Paginator($query); $total = $paginator->count(); $lastPage = (int)ceil($total / $entriesPerPage); return [ 'customers' => $paginator, 'lastPage' => $lastPage, 'total' => $total ]; } }

您可能容易受到 SQL 注入攻击,因为您将列名作为变量传递,并且 SQL 查询的这些部分无法使用查询绑定。有关更多信息,请参阅 OWASP 备忘单网站上的
SQL 注入预防

页面。

© www.soinside.com 2019 - 2024. All rights reserved.