1

Is it possible to use a UniqueEntity annotation on a foreign object property ?

For example I have two class :

class A {
    private $id;
    private $num;

    /**
     * @ORM\ManyToOne(targetEntity="B" ....)
     */
    private $b;

    ...
}


class B {
    private $id;
    private $sku;

    ...
}

I need to prevent users entering a A.num already used for B.sku. I would like doing something like that :

/**
 * @UniqueEntity(fields={"num","b.sku"})
 */
class A {
    ...
}
Bapt
  • 173
  • 8
  • I don't think it's possible (like this). If anything, I would expect that you have to make the sku the joinColumn and then mark the relationship on the property b as unique. Even then I don't think it will be quite that easy because if you have multiple entries with the same sku in b and you reference objects via sku I'm not sure Doctrine can safely identify which row to use for this reference. – dbrumann Feb 07 '18 at 10:06
  • Do you want to enforce data integrity on a database level or do you just want to check if your `A` entity is valid by using the [validator](https://symfony.com/doc/current/validation.html) component of Symfony? – Alan T. Feb 07 '18 at 12:38
  • @AlanT. I Just want to check my A Entity is valid before flushing. – Bapt Feb 08 '18 at 10:22

1 Answers1

0

For such a case, you could try to enforce data integrity on a database level but the implementation of such a constraint would mainly depend on your RDBMS (an exemple here). As far as I know, Doctrine only allows to add unique and check constraints so you will need to trust your application code to validate your entity properly before it is persisted here.

To do so, instead of UniqueEntity, you could use the Callback or the Expression constraint to create your custom validation rule. Since your rule is not so complex, it would be less verbose to use @Assert\Expression. Something like this would produce the desired result:

@Assert\Expression(
    "this.getB() == null or this.getB().getSku() != this.getNum()",
    message="The chosen number should not be the same as the associated number B.sku"
)

As explained in the documentation, you can attach this annotation to your class directly or you can map it to a specific field. In your example, I guess attaching it to num would be best.

Alan T.
  • 1,382
  • 1
  • 7
  • 14