У меня есть Doctrine сущности Cart
с этими двумя столбцами:
$user
(столбец ManyToOne, ссылающийся на объект пользователя)$status
(поле строки с двумя возможными значениями: pending
и completed
)... и я должен предотвратить две "отложенные" тележки для одного и того же пользователя.
Как я могу это сделать?
UniqueConstraint не является решением, поскольку пользователь должен иметь две или более завершенных тележки, но одну только ожидающую корзину.
С другой стороны, я мог бы реализовать прослушиватель prePersist и проверять дубликаты значений перед вставками, но мне не нравится это решение, потому что я не хочу делать дополнительные запросы к базе данных.
Любое решение?
Наконец, следуя рекомендациям и документации Symfony, я выбрал это решение:
Класс ограничений
<?php
namespace MyBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*
*/
class UniquePendingCart extends Constraint
{
public $message = 'Only one pending cart by user';
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
public function validatedBy()
{
return 'my.validator.unique_pending_cart';
}
}
Служба валидатора Внедрение моего сервиса CartRepository
:
my.validator:
class: AppBundle\Validator\Constraints\UniquePendingCartValidator
arguments:
- @my.cart_repository
tags:
- name: validator.constraint_validator
- alias: my.validator.unique_pending_cart
Класс проверки достоверности
<?php
namespace MyBundle\Validator\Constraints;
use Doctrine\Common\Persistence\ObjectRepository;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Bshop\AppBundle\Model\Interfaces\OrderInterface;
class UniquePendingCartValidator extends ConstraintValidator
{
protected $repository;
public function __construct(ObjectRepository $repository)
{
$this->repository = $repository;
}
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof UniquePendingCart) {
throw new UnexpectedTypeException($constraint,
__NAMESPACE__.'\UniquePendingCart');
}
$isValid = $this->isStatusValid($value);
if (!$isValid) {
$this->context->buildViolation($constraint->message)
->addViolation();
}
}
protected function isStatusValid($cart)
{
// use repository to find another possible pending cart
return true;
}
}
А затем примените ограничение в моем Cart
<?php
use Doctrine\ORM\Mapping as ORM;
use MyBundle\Validator\Constraints as MyAssert;
/**
* @ORM\Entity
* @MyAssert\UniquePendingCart
*/
class Cart {
// ...
}
Теперь я могу проверить корзину $ и проверить, что это действительно...
$cart = // my cart
$validator = $this->get("validator");
$errors = $validator->validate($cart);
if (0 !== count($errors)) {
// ops, exception...
}