Skip to content

Commit

Permalink
refactored Doctrine Bridge
Browse files Browse the repository at this point in the history
 * added a RegistryInterface

 * changed all classes to depend on the Registry instead of a specific EntityManager

This is more consistent as the validator already took the registry and this allows
to use any entity manager in Forms.
  • Loading branch information
fabpot committed Jun 8, 2011
1 parent 84b25b1 commit fbf3695
Show file tree
Hide file tree
Showing 15 changed files with 308 additions and 225 deletions.
4 changes: 4 additions & 0 deletions UPDATE.md
Expand Up @@ -9,6 +9,10 @@ timeline closely anyway.
beta4 to beta5
--------------

* The `em` option of the Doctrine `EntityType` class now takes the entity
manager name instead of the EntityManager instance. If you don't pass this
option, the default Entity Manager will be used as before.

* In the Console component: `Command::getFullname()` and
`Command::getNamespace()` have been removed (`Command::getName()` behavior
is now the same as the old `Command::getFullname()`).
Expand Down
16 changes: 6 additions & 10 deletions src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php
Expand Up @@ -12,30 +12,26 @@
namespace Symfony\Bridge\Doctrine\Form;

use Symfony\Component\Form\AbstractExtension;
use Doctrine\ORM\EntityManager;
use Symfony\Bridge\Doctrine\RegistryInterface;

class DoctrineOrmExtension extends AbstractExtension
{
/**
* The Doctrine 2 entity manager
* @var Doctrine\ORM\EntityManager
*/
protected $em = null;
protected $registry;

public function __construct(EntityManager $em)
public function __construct(RegistryInterface $registry)
{
$this->em = $em;
$this->registry = $registry;
}

protected function loadTypes()
{
return array(
new Type\EntityType($this->em),
new Type\EntityType($this->registry),
);
}

protected function loadTypeGuesser()
{
return new DoctrineOrmTypeGuesser($this->em);
return new DoctrineOrmTypeGuesser($this->registry);
}
}
202 changes: 71 additions & 131 deletions src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php
Expand Up @@ -15,147 +15,77 @@
use Symfony\Component\Form\Guess\Guess;
use Symfony\Component\Form\Guess\TypeGuess;
use Symfony\Component\Form\Guess\ValueGuess;
use Doctrine\ORM\EntityManager;
use Symfony\Bridge\Doctrine\RegistryInterface;

class DoctrineOrmTypeGuesser implements FormTypeGuesserInterface
{
/**
* The Doctrine 2 entity manager
* @var Doctrine\ORM\EntityManager
*/
protected $em = null;
protected $registry;

public function __construct(EntityManager $em)
{
$this->em = $em;
}
private $cache;

/**
* Returns whether Doctrine 2 metadata exists for that class
*
* @return Boolean
*/
protected function isMappedClass($class)
public function __construct(RegistryInterface $registry)
{
return !$this->em->getConfiguration()->getMetadataDriverImpl()->isTransient($class);
$this->registry = $registry;
$this->cache = array();
}

/**
* {@inheritDoc}
*/
public function guessType($class, $property)
{
if ($this->isMappedClass($class)) {
$metadata = $this->em->getClassMetadata($class);

if ($metadata->hasAssociation($property)) {
$multiple = $metadata->isCollectionValuedAssociation($property);
$mapping = $metadata->getAssociationMapping($property);

return new TypeGuess(
'entity',
array(
'em' => $this->em,
'class' => $mapping['targetEntity'],
'multiple' => $multiple,
),
Guess::HIGH_CONFIDENCE
);
} else {
switch ($metadata->getTypeOfField($property))
{
// case 'array':
// return new TypeGuess(
// 'Collection',
// array(),
// Guess::HIGH_CONFIDENCE
// );
case 'boolean':
return new TypeGuess(
'checkbox',
array(),
Guess::HIGH_CONFIDENCE
);
case 'datetime':
case 'vardatetime':
case 'datetimetz':
return new TypeGuess(
'datetime',
array(),
Guess::HIGH_CONFIDENCE
);
case 'date':
return new TypeGuess(
'date',
array(),
Guess::HIGH_CONFIDENCE
);
case 'decimal':
case 'float':
return new TypeGuess(
'number',
array(),
Guess::MEDIUM_CONFIDENCE
);
case 'integer':
case 'bigint':
case 'smallint':
return new TypeGuess(
'integer',
array(),
Guess::MEDIUM_CONFIDENCE
);
case 'string':
return new TypeGuess(
'text',
array(),
Guess::MEDIUM_CONFIDENCE
);
case 'text':
return new TypeGuess(
'textarea',
array(),
Guess::MEDIUM_CONFIDENCE
);
case 'time':
return new TypeGuess(
'time',
array(),
Guess::HIGH_CONFIDENCE
);
// case 'object': ???
}
}
if (!$metadata = $this->getMetadata($class)) {
return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
}

return new TypeGuess(
'text',
array(),
Guess::LOW_CONFIDENCE
);
if ($metadata->hasAssociation($property)) {
$multiple = $metadata->isCollectionValuedAssociation($property);
$mapping = $metadata->getAssociationMapping($property);

return new TypeGuess('entity', array('em' => $this->em, 'class' => $mapping['targetEntity'], 'multiple' => $multiple), Guess::HIGH_CONFIDENCE);

This comment has been minimized.

Copy link
@andy-cox

andy-cox Jun 8, 2011

Contributor

Is $this->em defined? Or should it be retrieved from the registry?

This comment has been minimized.

Copy link
@fabpot

fabpot Jun 8, 2011

Author Member

Very good catch. Fixed here: 2d91183

Thanks.

}

switch ($metadata->getTypeOfField($property))
{
//case 'array':
// return new TypeGuess('Collection', array(), Guess::HIGH_CONFIDENCE);
case 'boolean':
return new TypeGuess('checkbox', array(), Guess::HIGH_CONFIDENCE);
case 'datetime':
case 'vardatetime':
case 'datetimetz':
return new TypeGuess('datetime', array(), Guess::HIGH_CONFIDENCE);
case 'date':
return new TypeGuess('date', array(), Guess::HIGH_CONFIDENCE);
case 'decimal':
case 'float':
return new TypeGuess('number', array(), Guess::MEDIUM_CONFIDENCE);
case 'integer':
case 'bigint':
case 'smallint':
return new TypeGuess('integer', array(), Guess::MEDIUM_CONFIDENCE);
case 'string':
return new TypeGuess('text', array(), Guess::MEDIUM_CONFIDENCE);
case 'text':
return new TypeGuess('textarea', array(), Guess::MEDIUM_CONFIDENCE);
case 'time':
return new TypeGuess('time', array(), Guess::HIGH_CONFIDENCE);
default:
return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
}
}

/**
* {@inheritDoc}
*/
public function guessRequired($class, $property)
{
if ($this->isMappedClass($class)) {
$metadata = $this->em->getClassMetadata($class);

if ($metadata->hasField($property)) {
if (!$metadata->isNullable($property)) {
return new ValueGuess(
true,
Guess::HIGH_CONFIDENCE
);
}

return new ValueGuess(
false,
Guess::MEDIUM_CONFIDENCE
);
if ($metadata = $this->getMetadata($class) && $metadata->hasField($property)) {
if (!$metadata->isNullable($property)) {
return new ValueGuess(true, Guess::HIGH_CONFIDENCE);
}

return new ValueGuess(false, Guess::MEDIUM_CONFIDENCE);
}
}

Expand All @@ -164,19 +94,11 @@ public function guessRequired($class, $property)
*/
public function guessMaxLength($class, $property)
{
if ($this->isMappedClass($class)) {
$metadata = $this->em->getClassMetadata($class);
if ($metadata = $this->getMetadata($class) && !$metadata->hasAssociation($property)) {
$mapping = $metadata->getFieldMapping($property);

if (!$metadata->hasAssociation($property)) {
$mapping = $metadata->getFieldMapping($property);


if (isset($mapping['length'])) {
return new ValueGuess(
$mapping['length'],
Guess::HIGH_CONFIDENCE
);
}
if (isset($mapping['length'])) {
return new ValueGuess($mapping['length'], Guess::HIGH_CONFIDENCE);
}
}
}
Expand All @@ -186,6 +108,24 @@ public function guessMaxLength($class, $property)
*/
public function guessMinLength($class, $property)
{
return;
}

/**
* Returns whether Doctrine 2 metadata exists for that class
*
* @return Boolean
*/
protected function getMetadata($class)
{
if (array_key_exists($class, $this->cache)) {
return $this->cache[$class];
}

$this->cache[$class] = null;
foreach ($this->registry->getEntityManagers() as $em) {
if ($em->getConfiguration()->getMetadataDriverImpl()->isTransient($class)) {
return $this->cache[$class] = $em->getClassMetadata($class);
}
}
}
}
14 changes: 7 additions & 7 deletions src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php
Expand Up @@ -13,20 +13,20 @@

use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Bridge\Doctrine\RegistryInterface;
use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList;
use Symfony\Bridge\Doctrine\Form\EventListener\MergeCollectionListener;
use Symfony\Bridge\Doctrine\Form\DataTransformer\EntitiesToArrayTransformer;
use Symfony\Bridge\Doctrine\Form\DataTransformer\EntityToIdTransformer;
use Symfony\Component\Form\AbstractType;
use Doctrine\ORM\EntityManager;

class EntityType extends AbstractType
{
private $em;
protected $registry;

public function __construct(EntityManager $em)
public function __construct(RegistryInterface $registry)
{
$this->em = $em;
$this->registry = $registry;
}

public function buildForm(FormBuilder $builder, array $options)
Expand All @@ -46,7 +46,7 @@ public function getDefaultOptions(array $options)
$defaultOptions = array(
'multiple' => false,
'expanded' => false,
'em' => $this->em,
'em' => null,
'class' => null,
'property' => null,
'query_builder' => null,
Expand All @@ -60,7 +60,7 @@ public function getDefaultOptions(array $options)

if (!isset($options['choice_list'])) {
$defaultOptions['choice_list'] = new EntityChoiceList(
$options['em'],
$this->registry->getEntityManager($options['em']),
$options['class'],
$options['property'],
$options['query_builder'],
Expand All @@ -80,4 +80,4 @@ public function getName()
{
return 'entity';
}
}
}

3 comments on commit fbf3695

@mgatto
Copy link

@mgatto mgatto commented on fbf3695 Jun 14, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the standalone Form, I simply was trying this in Silex:

$extensions[] = new \Symfony\Bridge\Doctrine\Form\DoctrineOrmExtension($app['doctrine.orm.em']);

However, with this new registry argument, I don't understand which concrete class to instantiate which implements RegistryInterface?

@stof
Copy link
Member

@stof stof commented on fbf3695 Jun 15, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mgatto you need to write another implementation of the interface for Silex as the implementation provided here depends of the DI component

@mgatto
Copy link

@mgatto mgatto commented on fbf3695 Jun 15, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I'll give it a try and post it to the Silex project.

Please sign in to comment.