我在项目中使用 Symfony Validator 和 Symfony Service Container ,但不是完整的Symfony Framework。
我编写了一个自定义验证器,它需要一些依赖项作为构造函数参数提供。
Symfony Documentation描述了将验证器配置为服务的方法,我已成功完成。但是,重要的是使用validator.constraint_validator
服务标签,我怀疑它们会粘在一起。
此服务标签似乎特定于使用完整的Symfony框架时 - 当我添加此标记时,Symfony Validator并没有神奇地加载我的自定义验证器(毫不奇怪。)
那么,我如何链接Validator和Service Container组件?或者是否有任何其他策略让Symfony Validator加载带有依赖项的客户验证器?
答案 0 :(得分:1)
你是对的,这个标签(validator.constraint_validator
)由编译器处理来自Symfony/FrameworkBundle
。
如果您不想使用此捆绑包,但想要将DI容器与验证器链接,则应重新实施此过程。
首先,我们需要一个ConstraintValidatorFactoryInterface实例。 Default implementation只查找一个类,其名称由validatedBy()约束方法返回。 Implementation from FrameworkBundle将validatedBy()的结果视为服务标识符/或标记别名,并从容器中获取此服务。我们的实现应该做那样的事情:
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\ConstraintValidatorFactoryInterface;
use Symfony\Component\Validator\Constraint;
class ContainerConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getInstance(Constraint $constraint)
{
// Simplified implementation, just for example:
return $this->container->get($constraint->validatedBy());
}
}
例如,假设我们有一些自定义验证约束和验证器类具有一些依赖性:
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class CustomConstraint extends Constraint
{
public $message = 'Oops!';
public function validatedBy()
{
return 'validator.custom';
}
}
class CustomConstraintValidator extends ConstraintValidator
{
private $dependency;
public function __construct($dependency)
{
$this->dependency = $dependency;
}
public function validate($value, Constraint $constraint)
{
if (rand() % 2 === 0) {
$this->context
->buildViolation($constraint->message)
->addViolation();
}
}
}
接下来,我们将约束验证器注册为具有与相关约束对象的validatedBy()
方法的结果相同的ID的服务。我们通过这个工厂创建与容器相关的验证器服务的实例。所有约束验证器都以相同的方式注册。
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Validator\Validation;
$container = new ContainerBuilder();
$container->register(
'validator.custom',
new CustomConstraintValidator('Some dependency value')
);
$validatorBuilder = Validation::createValidatorBuilder();
$validatorBuilder->setConstraintValidatorFactory(
new ContainerConstraintValidatorFactory($container)
);
$validator = $validatorBuilder->getValidator();
$violations = $validator->validate('test value', [
new CustomConstraint()
]);
它有效,但我建议考虑使用FrameworkBundle
来重新发明轮子。您可以将其配置为仅使用您需要的东西。