ConstraintViolationListInterface 到 Symfony 中的异常
ConstraintViolationListInterface to Exception in Symfony
我需要将 ConstraintViolationListInterface
类型的对象转换为单个异常以进行进一步记录,其中消息是来自列表中每个约束违规的消息的串联,当验证失败时。
显然,我无法在使用验证的每个包中重复 foreach 循环来实现此目的,因此我正在考虑再创建一个包,以提供接受 ConstraintViolationListInterface
并返回单个异常的简单服务。 Symfony 中是否有针对此的标准解决方案?我需要写这个服务似乎很奇怪,这个问题对我来说似乎很常见。
也许你可以像这样创建一个 ConstraintViolationsEvent :
namespace AppBundle\Event;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\Validator\ConstraintViolationListInterface;
/**
* The order.placed event is dispatched each time an order is created
* in the system.
*/
class ConstraintViolationsEvent extends Event
{
const VIOLATIONS_DETECTED = 'constraint_violations.detected';
protected $constraintViolationList;
public function __construct(ConstraintViolationListInterface $constraintViolationList)
{
$this->constraintViolationList = $constraintViolationList;
}
public function getConstraintViolationList()
{
return $this->constraintViolationList;
}
}
然后您可以为此事件创建一个侦听器,并在该侦听器中,根据发现的所有违规情况创建您的异常。每次你会发现违规行为时,你只需像这样在你的控制器中发送你的事件:
class MyController extends Controller
{
public function myFormAction(Request $request)
{
/** handle the request, get the form data, validate the form...etc. **/
$event = new ConstraintViolationsEvent($constraintViolationList);
$dispatcher->dispatch(ConstraintViolationsEvent::VIOLATIONS_DETECTED, $event);
}
}
事实上,您可以在服务中管理异常的创建并在侦听器中调用服务。由你决定。
我也很惊讶 symfony 对此没有任何帮助,这就是我创建自定义异常的原因:
class ValidationException extends \Exception
{
private $violations;
public function __construct(array $violations)
{
$this->violations = $violations;
parent::__construct('Validation failed.');
}
public function getMessages()
{
$messages = [];
foreach ($this->violations as $paramName => $violationList) {
foreach ($violationList as $violation) {
$messages[$paramName][] = $violation->getMessage();
}
}
return $messages;
}
public function getJoinedMessages()
{
$messages = [];
foreach ($this->violations as $paramName => $violationList) {
foreach ($violationList as $violation) {
$messages[$paramName][] = $violation->getMessage();
}
$messages[$paramName] = implode(' ', $messages[$paramName]);
}
return $messages;
}
}
所有代码可用 here。
我用下一种方式使用这个异常:
try {
$errors = $validator->validate(...);
if (0 !== count($errors)) {
throw new ValidationException($errors);
}
} catch (ValidationException $e) {
// Here you can obtain your validation errors.
var_dump($e->getMessages());
}
这个解决方案对我来说很好用:
protected function violationsToArray(ConstraintViolationListInterface $violations)
{
$messages = [];
foreach ($violations as $constraint) {
$prop = $constraint->getPropertyPath();
$messages[$prop][] = $constraint->getMessage();
}
return $messages;
}
请注意,使用 $violations 数组键作为 属性 名称将不起作用:
$messages = [];
foreach ($violations as $prop => $constraint) {
// $prop will not contain any value and this will not work as expected
$messages[$prop][] = $constraint->getMessage();
}
我不知道以前是不是这样,但是,使用 Symfony 5.4(可能还有一段时间),您可以在返回的 ConstraintViolationList
对象上使用字符串转换:
/** @var ConstraintViolationList $violations */
$violations = $this->validator->validate($object);
if ($violations->count()) {
throw new \Exception('Validation failed: '.$violations);
}
在这种情况下,当 $violations
与前一个字符串连接时会自动完成转换。当然,你无法控制输出。
我需要将 ConstraintViolationListInterface
类型的对象转换为单个异常以进行进一步记录,其中消息是来自列表中每个约束违规的消息的串联,当验证失败时。
显然,我无法在使用验证的每个包中重复 foreach 循环来实现此目的,因此我正在考虑再创建一个包,以提供接受 ConstraintViolationListInterface
并返回单个异常的简单服务。 Symfony 中是否有针对此的标准解决方案?我需要写这个服务似乎很奇怪,这个问题对我来说似乎很常见。
也许你可以像这样创建一个 ConstraintViolationsEvent :
namespace AppBundle\Event;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\Validator\ConstraintViolationListInterface;
/**
* The order.placed event is dispatched each time an order is created
* in the system.
*/
class ConstraintViolationsEvent extends Event
{
const VIOLATIONS_DETECTED = 'constraint_violations.detected';
protected $constraintViolationList;
public function __construct(ConstraintViolationListInterface $constraintViolationList)
{
$this->constraintViolationList = $constraintViolationList;
}
public function getConstraintViolationList()
{
return $this->constraintViolationList;
}
}
然后您可以为此事件创建一个侦听器,并在该侦听器中,根据发现的所有违规情况创建您的异常。每次你会发现违规行为时,你只需像这样在你的控制器中发送你的事件:
class MyController extends Controller
{
public function myFormAction(Request $request)
{
/** handle the request, get the form data, validate the form...etc. **/
$event = new ConstraintViolationsEvent($constraintViolationList);
$dispatcher->dispatch(ConstraintViolationsEvent::VIOLATIONS_DETECTED, $event);
}
}
事实上,您可以在服务中管理异常的创建并在侦听器中调用服务。由你决定。
我也很惊讶 symfony 对此没有任何帮助,这就是我创建自定义异常的原因:
class ValidationException extends \Exception
{
private $violations;
public function __construct(array $violations)
{
$this->violations = $violations;
parent::__construct('Validation failed.');
}
public function getMessages()
{
$messages = [];
foreach ($this->violations as $paramName => $violationList) {
foreach ($violationList as $violation) {
$messages[$paramName][] = $violation->getMessage();
}
}
return $messages;
}
public function getJoinedMessages()
{
$messages = [];
foreach ($this->violations as $paramName => $violationList) {
foreach ($violationList as $violation) {
$messages[$paramName][] = $violation->getMessage();
}
$messages[$paramName] = implode(' ', $messages[$paramName]);
}
return $messages;
}
}
所有代码可用 here。
我用下一种方式使用这个异常:
try {
$errors = $validator->validate(...);
if (0 !== count($errors)) {
throw new ValidationException($errors);
}
} catch (ValidationException $e) {
// Here you can obtain your validation errors.
var_dump($e->getMessages());
}
这个解决方案对我来说很好用:
protected function violationsToArray(ConstraintViolationListInterface $violations)
{
$messages = [];
foreach ($violations as $constraint) {
$prop = $constraint->getPropertyPath();
$messages[$prop][] = $constraint->getMessage();
}
return $messages;
}
请注意,使用 $violations 数组键作为 属性 名称将不起作用:
$messages = [];
foreach ($violations as $prop => $constraint) {
// $prop will not contain any value and this will not work as expected
$messages[$prop][] = $constraint->getMessage();
}
我不知道以前是不是这样,但是,使用 Symfony 5.4(可能还有一段时间),您可以在返回的 ConstraintViolationList
对象上使用字符串转换:
/** @var ConstraintViolationList $violations */
$violations = $this->validator->validate($object);
if ($violations->count()) {
throw new \Exception('Validation failed: '.$violations);
}
在这种情况下,当 $violations
与前一个字符串连接时会自动完成转换。当然,你无法控制输出。