Symfony 4: Add constraint new UniqueEntity() to x if y is null

Viewed 533

I have an entity class with two properties, country and state. The entries in the database have to be unique. Meaning, if I submit country=Germany and state=BB to the database, it adds the new entry if the same entry does not yet exist.

However, the state property can be null, in that case it is not mapped by doctrine(?) and I can still submit a value for the country. The problem is that I cannot manage to make this entry unique i.e. you should not be able to input the same country multiple times without a unique state. Here is where I struggle.

I have tried various modifications to the entity constraints.

Here is the code that verifies that country & state are an unique entry in the database:

public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addConstraint(new UniqueEntity([
            'fields' => ['country', 'state'],
            'message' => 'State is already used with this country!',
        ]));
    }
2 Answers

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/tutorials/composite-primary-keys.html

Maybe an entity with a composite primary key could work fine for you.

/**
 * @UniqueEntity
 */
class UniqueEntity
{
    /** @Id @Column(type="string") */
    private $country;
    /** @Id @Column(type="string") */
    private $state = 'empty'; // case you have no state and a primary key can't be null

    public function __construct($country, $state)
    {
        $this->country= $country;
        $this->state= $state;
    }

    public function getCountry()
    {
        return $this->country;
    }

    public function getState()
    {
        return $this->state;
    }
}

The only constraint is that you can't have a null value as state if it's a primary key.But then again, you can have a default value like 'no' as a state value, wich will be both an acceptable key and a unique value

It took me a while but this is the custom validator class I wrote to solve my problem. Maybe it will help someone else.

<?php

namespace XXX;

use XXX\Services\CountryAndStateService;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

class CountryAndStateValidator extends ConstraintValidator
{
/**
 * @var countryAndStateService
 */
 private $countryAndStateService;

   /**
    * CountryAndState constructor.
    */
     public function __construct(CountryAndStateService $countryAndStateService)
     {
         $this->countryAndStateService = $countryAndStateService;
     }

     /**
     * Taking country and state; validating whether the same country with state === null does already exist.
     *
     */
     public function validate($value, Constraint $constraint)
     {
        /* Accessing user input of state and country */
        $state = $this->context->getRoot()->getData()->getState();
        $country = $this->context->getRoot()->getData()->getCountry();

        /* Comparing the country user input to the country data in the database */
        $existingCountry = $this->countryAndStateService->getCountryByCountry($country);

        if ($state === null) {
            if ($existingCountry) {
                $this->context->buildViolation($constraint->message)
                    ->addViolation();
            } else {
                return;
            }
         }else {
            return;
        }
    }
}
Related