我找不到类似的帖子,所以我会尝试一下。我目前正在开发一个 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”子句?能不能让它更有活力,或者就这样就可以了?
尝试通过单击前端对列进行排序时会出现此问题;它只影响当前页面的数据。目标是按所有条目对其进行排序。
是的,这是合乎逻辑的,因为每次您向 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 注入预防