diff --git a/src/Symfony/Bundle/DoctrineBundle/Form/ValueTransformer/CollectionToChoiceTransformer.php b/src/Symfony/Bundle/DoctrineBundle/Form/ValueTransformer/CollectionToChoiceTransformer.php deleted file mode 100644 index b019fb13a84e..000000000000 --- a/src/Symfony/Bundle/DoctrineBundle/Form/ValueTransformer/CollectionToChoiceTransformer.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\DoctrineBundle\Form\ValueTransformer; - -use Symfony\Component\Form\ValueTransformer\BaseValueTransformer; -use Symfony\Component\Form\ValueTransformer\TransformationFailedException; - -/** - * Transforms a Collection into a Choice field used for Multiple Select fields or checkbox groups. - * - * @author Benjamin Eberlei - */ -class CollectionToChoiceTransformer extends BaseValueTransformer -{ - protected function configure() - { - $this->addRequiredOption('em'); - $this->addRequiredOption('className'); - - parent::configure(); - } - - /** - * @param array $ids - * @param Collection $collection - */ - public function reverseTransform($ids, $collection) - { - if (count($ids) == 0) { - // don't check for collection count, a straight clear doesnt initialize the collection - $collection->clear(); - return $collection; - } - - $em = $this->getOption('em'); - $metadata = $em->getClassMetadata($this->getOption('className')); - $reflField = $metadata->getReflectionProperty($metadata->identifier[0]); - - foreach ($collection AS $object) { - $key = array_search($reflField->getValue($object), $ids); - if (false === $key) { - $collection->removeElement($object); - } else { - unset($ids[$key]); - } - } - - // @todo: This can be greatly optimized into a single SELECT .. WHERE id IN () query. - foreach ($ids AS $id) { - $entity = $em->find($this->getOption('className'), $id); - if (!$entity) { - throw new TransformationFailedException("Selected entity of type '" . $this->getOption('className') . "' by id '" . $id . "' which is not present in the database."); - } - $collection->add($entity); - } - - return $collection; - } - - /** - * @param Collection $value - */ - public function transform($value) - { - if (null === $value) { - return array(); - } - - $metadata = $this->getOption('em')->getClassMetadata($this->getOption('className')); - $reflField = $metadata->getReflectionProperty($metadata->identifier[0]); - - $ids = array(); - foreach ($value AS $object) { - $ids[] = $reflField->getValue($object); - } - - return $ids; - } -} \ No newline at end of file diff --git a/src/Symfony/Bundle/DoctrineBundle/Form/ValueTransformer/EntityToIDTransformer.php b/src/Symfony/Bundle/DoctrineBundle/Form/ValueTransformer/EntityToIDTransformer.php deleted file mode 100644 index fbbf3cf749e0..000000000000 --- a/src/Symfony/Bundle/DoctrineBundle/Form/ValueTransformer/EntityToIDTransformer.php +++ /dev/null @@ -1,64 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\DoctrineBundle\Form\ValueTransformer; - -use Symfony\Component\Form\ValueTransformer\BaseValueTransformer; -use Symfony\Component\Form\ValueTransformer\TransformationFailedException; - -/** - * Transforms a Doctrine Entity into its identifier value and back. - * - * This only works with single-field primary key fields. - * - * @author Benjamin Eberlei - */ -class EntityToIDTransformer extends BaseValueTransformer -{ - protected function configure() - { - $this->addRequiredOption('em'); - $this->addRequiredOption('className'); - - parent::configure(); - } - - /** - * Reverse Transforming the selected id value to an Doctrine Entity. - * - * This handles NULL, the EntityManager#find method returns null if no entity was found. - * - * @param int|string $newId - * @param object $oldEntity - * @return object - */ - public function reverseTransform($newId, $oldEntity) - { - if (empty($newId)) { - return null; - } - - return $this->getOption('em')->find($this->getOption('className'), $newId); - } - - /** - * @param object $entity - * @return int|string - */ - public function transform($entity) - { - if (empty($entity)) { - return 0; - } - - return current( $this->getOption('em')->getUnitOfWork()->getEntityIdentifier($entity) ); - } -} \ No newline at end of file diff --git a/src/Symfony/Bundle/DoctrineBundle/Tests/Form/ValueTransformer/CollectionToChoiceTransformerTest.php b/src/Symfony/Bundle/DoctrineBundle/Tests/Form/ValueTransformer/CollectionToChoiceTransformerTest.php deleted file mode 100644 index ed838bce562e..000000000000 --- a/src/Symfony/Bundle/DoctrineBundle/Tests/Form/ValueTransformer/CollectionToChoiceTransformerTest.php +++ /dev/null @@ -1,141 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer; - -use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\ORM\Tools\SchemaTool; -use Symfony\Bundle\DoctrineBundle\Form\ValueTransformer\CollectionToChoiceTransformer; - -class CollectionToChoiceTransformerTest extends \Symfony\Bundle\DoctrineBundle\Tests\TestCase -{ - /** - * @var EntityManager - */ - private $em; - - protected function setUp() - { - parent::setUp(); - $this->em = $this->createTestEntityManager(); - - $schemaTool = new SchemaTool($this->em); - $classes = array($this->em->getClassMetadata('Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag')); - try { - $schemaTool->dropSchema($classes); - } catch(\Exception $e) { - - } - try { - $schemaTool->createSchema($classes); - } catch(\Exception $e) { - } - } - - public function testCreateWithoutEntityManagerThrowsException() - { - $this->setExpectedException('Symfony\Component\Form\Exception\MissingOptionsException'); - $transformer = new CollectionToChoiceTransformer(array("className" => "Tag")); - } - - public function testCreateWithoutClassNameThrowsException() - { - $this->setExpectedException('Symfony\Component\Form\Exception\MissingOptionsException'); - $transformer = new CollectionToChoiceTransformer(array("em" => $this->em)); - } - - public function createTransformer() - { - return new CollectionToChoiceTransformer(array( - "em" => $this->em, - "className" => 'Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag' - )); - } - - public function testTransformEmpty() - { - $transformer = $this->createTransformer(); - $ids = $transformer->transform(new ArrayCollection()); - - $this->assertEquals(array(), $ids); - } - - public function testTransformNull() - { - $transformer = $this->createTransformer(); - - $this->assertEquals(array(), $transformer->transform(null)); - } - - public function createTagCollection() - { - $tags = new ArrayCollection(); - $tags->add(new Tag("foo")); - $tags->add(new Tag("bar")); - - foreach ($tags AS $tag) { - $this->em->persist($tag); - } - $this->em->flush(); - $this->em->clear(); - - return $tags; - } - - public function testTransform() - { - $transformer = $this->createTransformer(); - $ids = $transformer->transform($this->createTagCollection()); - - $this->assertEquals(array(1, 2), $ids); - } - - public function testReverseTransformEmpty() - { - $transformer = $this->createTransformer(); - - $col = new ArrayCollection(); - - $newCol = $transformer->reverseTransform(array(), $col); - $this->assertSame($col, $newCol, "Collection is an expensive object, it should be re-used."); - - $this->assertEquals(0, count($newCol)); - } - - public function testReverseTransformEmptyClearsCollection() - { - $transformer = $this->createTransformer(); - - $newCol = $transformer->reverseTransform(array(), $this->createTagCollection()); - $this->assertEquals(0, count($newCol)); - } - - public function testReverseTransformFetchFromEntityManager() - { - $transformer = $this->createTransformer(); - - $col = new ArrayCollection(); - $tags = $this->createTagCollection(); - - $newCol = $transformer->reverseTransform(array(1, 2), $col); - $this->assertEquals(2, count($newCol)); - } - - public function testReverseTransformRemoveMissingFromCollection() - { - $transformer = $this->createTransformer(); - $tags = $this->createTagCollection(); - - $newCol = $transformer->reverseTransform(array(1), $tags); - $this->assertEquals(1, count($newCol)); - $this->assertFalse($newCol->contains($this->em->find('Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag', 2))); - } -} \ No newline at end of file diff --git a/src/Symfony/Bundle/DoctrineBundle/Tests/Form/ValueTransformer/EntityToIDTransformerTest.php b/src/Symfony/Bundle/DoctrineBundle/Tests/Form/ValueTransformer/EntityToIDTransformerTest.php deleted file mode 100644 index 8c65145e7beb..000000000000 --- a/src/Symfony/Bundle/DoctrineBundle/Tests/Form/ValueTransformer/EntityToIDTransformerTest.php +++ /dev/null @@ -1,100 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer; - -use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\ORM\Tools\SchemaTool; -use Symfony\Bundle\DoctrineBundle\Form\ValueTransformer\EntityToIDTransformer; - -class EntityToIDTransformerTest extends \Symfony\Bundle\DoctrineBundle\Tests\TestCase -{ - /** - * @var EntityManager - */ - private $em; - - protected function setUp() - { - parent::setUp(); - $this->em = $this->createTestEntityManager(); - - $schemaTool = new SchemaTool($this->em); - $classes = array($this->em->getClassMetadata('Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag')); - try { - $schemaTool->dropSchema($classes); - } catch(\Exception $e) { - - } - try { - $schemaTool->createSchema($classes); - } catch(\Exception $e) { - - } - } - - public function testRequiredEntityManager() - { - $this->setExpectedException('Symfony\Component\Form\Exception\MissingOptionsException'); - $transformer = new EntityToIDTransformer(array('className' => 'Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag')); - } - - public function testRequiredClassName() - { - $this->setExpectedException('Symfony\Component\Form\Exception\MissingOptionsException'); - $transformer = new EntityToIDTransformer(array('em' => $this->em)); - } - - public function createTransformer() - { - $transformer = new EntityToIDTransformer(array( - 'em' => $this->em, - 'className' => 'Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag' - )); - return $transformer; - } - - public function testTranformEmptyValueReturnsNull() - { - $transformer = $this->createTransformer(); - $this->assertEquals(0, $transformer->transform(null)); - $this->assertEquals(0, $transformer->transform("")); - $this->assertEquals(0, $transformer->transform(0)); - } - - public function testTransform() - { - $transformer = $this->createTransformer(); - - $tag = new Tag("name"); - $this->em->persist($tag); - $this->em->flush(); - - $this->assertEquals(1, $transformer->transform($tag)); - } - - public function testReverseTransformEmptyValue() - { - $transformer = $this->createTransformer(); - $this->assertNull($transformer->reverseTransform(0, null)); - } - - public function testReverseTransform() - { - $transformer = $this->createTransformer(); - - $tag = new Tag("name"); - $this->em->persist($tag); - $this->em->flush(); - - $this->assertSame($tag, $transformer->reverseTransform(1, null)); - } -} \ No newline at end of file diff --git a/src/Symfony/Component/Form/ChoiceField.php b/src/Symfony/Component/Form/ChoiceField.php index 350ea8e4292e..659b6d2dd734 100644 --- a/src/Symfony/Component/Form/ChoiceField.php +++ b/src/Symfony/Component/Form/ChoiceField.php @@ -119,6 +119,10 @@ protected function initializeChoices() { if (!$this->choices) { $this->choices = $this->getInitializedChoices(); + + if (!$this->isRequired()) { + $this->choices = array('' => $this->getOption('empty_value')) + $this->choices; + } } } @@ -130,15 +134,10 @@ protected function getInitializedChoices() $choices = $choices->__invoke(); } - // TESTME if (!is_array($choices)) { throw new InvalidOptionsException('The "choices" option must be an array or a closure returning an array', array('choices')); } - if (!$this->isRequired()) { - $choices = array_merge(array('' => $this->getOption('empty_value')), $choices); - } - return $choices; } diff --git a/src/Symfony/Bundle/DoctrineBundle/Form/ValueTransformer/CollectionToStringTransformer.php b/src/Symfony/Component/Form/Extension/Doctrine/CollectionToStringTransformer.php similarity index 98% rename from src/Symfony/Bundle/DoctrineBundle/Form/ValueTransformer/CollectionToStringTransformer.php rename to src/Symfony/Component/Form/Extension/Doctrine/CollectionToStringTransformer.php index 1fcb0a77ae83..dcc396d579bc 100644 --- a/src/Symfony/Bundle/DoctrineBundle/Form/ValueTransformer/CollectionToStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Doctrine/CollectionToStringTransformer.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Bundle\DoctrineBundle\Form\ValueTransformer; +namespace Symfony\Component\Form\Extension\Doctrine; use Symfony\Component\Form\ValueTransformer\BaseValueTransformer; use Symfony\Component\Form\ValueTransformer\TransformationFailedException; @@ -33,6 +33,7 @@ * @todo Refactor to make 'fieldName' optional (identifier). * * @author Benjamin Eberlei + * @author Bernhard Schussek */ class CollectionToStringTransformer extends BaseValueTransformer { diff --git a/src/Symfony/Component/Form/Extension/Doctrine/EntityChoiceField.php b/src/Symfony/Component/Form/Extension/Doctrine/EntityChoiceField.php new file mode 100644 index 000000000000..7974527f97b0 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Doctrine/EntityChoiceField.php @@ -0,0 +1,504 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Extension\Doctrine; + +use Symfony\Component\Form\ChoiceField; +use Symfony\Component\Form\PropertyPath; +use Symfony\Component\Form\ValueTransformer\TransformationFailedException; +use Symfony\Component\Form\Exception\FormException; +use Symfony\Component\Form\Exception\InvalidOptionsException; +use Doctrine\Common\Collections\Collection; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\ORM\QueryBuilder; +use Doctrine\ORM\NoResultException; + +/** + * A field for selecting one or more from a list of Doctrine 2 entities + * + * You at least have to pass the entity manager and the entity class in the + * options "em" and "class". + * + * + * $form->add(new EntityChoiceField('tags', array( + * 'em' => $em, + * 'class' => 'Application\Entity\Tag', + * ))); + * + * + * Additionally to the options in ChoiceField, the following options are + * available: + * + * * em: The entity manager. Required. + * * class: The class of the selectable entities. Required. + * * property: The property displayed as value of the choices. If this + * option is not available, the field will try to convert + * objects into strings using __toString(). + * * query_builder: The query builder for fetching the selectable entities. + * You can also pass a closure that receives the repository + * as single argument and returns a query builder. + * + * The following sample outlines the use of the "query_builder" option + * with closures. + * + * + * $form->add(new EntityChoiceField('tags', array( + * 'em' => $em, + * 'class' => 'Application\Entity\Tag', + * 'query_builder' => function ($repository) { + * return $repository->createQueryBuilder('t')->where('t.enabled = 1'); + * }, + * ))); + * + * + * @author Bernhard Schussek + */ +class EntityChoiceField extends ChoiceField +{ + /** + * The entities from which the user can choose + * + * This array is either indexed by ID (if the ID is a single field) + * or by key in the choices array (if the ID consists of multiple fields) + * + * This property is initialized by initializeChoices(). It should only + * be accessed through getEntity() and getEntities(). + * + * @var Collection + */ + protected $entities = null; + + /** + * Contains the query builder that builds the query for fetching the + * entities + * + * This property should only be accessed through getQueryBuilder(). + * + * @var Doctrine\ORM\QueryBuilder + */ + protected $queryBuilder = null; + + /** + * The fields of which the identifier of the underlying class consists + * + * This property should only be accessed through getIdentifierFields(). + * + * @var array + */ + protected $identifier = array(); + + /** + * A cache for \ReflectionProperty instances for the underlying class + * + * This property should only be accessed through getReflProperty(). + * + * @var array + */ + protected $reflProperties = array(); + + /** + * A cache for the UnitOfWork instance of Doctrine + * + * @var Doctrine\ORM\UnitOfWork + */ + protected $unitOfWork = null; + + /** + * {@inheritDoc} + */ + protected function configure() + { + $this->addRequiredOption('em'); + $this->addRequiredOption('class'); + $this->addOption('property'); + $this->addOption('query_builder'); + + // Override option - it is not required for this subclass + $this->addOption('choices', array()); + + parent::configure(); + + // The entities can be passed directly in the "choices" option. + // In this case, initializing the entity cache is a cheap operation + // so do it now! + if (is_array($this->getOption('choices')) && count($this->getOption('choices')) > 0) { + $this->initializeChoices(); + } + + // If a query builder was passed, it must be a closure or QueryBuilder + // instance + if ($qb = $this->getOption('query_builder')) { + if (!($qb instanceof QueryBuilder || $qb instanceof \Closure)) { + throw new InvalidOptionsException( + 'The option "query_builder" most contain a closure or a QueryBuilder instance', + array('query_builder')); + } + } + } + + /** + * Returns the query builder instance for the choices of this field + * + * @return Doctrine\ORM\QueryBuilder The query builder + * @throws InvalidOptionsException When the query builder was passed as + * closure and that closure does not + * return a QueryBuilder instance + */ + protected function getQueryBuilder() + { + if (!$this->getOption('query_builder')) { + return null; + } + + if (!$this->queryBuilder) { + $qb = $this->getOption('query_builder'); + + if ($qb instanceof \Closure) { + $class = $this->getOption('class'); + $em = $this->getOption('em'); + $qb = $qb($em->getRepository($class)); + + if (!$qb instanceof QueryBuilder) { + throw new InvalidOptionsException( + 'The closure in the option "query_builder" should return a QueryBuilder instance', + array('query_builder')); + } + } + + $this->queryBuilder = $qb; + } + + return $this->queryBuilder; + } + + /** + * Returns the unit of work of the entity manager + * + * This object is cached for faster lookups. + * + * @return Doctrine\ORM\UnitOfWork The unit of work + */ + protected function getUnitOfWork() + { + if (!$this->unitOfWork) { + $this->unitOfWork = $this->getOption('em')->getUnitOfWork(); + } + + return $this->unitOfWork; + } + + /** + * Initializes the choices and returns them + * + * The choices are generated from the entities. If the entities have a + * composite identifier, the choices are indexed using ascending integers. + * Otherwise the identifiers are used as indices. + * + * If the entities were passed in the "choices" option, this method + * does not have any significant overhead. Otherwise, if a query builder + * was passed in the "query_builder" option, this builder is now used + * to construct a query which is executed. In the last case, all entities + * for the underlying class are fetched from the repository. + * + * If the option "property" was passed, the property path in that option + * is used as option values. Otherwise this method tries to convert + * objects to strings using __toString(). + * + * @return array An array of choices + */ + protected function getInitializedChoices() + { + if ($this->getOption('choices')) { + $entities = parent::getInitializedChoices(); + } else if ($qb = $this->getQueryBuilder()) { + $entities = $qb->getQuery()->execute(); + } else { + $class = $this->getOption('class'); + $em = $this->getOption('em'); + $entities = $em->getRepository($class)->findAll(); + } + + $propertyPath = null; + $choices = array(); + $this->entities = array(); + + // The propery option defines, which property (path) is used for + // displaying entities as strings + if ($this->getOption('property')) { + $propertyPath = new PropertyPath($this->getOption('property')); + } + + foreach ($entities as $key => $entity) { + if ($propertyPath) { + // If the property option was given, use it + $value = $propertyPath->getValue($entity); + } else { + // Otherwise expect a __toString() method in the entity + $value = (string)$entity; + } + + if (count($this->getIdentifierFields()) > 1) { + // When the identifier consists of multiple field, use + // naturally ordered keys to refer to the choices + $choices[$key] = $value; + $this->entities[$key] = $entity; + } else { + // When the identifier is a single field, index choices by + // entity ID for performance reasons + $id = current($this->getIdentifierValues($entity)); + $choices[$id] = $value; + $this->entities[$id] = $entity; + } + } + + return $choices; + } + + /** + * Returns the according entities for the choices + * + * If the choices were not initialized, they are initialized now. This + * is an expensive operation, except if the entities were passed in the + * "choices" option. + * + * @return array An array of entities + */ + protected function getEntities() + { + if (!$this->entities) { + // indirectly initializes the entities property + $this->initializeChoices(); + } + + return $this->entities; + } + + /** + * Returns the entity for the given key + * + * If the underlying entities have composite identifiers, the choices + * are intialized. The key is expected to be the index in the choices + * array in this case. + * + * 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 + */ + protected function getEntity($key) + { + $id = $this->getIdentifierFields(); + + if (count($id) > 1) { + // $key is a collection index + $entities = $this->getEntities(); + return $entities[$key]; + } else if ($this->entities) { + return $this->entities[$key]; + } else if ($qb = $this->getQueryBuilder()) { + // should we clone the builder? + $alias = $qb->getRootAlias(); + $where = $qb->expr()->eq($alias.'.'.current($id), $key); + + return $qb->andWhere($where)->getQuery()->getSingleResult(); + } + + return $this->getOption('em')->find($this->getOption('class'), $key); + } + + /** + * Returns the \ReflectionProperty instance for a property of the + * underlying class + * + * @param string $property The name of the property + * @return \ReflectionProperty The reflection instsance + */ + protected function getReflProperty($property) + { + if (!isset($this->reflProperties[$property])) { + $this->reflProperties[$property] = new \ReflectionProperty($this->getOption('class'), $field); + $this->reflProperties[$property]->setAccessible(true); + } + + return $this->reflProperties[$property]; + } + + /** + * Returns the fields included in the identifier of the underlying class + * + * @return array An array of field names + */ + protected function getIdentifierFields() + { + if (!$this->identifier) { + $metadata = $this->getOption('em')->getClassMetadata($this->getOption('class')); + $this->identifier = $metadata->getIdentifierFieldNames(); + } + + return $this->identifier; + } + + /** + * 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 + * @throws FormException If the entity does not exist in Doctrine's + * identity map + */ + protected function getIdentifierValues($entity) + { + if (!$this->getUnitOfWork()->isInIdentityMap($entity)) { + throw new FormException('Entities passed to the choice field must be managed'); + } + + return $this->getUnitOfWork()->getEntityIdentifier($entity); + } + + /** + * Merges the selected and deselected entities into the collection passed + * when calling setData() + * + * @see parent::processData() + */ + protected function processData($data) + { + // reuse the existing collection to optimize for Doctrine + if ($data instanceof Collection) { + $currentData = $this->getData(); + + if (!$currentData) { + $currentData = $data; + } else if (count($data) === 0) { + $currentData->clear(); + } else { + // merge $data into $currentData + foreach ($currentData as $entity) { + if (!$data->contains($entity)) { + $currentData->removeElement($entity); + } else { + $data->removeElement($entity); + } + } + + foreach ($data as $entity) { + $currentData->add($entity); + } + } + + return $currentData; + } + + return $data; + } + + /** + * Transforms choice keys into entities + * + * @param mixed $keyOrKeys An array of keys, a single key or NULL + * @return Collection|object A collection of entities, a single entity + * or NULL + */ + protected function reverseTransform($keyOrKeys) + { + $keyOrKeys = parent::reverseTransform($keyOrKeys); + + if (null === $keyOrKeys) { + return $this->getOption('multiple') ? new ArrayCollection() : null; + } + + $notFound = array(); + + if (count($this->getIdentifierFields()) > 1) { + $notFound = array_diff((array)$keyOrKeys, array_keys($this->getEntities())); + } else if ($this->entities) { + $notFound = array_diff((array)$keyOrKeys, array_keys($this->entities)); + } + + if (0 === count($notFound)) { + if (is_array($keyOrKeys)) { + $result = new ArrayCollection(); + + // optimize this into a SELECT WHERE IN query + foreach ($keyOrKeys as $key) { + try { + $result->add($this->getEntity($key)); + } catch (NoResultException $e) { + $notFound[] = $key; + } + } + } else { + try { + $result = $this->getEntity($keyOrKeys); + } catch (NoResultException $e) { + $notFound[] = $keyOrKeys; + } + } + } + + if (count($notFound) > 0) { + throw new TransformationFailedException('The entities with keys "%s" could not be found', implode('", "', $notFound)); + } + + return $result; + } + + /** + * Transforms entities into choice keys + * + * @param Collection|object A collection of entities, a single entity or + * NULL + * @return mixed An array of choice keys, a single key or + * NULL + */ + protected function transform($collectionOrEntity) + { + if (null === $collectionOrEntity) { + return $this->getOption('multiple') ? array() : ''; + } + + if (count($this->identifier) > 1) { + // load all choices + $availableEntities = $this->getEntities(); + + if ($collectionOrEntity instanceof Collection) { + $result = array(); + + foreach ($collectionOrEntity as $entity) { + // identify choices by their collection key + $key = array_search($entity, $availableEntities); + $result[] = $key; + } + } else { + $result = array_search($collectionOrEntity, $availableEntities); + } + } else { + if ($collectionOrEntity instanceof Collection) { + $result = array(); + + foreach ($collectionOrEntity as $entity) { + $result[] = current($this->getIdentifierValues($entity)); + } + } else { + $result = current($this->getIdentifierValues($collectionOrEntity)); + } + } + + + return parent::transform($result); + } +} \ No newline at end of file diff --git a/src/Symfony/Bundle/DoctrineBundle/Tests/Form/ValueTransformer/CollectionToStringTransformerTest.php b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/CollectionToStringTransformerTest.php similarity index 87% rename from src/Symfony/Bundle/DoctrineBundle/Tests/Form/ValueTransformer/CollectionToStringTransformerTest.php rename to tests/Symfony/Tests/Component/Form/Extension/Doctrine/CollectionToStringTransformerTest.php index 1f3f88fe11e4..756425bd2c9e 100644 --- a/src/Symfony/Bundle/DoctrineBundle/Tests/Form/ValueTransformer/CollectionToStringTransformerTest.php +++ b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/CollectionToStringTransformerTest.php @@ -9,13 +9,15 @@ * file that was distributed with this source code. */ -namespace Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer; +namespace Symfony\Tests\Component\Form\Extension\Doctrine; -use Symfony\Bundle\DoctrineBundle\Form\ValueTransformer\CollectionToStringTransformer; +require_once __DIR__.'/TestCase.php'; + +use Symfony\Component\Form\Extension\Doctrine\CollectionToStringTransformer; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Tools\SchemaTool; -class CollectionToStringTransformerTest extends \Symfony\Bundle\DoctrineBundle\Tests\TestCase +class CollectionToStringTransformerTest extends TestCase { /** * @var EntityManager @@ -28,7 +30,7 @@ protected function setUp() $this->em = $this->createTestEntityManager(); $schemaTool = new SchemaTool($this->em); - $classes = array($this->em->getClassMetadata('Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag')); + $classes = array($this->em->getClassMetadata(__NAMESPACE__.'\Tag')); try { $schemaTool->dropSchema($classes); } catch(\Exception $e) { @@ -45,7 +47,7 @@ public function testNoEntityManagerThrowsException() { $this->setExpectedException('Symfony\Component\Form\Exception\MissingOptionsException'); $transformer = new CollectionToStringTransformer(array( - 'class_name' => 'Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag', + 'class_name' => __NAMESPACE__.'\Tag', 'field_name' => 'name', )); } @@ -63,7 +65,7 @@ public function testNoFieldNameThrowsException() { $this->setExpectedException('Symfony\Component\Form\Exception\MissingOptionsException'); $transformer = new CollectionToStringTransformer(array( - 'class_name' => 'Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag', + 'class_name' => __NAMESPACE__.'\Tag', 'em' => $this->em, )); } @@ -71,7 +73,7 @@ public function testNoFieldNameThrowsException() public function createTransformer() { $transformer = new CollectionToStringTransformer(array( - 'class_name' => 'Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag', + 'class_name' => __NAMESPACE__.'\Tag', 'field_name' => 'name', 'em' => $this->em, 'create_instance_callback' => function($tagName) { @@ -99,7 +101,7 @@ public function testTransformCollection() $tags = new ArrayCollection(); $tags->add(new Tag("foo")); $tags->add(new Tag("bar")); - + $this->assertEquals("foo,bar", $transformer->transform($tags)); } @@ -187,7 +189,7 @@ public function testReverseTransformNewUnknownEntity() $this->assertSame($this->em, $transformer->getOption('em')); - $this->assertEquals(1, count($this->em->getRepository('Symfony\Bundle\DoctrineBundle\Tests\Form\ValueTransformer\Tag')->findAll())); + $this->assertEquals(1, count($this->em->getRepository(__NAMESPACE__.'\Tag')->findAll())); } /** diff --git a/tests/Symfony/Tests/Component/Form/Extension/Doctrine/EntityChoiceFieldTest.php b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/EntityChoiceFieldTest.php new file mode 100644 index 000000000000..d3f057bcec5a --- /dev/null +++ b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/EntityChoiceFieldTest.php @@ -0,0 +1,556 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Tests\Component\Form\Extension\Doctrine; + +require_once __DIR__.'/TestCase.php'; +require_once __DIR__.'/Fixtures/SingleIdentEntity.php'; +require_once __DIR__.'/Fixtures/CompositeIdentEntity.php'; + +use Symfony\Component\Form\Extension\Doctrine\EntityChoiceField; +use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Tests\Component\Form\Extension\Doctrine\Fixtures\SingleIdentEntity; +use Symfony\Tests\Component\Form\Extension\Doctrine\Fixtures\CompositeIdentEntity; +use Doctrine\ORM\Tools\SchemaTool; +use Doctrine\Common\Collections\ArrayCollection; + +class EntityChoiceFieldTest extends TestCase +{ + const SINGLE_IDENT_CLASS = 'Symfony\Tests\Component\Form\Extension\Doctrine\Fixtures\SingleIdentEntity'; + + const COMPOSITE_IDENT_CLASS = 'Symfony\Tests\Component\Form\Extension\Doctrine\Fixtures\CompositeIdentEntity'; + + /** + * @var EntityManager + */ + private $em; + + protected function setUp() + { + parent::setUp(); + + $this->em = $this->createTestEntityManager(); + + $schemaTool = new SchemaTool($this->em); + $classes = array( + $this->em->getClassMetadata(self::SINGLE_IDENT_CLASS), + $this->em->getClassMetadata(self::COMPOSITE_IDENT_CLASS), + ); + + try { + $schemaTool->dropSchema($classes); + } catch(\Exception $e) { + } + + try { + $schemaTool->createSchema($classes); + } catch(\Exception $e) { + } + } + + protected function persist(array $entities) + { + foreach ($entities as $entity) { + $this->em->persist($entity); + } + + $this->em->flush(); + // no clear, because entities managed by the choice field must + // be managed! + } + + public function testNonRequiredContainsEmptyField() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + + $this->persist(array($entity1, $entity2)); + + $field = new EntityChoiceField('name', array( + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'required' => false, + 'property' => 'name' + )); + + $this->assertEquals(array('' => '', 1 => 'Foo', 2 => 'Bar'), $field->getOtherChoices()); + } + +// public function testSetDataToUninitializedEntityWithNonRequired() +// { +// $entity1 = new SingleIdentEntity(1, 'Foo'); +// $entity2 = new SingleIdentEntity(2, 'Bar'); +// +// $this->persist(array($entity1, $entity2)); +// +// $field = new EntityChoiceField('name', array( +// 'em' => $this->em, +// 'class' => self::SINGLE_IDENT_CLASS, +// 'required' => false, +// 'property' => 'name' +// )); +// +// $this->assertEquals(array('' => '', 1 => 'Foo', 2 => 'Bar'), $field->getOtherChoices()); +// +// } + + /** + * @expectedException Symfony\Component\Form\Exception\InvalidOptionsException + */ + public function testConfigureQueryBuilderWithNonQueryBuilderAndNonClosure() + { + $field = new EntityChoiceField('name', array( + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'query_builder' => new \stdClass(), + )); + } + + /** + * @expectedException Symfony\Component\Form\Exception\InvalidOptionsException + */ + public function testConfigureQueryBuilderWithClosureReturningNonQueryBuilder() + { + $field = new EntityChoiceField('name', array( + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'query_builder' => function () { + return new \stdClass(); + }, + )); + + $field->bind('2'); + } + + /** + * @expectedException Symfony\Component\Form\Exception\FormException + */ + public function testChoicesMustBeManaged() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + + // no persist here! + + $field = new EntityChoiceField('name', array( + 'multiple' => false, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'choices' => array($entity1, $entity2), + 'property' => 'name', + )); + } + + public function testSetDataSingle_null() + { + $field = new EntityChoiceField('name', array( + 'multiple' => false, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + )); + $field->setData(null); + + $this->assertEquals(null, $field->getData()); + $this->assertEquals('', $field->getDisplayedData()); + } + + public function testSetDataMultiple_null() + { + $field = new EntityChoiceField('name', array( + 'multiple' => true, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + )); + $field->setData(null); + + $this->assertEquals(null, $field->getData()); + $this->assertEquals(array(), $field->getDisplayedData()); + } + + public function testBindSingle_null() + { + $field = new EntityChoiceField('name', array( + 'multiple' => false, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + )); + $field->bind(null); + + $this->assertEquals(null, $field->getData()); + $this->assertEquals('', $field->getDisplayedData()); + } + + public function testBindMultiple_null() + { + $field = new EntityChoiceField('name', array( + 'multiple' => true, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + )); + $field->bind(null); + + $this->assertEquals(new ArrayCollection(), $field->getData()); + $this->assertEquals(array(), $field->getDisplayedData()); + } + + public function testBindSingleNonExpanded_singleIdentifier() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + + $this->persist(array($entity1, $entity2)); + + $field = new EntityChoiceField('name', array( + 'multiple' => false, + 'expanded' => false, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'property' => 'name', + )); + + $field->bind('2'); + + $this->assertTrue($field->isTransformationSuccessful()); + $this->assertEquals($entity2, $field->getData()); + $this->assertEquals(2, $field->getDisplayedData()); + } + + public function testBindSingleNonExpanded_compositeIdentifier() + { + $entity1 = new CompositeIdentEntity(10, 20, 'Foo'); + $entity2 = new CompositeIdentEntity(30, 40, 'Bar'); + + $this->persist(array($entity1, $entity2)); + + $field = new EntityChoiceField('name', array( + 'multiple' => false, + 'expanded' => false, + 'em' => $this->em, + 'class' => self::COMPOSITE_IDENT_CLASS, + 'property' => 'name', + )); + + // the collection key is used here + $field->bind('1'); + + $this->assertTrue($field->isTransformationSuccessful()); + $this->assertEquals($entity2, $field->getData()); + $this->assertEquals(1, $field->getDisplayedData()); + } + + public function testBindMultipleNonExpanded_singleIdentifier() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + $entity3 = new SingleIdentEntity(3, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'multiple' => true, + 'expanded' => false, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'property' => 'name', + )); + + $field->bind(array('1', '3')); + + $expected = new ArrayCollection(array($entity1, $entity3)); + + $this->assertTrue($field->isTransformationSuccessful()); + $this->assertEquals($expected, $field->getData()); + $this->assertEquals(array(1, 3), $field->getDisplayedData()); + } + + public function testBindMultipleNonExpanded_singleIdentifier_existingData() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + $entity3 = new SingleIdentEntity(3, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'multiple' => true, + 'expanded' => false, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'property' => 'name', + )); + + $existing = new ArrayCollection(array($entity2)); + + $field->setData($existing); + $field->bind(array('1', '3')); + + // entry with index 0 was removed + $expected = new ArrayCollection(array(1 => $entity1, 2 => $entity3)); + + $this->assertTrue($field->isTransformationSuccessful()); + $this->assertEquals($expected, $field->getData()); + // same object still, useful if it is a PersistentCollection + $this->assertSame($existing, $field->getData()); + $this->assertEquals(array(1, 3), $field->getDisplayedData()); + } + + public function testBindMultipleNonExpanded_compositeIdentifier() + { + $entity1 = new CompositeIdentEntity(10, 20, 'Foo'); + $entity2 = new CompositeIdentEntity(30, 40, 'Bar'); + $entity3 = new CompositeIdentEntity(50, 60, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'multiple' => true, + 'expanded' => false, + 'em' => $this->em, + 'class' => self::COMPOSITE_IDENT_CLASS, + 'property' => 'name', + )); + + // because of the composite key collection keys are used + $field->bind(array('0', '2')); + + $expected = new ArrayCollection(array($entity1, $entity3)); + + $this->assertTrue($field->isTransformationSuccessful()); + $this->assertEquals($expected, $field->getData()); + $this->assertEquals(array(0, 2), $field->getDisplayedData()); + } + + public function testBindMultipleNonExpanded_compositeIdentifier_existingData() + { + $entity1 = new CompositeIdentEntity(10, 20, 'Foo'); + $entity2 = new CompositeIdentEntity(30, 40, 'Bar'); + $entity3 = new CompositeIdentEntity(50, 60, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'multiple' => true, + 'expanded' => false, + 'em' => $this->em, + 'class' => self::COMPOSITE_IDENT_CLASS, + 'property' => 'name', + )); + + $existing = new ArrayCollection(array($entity2)); + + $field->setData($existing); + $field->bind(array('0', '2')); + + // entry with index 0 was removed + $expected = new ArrayCollection(array(1 => $entity1, 2 => $entity3)); + + $this->assertTrue($field->isTransformationSuccessful()); + $this->assertEquals($expected, $field->getData()); + // same object still, useful if it is a PersistentCollection + $this->assertSame($existing, $field->getData()); + $this->assertEquals(array(0, 2), $field->getDisplayedData()); + } + + public function testBindSingleExpanded() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + + $this->persist(array($entity1, $entity2)); + + $field = new EntityChoiceField('name', array( + 'multiple' => false, + 'expanded' => true, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'property' => 'name', + )); + + $field->bind('2'); + + $this->assertTrue($field->isTransformationSuccessful()); + $this->assertEquals($entity2, $field->getData()); + $this->assertSame(false, $field['1']->getData()); + $this->assertSame(true, $field['2']->getData()); + $this->assertSame('', $field['1']->getDisplayedData()); + $this->assertSame('1', $field['2']->getDisplayedData()); + $this->assertSame(array('1' => '', '2' => '1'), $field->getDisplayedData()); + } + + public function testBindMultipleExpanded() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + $entity3 = new SingleIdentEntity(3, 'Bar'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'multiple' => true, + 'expanded' => true, + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'property' => 'name', + )); + + $field->bind(array('1' => '1', '3' => '3')); + + $expected = new ArrayCollection(array($entity1, $entity3)); + + $this->assertTrue($field->isTransformationSuccessful()); + $this->assertEquals($expected, $field->getData()); + $this->assertSame(true, $field['1']->getData()); + $this->assertSame(false, $field['2']->getData()); + $this->assertSame(true, $field['3']->getData()); + $this->assertSame('1', $field['1']->getDisplayedData()); + $this->assertSame('', $field['2']->getDisplayedData()); + $this->assertSame('1', $field['3']->getDisplayedData()); + $this->assertSame(array('1' => '1', '2' => '', '3' => '1'), $field->getDisplayedData()); + } + + public function testOverrideChoices() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + $entity3 = new SingleIdentEntity(3, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + // not all persisted entities should be displayed + 'choices' => array($entity1, $entity2), + 'property' => 'name', + )); + + $field->bind('2'); + + $this->assertEquals(array(1 => 'Foo', 2 => 'Bar'), $field->getOtherChoices()); + $this->assertTrue($field->isTransformationSuccessful()); + $this->assertEquals($entity2, $field->getData()); + $this->assertEquals(2, $field->getDisplayedData()); + } + + public function testDisallowChoicesThatAreNotIncluded_choices_singleIdentifier() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + $entity3 = new SingleIdentEntity(3, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'choices' => array($entity1, $entity2), + 'property' => 'name', + )); + + $field->bind('3'); + + $this->assertFalse($field->isTransformationSuccessful()); + $this->assertNull($field->getData()); + } + + public function testDisallowChoicesThatAreNotIncluded_choices_compositeIdentifier() + { + $entity1 = new CompositeIdentEntity(10, 20, 'Foo'); + $entity2 = new CompositeIdentEntity(30, 40, 'Bar'); + $entity3 = new CompositeIdentEntity(50, 60, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'em' => $this->em, + 'class' => self::COMPOSITE_IDENT_CLASS, + 'choices' => array($entity1, $entity2), + 'property' => 'name', + )); + + $field->bind('2'); + + $this->assertFalse($field->isTransformationSuccessful()); + $this->assertNull($field->getData()); + } + + public function testDisallowChoicesThatAreNotIncluded_queryBuilder_singleIdentifier() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + $entity3 = new SingleIdentEntity(3, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $repository = $this->em->getRepository(self::SINGLE_IDENT_CLASS); + + $field = new EntityChoiceField('name', array( + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'query_builder' => $repository->createQueryBuilder('e') + ->where('e.id IN (1, 2)'), + 'property' => 'name', + )); + + $field->bind('3'); + + $this->assertFalse($field->isTransformationSuccessful()); + $this->assertNull($field->getData()); + } + + public function testDisallowChoicesThatAreNotIncluded_queryBuilderAsClosure_singleIdentifier() + { + $entity1 = new SingleIdentEntity(1, 'Foo'); + $entity2 = new SingleIdentEntity(2, 'Bar'); + $entity3 = new SingleIdentEntity(3, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'em' => $this->em, + 'class' => self::SINGLE_IDENT_CLASS, + 'query_builder' => function ($repository) { + return $repository->createQueryBuilder('e') + ->where('e.id IN (1, 2)'); + }, + 'property' => 'name', + )); + + $field->bind('3'); + + $this->assertFalse($field->isTransformationSuccessful()); + $this->assertNull($field->getData()); + } + + public function testDisallowChoicesThatAreNotIncluded_queryBuilderAsClosure_compositeIdentifier() + { + $entity1 = new CompositeIdentEntity(10, 20, 'Foo'); + $entity2 = new CompositeIdentEntity(30, 40, 'Bar'); + $entity3 = new CompositeIdentEntity(50, 60, 'Baz'); + + $this->persist(array($entity1, $entity2, $entity3)); + + $field = new EntityChoiceField('name', array( + 'em' => $this->em, + 'class' => self::COMPOSITE_IDENT_CLASS, + 'query_builder' => function ($repository) { + return $repository->createQueryBuilder('e') + ->where('e.id1 IN (10, 50)'); + }, + 'property' => 'name', + )); + + $field->bind('2'); + + $this->assertFalse($field->isTransformationSuccessful()); + $this->assertNull($field->getData()); + } +} \ No newline at end of file diff --git a/tests/Symfony/Tests/Component/Form/Extension/Doctrine/Fixtures/CompositeIdentEntity.php b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/Fixtures/CompositeIdentEntity.php new file mode 100644 index 000000000000..98cbba3b33c0 --- /dev/null +++ b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/Fixtures/CompositeIdentEntity.php @@ -0,0 +1,22 @@ +id1 = $id1; + $this->id2 = $id2; + $this->name = $name; + } +} \ No newline at end of file diff --git a/tests/Symfony/Tests/Component/Form/Extension/Doctrine/Fixtures/SingleIdentEntity.php b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/Fixtures/SingleIdentEntity.php new file mode 100644 index 000000000000..b06037cbf38a --- /dev/null +++ b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/Fixtures/SingleIdentEntity.php @@ -0,0 +1,18 @@ +id = $id; + $this->name = $name; + } +} \ No newline at end of file diff --git a/tests/Symfony/Tests/Component/Form/Extension/Doctrine/TestCase.php b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/TestCase.php new file mode 100644 index 000000000000..dc080d042d0a --- /dev/null +++ b/tests/Symfony/Tests/Component/Form/Extension/Doctrine/TestCase.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Tests\Component\Form\Extension\Doctrine; + +use Doctrine\ORM\EntityManager; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; +use Symfony\Bundle\DoctrineBundle\DependencyInjection\DoctrineExtension; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; + +class TestCase extends \PHPUnit_Framework_TestCase +{ + protected function setUp() + { + if (!class_exists('Doctrine\\Common\\Version')) { + $this->markTestSkipped('Doctrine is not available.'); + } + } + + /** + * @return EntityManager + */ + protected function createTestEntityManager($paths = array()) + { + $config = new \Doctrine\ORM\Configuration(); + $config->setAutoGenerateProxyClasses(true); + $config->setProxyDir(\sys_get_temp_dir()); + $config->setProxyNamespace('SymfonyTests\Doctrine'); + $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver($paths)); + $config->setQueryCacheImpl(new \Doctrine\Common\Cache\ArrayCache()); + $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache()); + + $params = array( + 'driver' => 'pdo_sqlite', + 'memory' => true, + ); + + return EntityManager::create($params, $config); + } +}