Skip to content

Commit

Permalink
[DoctrineBridge] Optimize fetching of entities to use WHERE IN and fi…
Browse files Browse the repository at this point in the history
…x other inefficencies.
  • Loading branch information
beberlei authored and stof committed Dec 19, 2011
1 parent 517eebc commit b919d92
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 41 deletions.
59 changes: 32 additions & 27 deletions src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php
Expand Up @@ -107,6 +107,9 @@ public function __construct(ObjectManager $manager, $class, $property = null, En
// displaying entities as strings
if ($property) {
$this->propertyPath = new PropertyPath($property);
} else if (!method_exists($this->class, '__toString')) {
// Otherwise expect a __toString() method in the entity
throw new FormException('Entities passed to the choice field must have a "__toString()" method defined (or you can also override the "property" option).');
}

if (!is_array($choices) && !$choices instanceof \Closure && !is_null($choices)) {
Expand Down Expand Up @@ -202,11 +205,6 @@ private function loadEntities($entities, $group = null)
// If the property option was given, use it
$value = $this->propertyPath->getValue($entity);
} else {
// Otherwise expect a __toString() method in the entity
if (!method_exists($entity, '__toString')) {
throw new FormException('Entities passed to the choice field must have a "__toString()" method defined (or you can also override the "property" option).');
}

$value = (string) $entity;
}

Expand Down Expand Up @@ -261,7 +259,7 @@ public function getEntities()
}

/**
* Returns the entity for the given key.
* Returns the entities for the given keys.
*
* If the underlying entities have composite identifiers, the choices
* are initialized. The key is expected to be the index in the choices
Expand All @@ -270,35 +268,42 @@ public function getEntities()
* If they have single identifiers, they are either fetched from the
* internal entity cache (if filled) or loaded from the database.
*
* @param string $key The choice key (for entities with composite
* identifiers) or entity ID (for entities with single
* identifiers)
*
* @return object The matching entity
* @param array $keys The choice key (for entities with composite
* identifiers) or entity ID (for entities with single
* identifiers)
* @return object[] The matching entity
*/
public function getEntity($key)
public function getEntitiesByKeys($keys)
{
if (!$this->loaded) {
$this->load();
}

try {
if (count($this->identifier) > 1) {
// $key is a collection index
$entities = $this->getEntities();

return isset($entities[$key]) ? $entities[$key] : null;
} elseif ($this->entities) {
return isset($this->entities[$key]) ? $this->entities[$key] : null;
} else if ($entityLoader = $this->entityLoader) {
$entities = $entityLoader->getEntitiesByKeys($this->identifier, array($key));
return (isset($entities[0])) ? $entities[0] : false;
}
$found = array();

return $this->em->find($this->class, $key);
} catch (NoResultException $e) {
return null;
if (count($this->identifier) > 1) {
// $key is a collection index
$entities = $this->getEntities();
foreach ($keys as $key) {
if (isset($entities[$key])) {
$found[] = $entities[$key];
}
}
} else if ($this->entities) {
foreach ($keys as $key) {
if (isset($this->entities[$key])) {
$found[] = $this->entities[$key];
}
}
} else if ($entityLoader = $this->entityLoader) {
$found = $entityLoader->getEntitiesByKeys($this->identifier, $keys);
} else if ($keys) {
$identifier = current($this->identifier);
$found = $this->em->getRepository($this->class)
->findBy(array($identifier => $keys));
}

return $found;
}

/**
Expand Down
Expand Up @@ -84,19 +84,13 @@ public function reverseTransform($keys)
throw new UnexpectedTypeException($keys, 'array');
}

$notFound = array();

// optimize this into a SELECT WHERE IN query
foreach ($keys as $key) {
if ($entity = $this->choiceList->getEntity($key)) {
$collection->add($entity);
} else {
$notFound[] = $key;
}
$entities = $this->choiceList->getEntitiesByKeys($keys);
if (count($keys) != count($entities)) {
throw new TransformationFailedException('Not all entities matching the keys were found.');
}

if (count($notFound) > 0) {
throw new TransformationFailedException(sprintf('The entities with keys "%s" could not be found', implode('", "', $notFound)));
foreach ($entities as $entity) {
$collection->add($entity);
}

return $collection;
Expand Down
Expand Up @@ -74,10 +74,10 @@ public function reverseTransform($key)
throw new UnexpectedTypeException($key, 'numeric');
}

if (!($entity = $this->choiceList->getEntity($key))) {
if (!($entities = $this->choiceList->getEntitiesByKeys(array($key)))) {
throw new TransformationFailedException(sprintf('The entity with key "%s" could not be found', $key));
}

return $entity;
return $entities[0];
}
}
Expand Up @@ -19,4 +19,9 @@ public function __construct($id, $name) {
$this->id = $id;
$this->name = $name;
}

public function __toString()
{
return (string)$this->id;
}
}

0 comments on commit b919d92

Please sign in to comment.