你好沃尔特,
编辑:第一种方法在 symfony 3 中被弃用,因为评论中提到的线程操作。检查为 symfony 3 制作的第二种方法。
Symfony 2.3+,Symfony < 3
在这种情况下,由于 symfony 和大多数其他包都使用参数来定义服务类,我在这种情况下所做的就是扩展该服务。查看下面的示例,有关扩展服务的更多信息,请查看此链接
http://symfony.com/doc/current/bundles/override.html
首先,您需要为需要预验证的实体添加一些标记。我通常将接口用于类似这样的东西
namespace Your\Name\Space;
interface PreValidateInterface
{
public function preValidate();
}
在此之后,您扩展验证器服务
<?php
namespace Your\Name\Space;
use Symfony\Component\Validator\Validator;
class MyValidator extends Validator //feel free to rename this to your own liking
{
/**
* @inheritdoc
*/
public function validate($value, $groups = null, $traverse = false, $deep = false)
{
if (is_object($value) && $value instanceof PreValidateInterface) {
$value->preValidate();
}
return parent::validate($value, $groups, $traverse, $deep);
}
}
最后一步,您需要将类值参数添加到 config.yml 中的“参数”配置块中,如下所示:
parameters:
validator.class: Your\Name\Space\MyValidator
这是基本思想。现在,您可以将最终匹配这个想法与您想要实现的任何目标混合在一起。例如,不是在实体上调用方法(我通常喜欢将业务逻辑保留在我的实体之外),您可以查找接口,如果存在,您可以启动带有该实体的 pre.validate 事件,并且使用监听器来完成这项工作。之后,您可以保留 parent::validate 的结果并启动 post.validate 事件。你知道我要去哪里。你现在基本上可以在 validate 方法中做任何你喜欢的事情。
PS:上面的例子是简单的方法。如果你想走事件路由,服务扩展会更难,因为你需要将调度程序注入其中。检查我在开始时提供的链接以查看扩展服务的另一种方式,如果您需要帮助,请告诉我。
对于 Symfony 3.0 -> 3.1
在这种情况下,他们设法使扩展变得更加困难和肮脏
步骤1:
创建您自己的验证器,如下所示:
<?php
namespace Your\Name\Space;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Exception;
use Symfony\Component\Validator\MetadataInterface;
use Symfony\Component\Validator\Validator\ContextualValidatorInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class myValidator implements ValidatorInterface
{
/**
* @var ValidatorInterface
*/
protected $validator;
/**
* @param ValidatorInterface $validator
*/
public function __construct(ValidatorInterface $validator)
{
$this->validator = $validator;
}
/**
* Returns the metadata for the given value.
*
* @param mixed $value Some value
*
* @return MetadataInterface The metadata for the value
*
* @throws Exception\NoSuchMetadataException If no metadata exists for the given value
*/
public function getMetadataFor($value)
{
return $this->validator->getMetadataFor($value);
}
/**
* Returns whether the class is able to return metadata for the given value.
*
* @param mixed $value Some value
*
* @return bool Whether metadata can be returned for that value
*/
public function hasMetadataFor($value)
{
return $this->validator->hasMetadataFor($value);
}
/**
* Validates a value against a constraint or a list of constraints.
*
* If no constraint is passed, the constraint
* {@link \Symfony\Component\Validator\Constraints\Valid} is assumed.
*
* @param mixed $value The value to validate
* @param Constraint|Constraint[] $constraints The constraint(s) to validate
* against
* @param array|null $groups The validation groups to
* validate. If none is given,
* "Default" is assumed
*
* @return ConstraintViolationListInterface A list of constraint violations.
* If the list is empty, validation
* succeeded
*/
public function validate($value, $constraints = null, $groups = null)
{
//the code you are doing all of this for
if (is_object($value) && $value instanceof PreValidateInterface) {
$value->preValidate();
}
//End of code
return $this->validator->validate($value, $constraints, $groups);
}
/**
* Validates a property of an object against the constraints specified
* for this property.
*
* @param object $object The object
* @param string $propertyName The name of the validated property
* @param array|null $groups The validation groups to validate. If
* none is given, "Default" is assumed
*
* @return ConstraintViolationListInterface A list of constraint violations.
* If the list is empty, validation
* succeeded
*/
public function validateProperty($object, $propertyName, $groups = null)
{
$this->validator->validateProperty($object, $propertyName, $groups);
}
/**
* Validates a value against the constraints specified for an object's
* property.
*
* @param object|string $objectOrClass The object or its class name
* @param string $propertyName The name of the property
* @param mixed $value The value to validate against the
* property's constraints
* @param array|null $groups The validation groups to validate. If
* none is given, "Default" is assumed
*
* @return ConstraintViolationListInterface A list of constraint violations.
* If the list is empty, validation
* succeeded
*/
public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null)
{
$this->validator->validatePropertyValue($objectOrClass, $propertyName, $value, $groups);
}
/**
* Starts a new validation context and returns a validator for that context.
*
* The returned validator collects all violations generated within its
* context. You can access these violations with the
* {@link ContextualValidatorInterface::getViolations()} method.
*
* @return ContextualValidatorInterface The validator for the new context
*/
public function startContext()
{
$this->validator->startContext();
}
/**
* Returns a validator in the given execution context.
*
* The returned validator adds all generated violations to the given
* context.
*
* @param ExecutionContextInterface $context The execution context
*
* @return ContextualValidatorInterface The validator for that context
*/
public function inContext(ExecutionContextInterface $context)
{
$this->validator->inContext($context);
}
}
第2步:
像这样扩展 Symfony\Component\Validator\ValidatorBuilder :
namespace Your\Name\Space;
use Symfony\Component\Validator\ValidatorBuilder;
class myValidatorBuilder extends ValidatorBuilder
{
public function getValidator()
{
$validator = parent::getValidator();
return new MyValidator($validator);
}
}
你需要覆盖 Symfony\Component\Validator\Validation。这是丑陋/肮脏的部分,因为这个类是最终的,所以你不能扩展它,并且没有要实现的接口,所以你必须注意未来的 symfony 版本,以防向后兼容性被破坏。它是这样的:
namespace Your\Name\Space;
final class MyValidation
{
/**
* The Validator API provided by Symfony 2.4 and older.
*
* @deprecated use API_VERSION_2_5_BC instead.
*/
const API_VERSION_2_4 = 1;
/**
* The Validator API provided by Symfony 2.5 and newer.
*/
const API_VERSION_2_5 = 2;
/**
* The Validator API provided by Symfony 2.5 and newer with a backwards
* compatibility layer for 2.4 and older.
*/
const API_VERSION_2_5_BC = 3;
/**
* Creates a new validator.
*
* If you want to configure the validator, use
* {@link createValidatorBuilder()} instead.
*
* @return ValidatorInterface The new validator.
*/
public static function createValidator()
{
return self::createValidatorBuilder()->getValidator();
}
/**
* Creates a configurable builder for validator objects.
*
* @return ValidatorBuilderInterface The new builder.
*/
public static function createValidatorBuilder()
{
return new MyValidatorBuilder();
}
/**
* This class cannot be instantiated.
*/
private function __construct()
{
}
}
最后一步覆盖 config.yml 中的参数 validator.builder.factory.class:
参数:validator.builder.factory.class:Your\Name\Space\MyValidation
这是我能找到的侵入性最小的方法。不是那么干净,当您将 symfony 升级到未来版本时,它可能需要一些维护。
希望这会有所帮助,并且编码愉快
亚历山德鲁·科索伊