/** * {@inheritdoc} */ protected function createChoiceLoader($group = false) { $objects = $this->objects; $this->objectLoader->expects($this->any())->method('getEntities')->will($this->returnCallback(function () use($objects) { $values = array(); foreach ($objects as $object) { $values[$object->getLabel()] = $object; } return $values; })); $this->objectLoader->expects($this->any())->method('getEntitiesByIds')->will($this->returnCallback(function ($idField, $values) use($objects) { $entities = array(); foreach ($values as $id) { if (isset($objects[$id]) && is_string($idField)) { $entities[$id] = $objects[$id]; } } return $entities; })); $this->idReader->expects($this->any())->method('getIdField')->will($this->returnValue('id')); $this->idReader->expects($this->any())->method('isSingleId')->will($this->returnValue(true)); $this->idReader->expects($this->any())->method('getIdValue')->will($this->returnCallback(function ($value) use($objects) { foreach ($objects as $i => $object) { if ($object === $value) { return $i; } } throw new RuntimeException('MOCK_EXCEPTION'); })); return new DynamicDoctrineChoiceLoader($this->objectLoader, $this->idReader, 'label'); }
/** * {@inheritdoc} */ public function loadChoicesForValues(array $values, $value = null) { // Performance optimization // Also prevents the generation of "WHERE id IN ()" queries through the // object loader. At least with MySQL and on the development machine // this was tested on, no exception was thrown for such invalid // statements, consequently no test fails when this code is removed. // https://github.com/symfony/symfony/pull/8981#issuecomment-24230557 if (empty($values)) { return array(); } // Optimize performance in case we have an object loader and // a single-field identifier $optimize = null === $value || is_array($value) && $this->idReader === $value[0]; if ($optimize && !$this->choiceList && $this->objectLoader && $this->idReader->isSingleId()) { $unorderedObjects = $this->objectLoader->getEntitiesByIds($this->idReader->getIdField(), $values); $objectsById = array(); $objects = array(); // Maintain order and indices from the given $values // An alternative approach to the following loop is to add the // "INDEX BY" clause to the Doctrine query in the loader, // but I'm not sure whether that's doable in a generic fashion. foreach ($unorderedObjects as $object) { $objectsById[(string) $this->idReader->getIdValue($object)] = $object; } foreach ($values as $i => $id) { if (isset($objectsById[$id])) { $objects[$i] = $objectsById[$id]; } } return $objects; } return $this->loadChoiceList($value)->getChoicesForValues($values); }
public function testLoadChoicesForValuesLoadsOnlyChoicesIfValueIsIdReader() { $loader = new DoctrineChoiceLoader($this->om, $this->class, $this->idReader, $this->objectLoader); $choices = array($this->obj2, $this->obj3); $value = array($this->idReader, 'getIdValue'); $this->idReader->expects($this->any())->method('isSingleId')->willReturn(true); $this->idReader->expects($this->any())->method('getIdField')->willReturn('idField'); $this->repository->expects($this->never())->method('findAll'); $this->objectLoader->expects($this->once())->method('getEntitiesByIds')->with('idField', array('2'))->willReturn($choices); $this->idReader->expects($this->any())->method('getIdValue')->willReturnMap(array(array($this->obj2, '2'), array($this->obj3, '3'))); $this->assertSame(array($this->obj2), $loader->loadChoicesForValues(array('2'), $value)); }
/** * 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); $idValue = current($this->classMetadata->getIdentifierValues($object)); if ($this->associationIdReader) { $idValue = $this->associationIdReader->getIdValue($idValue); } return $idValue; }
/** * {@inheritdoc} */ public function loadValuesForChoices(array $choices, $value = null) { // Performance optimization if (empty($choices)) { return array(); } $values = array(); foreach ($choices as $i => $object) { if (is_object($object)) { try { $values[$i] = (string) $this->idReader->getIdValue($object); } catch (RuntimeException $e) { if (!$this->isAllowAdd()) { throw $e; } } } elseif ($this->isAllowAdd()) { $values[$i] = $object; } } return $values; }