我有一个Symfony控制器的通用结构(使用FOSRestBundle)
/**
* @Route\Get("users/{id}", requirements={"userId" = "(\d+)"})
*/
public function getUserAction(User $user)
{
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我要求http://localhost/users/1一切都很好.但如果我要求http://localhost/users/11111111111111111我得到500错误和异常
ERROR: value \"11111111111111111\" is out of range for type integer"
Run Code Online (Sandbox Code Playgroud)
有没有办法在ID传输到数据库之前检查?
作为解决方案,我可以指定id的长度
/**
* @Route\Get("users/{id}", requirements={"userId" = "(\d{,10})"})
*/
Run Code Online (Sandbox Code Playgroud)
但是Symfony会说没有这样的路线,而不是表明id不正确.
By telling Symfony that the getUserAction() argument is a User instance, it will take for granted that the {id} url parameter must be matched to the as primary key, handing it over to the Doctrine ParamConverter to fetch the corresponding User.
There are at least two workarounds.
repository_method configIn the controller function's comment, we can add the @ParamConverter annotation and tell it to use the repository_method option.
这样,Symfony 会将 url 参数传递给实体存储库中的函数,从中我们可以检查 url 参数的完整性。
在 中UserRepository,让我们创建一个通过主键获取实体的函数,首先检查参数的完整性。也就是说,$id不得大于 PHP 可以处理的最大整数(常量PHP_INT_MAX)。
请注意:$id是一个字符串,因此将其与 进行比较是安全的PHP_INT_MAX,因为 PHP 会自动类型转换PHP_INT_MAX为字符串并将其与 进行比较$id。如果它是一个整数,则测试总是会失败(根据设计,所有整数都小于或等于PHP_INT_MAX)。
// ...
use Symfony\Component\Form\Exception\OutOfBoundsException;
class UserRepository extends ...
{
// ...
public function findSafeById($id) {
if ($id > PHP_INT_MAX) {
throw new OutOfBoundsException($id . " is too large to fit in an integer");
}
return $this->find($id);
}
}
Run Code Online (Sandbox Code Playgroud)
这只是一个例子:在抛出异常之前我们可以做任何我们喜欢的事情(例如记录失败的尝试)。
然后,在我们的控制器中,添加注释ParamConverter:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
Run Code Online (Sandbox Code Playgroud)
并修改函数注释添加注释:
@ParamConverter("id", class="App:User", options={"repository_method" = "findSafeById"})
Run Code Online (Sandbox Code Playgroud)
我们的控制器函数应该如下所示:
/**
* @Get("users/{id}")
* @ParamConverter("id", class="App:User", options={"repository_method" = "findSafeById"})
*/
public function getUserAction(User $user) {
// Return a "OK" response with the content you like
}
Run Code Online (Sandbox Code Playgroud)
此技术允许自定义异常,但无法让您控制响应 - 在生产中您仍然会收到 500 错误。
文档:请参阅此处。
这种方式是 Symfony 3 之前唯一可行的方式,并且可以让您对生成的响应进行更细粒度的控制。
让我们像这样改变动作原型:
/**
* @Route\Get("users/{id}", requirements={"id" = "(\d+)"})
*/
public function getUserAction($id)
{
}
Run Code Online (Sandbox Code Playgroud)
现在,在操作中我们将收到请求$id,并且我们将能够检查它是否正常。如果没有,我们会抛出异常和/或返回一些错误响应(我们可以选择 HTTP 状态代码、格式和其他任何内容)。
下面您可以找到此过程的示例实现。
use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\FOSRestController;
use Symfony\Component\Form\Exception\OutOfBoundsException;
use Symfony\Component\HttpFoundation\JsonResponse;
class MyRestController extends FOSRestController {
/**
* @Get("users/{id}", requirements={"id" = "(\d+)"})
*/
public function getUserAction($id) {
try {
if ($id > PHP_INT_MAX) {
throw new OutOfBoundsException($id . " is too large to fit in an integer");
}
// Replace App\Entity\User with your actual Entity alias
$user = $this->getDoctrine()->getRepository('App\Entity\User')->find($id);
if (!$user) {
throw new \Doctrine\ORM\NoResultException("User not found");
}
// Return a "OK" response with the content you like
return new JsonResponse(['key' => 123]);
} catch (Exception $e) {
return new JsonResponse(['message' => $e->getMessage()], 400);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
302 次 |
| 最近记录: |