Symfony 常量以防止在重叠时间范围内重复

Joy*_*abu 4 mysql symfony doctrine-orm

如何使用 Doctrine ORM 在 Symfony 中强制重叠日期范围内的值的唯一性。

我有以下实体

<?php
/**
 * @ORM\Entity
 * @ORM\Table("tax_component")
 */

class TaxComponent
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(name="tax_component_id", type="integer")
     */
    private ?int $id;

    /**
     * @ORM\Column(name="tax_component_name", type="string", length=20)
     */
    private string $name;

    /**
     * @ORM\Column(name="tax_component_rate", type="integer")
     * @Assert\GreaterThanOrEqual(0)
     */
    private int $rate;

    /**
     * @ORM\Column(name="tax_component_applicable_from", type="datetime_immutable")
     */
    private DateTimeInterface $applicableFrom;

    /**
     * @ORM\Column(name="tax_component_applicable_to", type="datetime_immutable")
     */

    public function __construct(string $name, int $rate, ?DateTimeImmutable $applicableFrom = null, ?DateTimeImmutable $applicableTo = null)
    {
        ...
    }

}

Run Code Online (Sandbox Code Playgroud)

我想要$name的独特withing重叠的时间框架$applicableFrom和$applicableTo。例如,

$repository->save(
    new TaxComponent('inter-state', 1800, new DateTime('2018-04-01:00:00:00'), new DateTime('2019-03-31T23:59:59'))
);

// The following should be allowed since there is no overlap between the two time ranges using the name 'inter-state'
$repository->save(
    new TaxComponent('inter-state', 1200, new DateTime('2019-04-01:00:00:00'), new DateTime('2020-03-31T23:59:59'))
);

// The following should fail since 'inter-state' is ambiguous during the period 2019-09-01:00:00:00 to 2020-03-31T23:59:59
$repository->save(
    new TaxComponent('inter-state', 1800, new DateTime('2019-09-01:00:00:00'), new DateTime('2020-09-31T23:59:59'))
);
Run Code Online (Sandbox Code Playgroud)

是否有约束来强制执行这是 Symfony?

我正在计划TaxComponentRepository::save在调用之前从 内部检查现有实体$this->entityManager->persist。有更好的解决方案吗?

Dyl*_*Kas 5

更简洁的方法是创建您自己的自定义断言。

从创建约束开始:

<?php

namespace App\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class TaxComponentConstraint extends Constraint
{
    public $message = 'Another tax component overlap this one: {{ taxComponent}}';

    public function getTargets()
    {
        return self::CLASS_CONSTRAINT;
    }

    public function validatedBy()
    {
        return 'App\Validator\Constraints\TaxComponentValidator';
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您必须创建一个验证器来检查是否存在与两个税收组成部分的重叠。

<?php

namespace App\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;

class TaxComponentValidator extends ConstraintValidator
{
    public function validate($taxComponentObject, Constraint $constraint)
    {
    //Check however you want if the tax component can be created (So no overlap between two existing TaxComponent)
    if($overlappingTaxComponent){
        $this->context->buildViolation($constraint->message)
                        ->setParameter('{{ taxComponent }}', $overlappingTaxComponent->__toString())
                        ->addViolation();
    }

    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,$overlappingTaxComponent是一个 TaxComponent ,因为您的约束而阻止我们制作一个。

如果约束正确完成,您现在可以在实体中轻松使用它,以便在提交表单时自动检查:

<?php

//...
use App\Validator\Constraints as CustomAssert;

/**
 * @ORM\Entity
 * @ORM\Table("tax_component")
 * @CustomAssert\TaxComponentConstraint
 */
class TaxComponent
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(name="tax_component_id", type="integer")
     */
    private ?int $id;

    /**
     * @ORM\Column(name="tax_component_name", type="string", length=20)
     */
    private string $name;
Run Code Online (Sandbox Code Playgroud)

  • 这应该是类约束而不是属性约束,因此它可以访问验证中需要考虑的其他类成员。 (2认同)
  • 是的,在类级别会更好,因为我们正在研究三个属性来防止实体创建 (2认同)