/**
  * Returns the values of the identifier fields of an entity.
  *
  * Doctrine must know about this entity, that is, the entity must already
  * be persisted or added to the identity map before. Otherwise an
  * exception is thrown.
  *
  * @param  object $entity The entity for which to get the identifier
  *
  * @return array          The identifier values
  *
  * @throws FormException  If the entity does not exist in Doctrine's identity map
  */
 private function getIdentifierValues($entity)
 {
     if (!$this->em->contains($entity)) {
         throw new FormException('Entities passed to the choice field must be managed');
     }
     $this->em->initializeObject($entity);
     return $this->classMetadata->getIdentifierValues($entity);
 }
 /**
  * Returns the values of the identifier fields of an entity.
  *
  * Doctrine must know about this entity, that is, the entity must already
  * be persisted or added to the identity map before. Otherwise an
  * exception is thrown.
  *
  * @param object $entity The entity for which to get the identifier
  *
  * @return array          The identifier values
  *
  * @throws RuntimeException If the entity does not exist in Doctrine's identity map
  */
 private function getIdentifierValues($entity)
 {
     if (!$this->em->contains($entity)) {
         throw new RuntimeException('Entities passed to the choice field must be managed. Maybe ' . 'persist them in the entity manager?');
     }
     $this->em->initializeObject($entity);
     return $this->classMetadata->getIdentifierValues($entity);
 }
Example #3
0
 /**
  * Returns the ID value for an object.
  *
  * This method assumes that the object has a single-column ID.
  *
  * @param object $object The object.
  *
  * @return mixed The ID value.
  */
 public function getIdValue($object)
 {
     if (!$object) {
         return;
     }
     if (!$this->om->contains($object)) {
         throw new RuntimeException('Entities passed to the choice field must be managed. Maybe ' . 'persist them in the entity manager?');
     }
     $this->om->initializeObject($object);
     return current($this->classMetadata->getIdentifierValues($object));
 }
 /**
  * @param object     $entity
  * @param Constraint $constraint
  *
  * @throws UnexpectedTypeException
  * @throws ConstraintDefinitionException
  */
 public function validate($entity, Constraint $constraint)
 {
     /** @var Unique $constraint */
     if (!$constraint instanceof Unique) {
         throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\\Unique');
     }
     if (!is_array($constraint->fields) && !is_string($constraint->fields)) {
         throw new UnexpectedTypeException($constraint->fields, 'array');
     }
     if (null !== $constraint->errorPath && !is_string($constraint->errorPath)) {
         throw new UnexpectedTypeException($constraint->errorPath, 'string or null');
     }
     $fields = (array) $constraint->fields;
     if (0 === count($fields)) {
         throw new ConstraintDefinitionException('At least one field has to be specified.');
     }
     $class = $this->em->getClassMetadata($constraint->className);
     /* @var $class \Doctrine\Common\Persistence\Mapping\ClassMetadata */
     $criteria = [];
     foreach ($fields as $fieldName) {
         if (!$class->hasField($fieldName) && !$class->hasAssociation($fieldName)) {
             throw new ConstraintDefinitionException(sprintf("The field '%s' is not mapped by Doctrine, so it cannot be validated for uniqueness.", $fieldName));
         }
         $criteria[$fieldName] = $class->reflFields[$fieldName]->getValue($entity);
         if ($constraint->ignoreNull && null === $criteria[$fieldName]) {
             return;
         }
         if (null !== $criteria[$fieldName] && $class->hasAssociation($fieldName)) {
             /* Ensure the Proxy is initialized before using reflection to
              * read its identifiers. This is necessary because the wrapped
              * getter methods in the Proxy are being bypassed.
              */
             $this->em->initializeObject($criteria[$fieldName]);
             $relatedClass = $this->em->getClassMetadata($class->getAssociationTargetClass($fieldName));
             $relatedId = $relatedClass->getIdentifierValues($criteria[$fieldName]);
             if (count($relatedId) > 1) {
                 throw new ConstraintDefinitionException('Associated entities are not allowed to have more than one identifier field to be ' . 'part of a unique constraint in: ' . $class->getName() . '#' . $fieldName);
             }
             $criteria[$fieldName] = array_pop($relatedId);
         }
     }
     $repository = $this->em->getRepository($constraint->className);
     $result = $repository->{$constraint->repositoryMethod}($criteria);
     /* If the result is a MongoCursor, it must be advanced to the first
      * element. Rewinding should have no ill effect if $result is another
      * iterator implementation.
      */
     if ($result instanceof \Iterator) {
         $result->rewind();
     } elseif (is_array($result)) {
         reset($result);
     }
     /* If no entity matched the query criteria or a single entity matched,
      * which is the same as the entity being validated, the criteria is
      * unique.
      */
     if (0 === count($result)) {
         return;
     }
     if (1 === count($result)) {
         $props = PropertyAccess::createPropertyAccessor();
         if ($props->isReadable($entity, $constraint->idField)) {
             $current = is_array($result) ? current($result) : $result;
             if ($props->getValue($entity, $constraint->idField) === $props->getValue($current, $constraint->idField)) {
                 return;
             }
         }
     }
     $errorPath = null !== $constraint->errorPath ? $constraint->errorPath : $fields[0];
     $invalidValue = isset($criteria[$errorPath]) ? $criteria[$errorPath] : $criteria[$fields[0]];
     $this->buildViolation($constraint->message)->atPath($errorPath)->setInvalidValue($invalidValue)->addViolation();
 }