diff --git a/src/Entity/StorageLocation.php b/src/Entity/StorageLocation.php index ac70127c8..97929329b 100644 --- a/src/Entity/StorageLocation.php +++ b/src/Entity/StorageLocation.php @@ -31,7 +31,7 @@ use Symfony\Component\Validator\Constraints as Assert; * @AuditLog\Auditable * @AppAssert\StorageLocation() */ -class StorageLocation +class StorageLocation implements \Stringable { use Traits\TruncateStrings; diff --git a/src/Validator/Constraints/StorageLocationValidator.php b/src/Validator/Constraints/StorageLocationValidator.php index 960b27cd7..df4596522 100644 --- a/src/Validator/Constraints/StorageLocationValidator.php +++ b/src/Validator/Constraints/StorageLocationValidator.php @@ -4,6 +4,7 @@ namespace App\Validator\Constraints; use App\Entity; use App\Radio\Configuration; +use Doctrine\ORM\EntityManagerInterface; use Exception; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -11,11 +12,10 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException; class StorageLocationValidator extends ConstraintValidator { - protected Configuration $configuration; - - public function __construct(Configuration $configuration) - { - $this->configuration = $configuration; + public function __construct( + protected Configuration $configuration, + protected EntityManagerInterface $em, + ) { } public function validate($storageLocation, Constraint $constraint): void @@ -28,14 +28,52 @@ class StorageLocationValidator extends ConstraintValidator throw new UnexpectedTypeException($storageLocation, Entity\StorageLocation::class); } + // Ensure this storage location validates. try { $storageLocation->validate(); } catch (Exception $e) { - $message = __('This storage location could not be validated: %s', '{{ error }}'); + $message = __( + 'Storage location %s could not be validated: %s', + '{{ storageLocation }}', + '{{ error }}' + ); $this->context->buildViolation($message) + ->setParameter('{{ storageLocation }}', (string)$storageLocation) ->setParameter('{{ error }}', $e->getMessage()) ->addViolation(); } + + // Ensure it's not a duplicate of other storage locations. + $qb = $this->em->createQueryBuilder() + ->select('sl') + ->from(Entity\StorageLocation::class, 'sl') + ->where('sl.type = :type') + ->setParameter('type', $storageLocation->getType()) + ->andWhere('sl.adapter = :adapter') + ->setParameter('adapter', $storageLocation->getAdapter()); + + if (null !== $storageLocation->getId()) { + $qb->andWhere('sl.id != :id') + ->setParameter('id', $storageLocation->getId()); + } + + $storageLocationUri = $storageLocation->getUri(); + + /** @var Entity\StorageLocation $row */ + foreach ($qb->getQuery()->toIterable() as $row) { + if ($row->getUri() === $storageLocationUri) { + $message = __( + 'Storage location %s already exists.', + '{{ storageLocation }}', + ); + + $this->context->buildViolation($message) + ->setParameter('{{ storageLocation }}', (string)$storageLocation) + ->addViolation(); + + break; + } + } } }