Symfony forms (as standalone component with Doctrine) EntityType not working

Believe me, you're asking for trouble!

EntityType::class works when it is seamsly integrated to "Symfony" framework (there's magic under the hoods - via DoctrineBundle). Otherwise, you need to write a lot of code for it to work properly.
Not worth the effort!

It's a lot easier if you to create an entity repository and inject it in form constructor, then use in a ChoiceType::class field. Somethink like this:

<?php
# you form class
namespace Application\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class InvoiceItemtType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('product', ChoiceType::class, [
            'choices' => $this->loadProducts($options['products'])
        ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(['products' => [],]); # custom form option
    }

    private function loadProducts($productsCollection)
    {
        # custom logic here (if any)
    }
}

And somewhere in application:

$repo = $entityManager->getRepository(Product::class);
$formOptions = ['products' => $repo->findAll()];
$formFactory = Forms::createFormFactory();
$formFactory->create(InvoiceItemtType::class, new InvoiceItem, $formOptions);

That's the point!


Expanding on the answer by xabbuh.

I was able to implement EntityType in the FormBuilder without too much extra work. However it does not work with the annotations in order to use Constraints directly inside the entity, which would require a lot more work.

You can easily facilitate the ManagerRegistry requirement of the Doctrine ORM Forms Extension, by extending the existing AbstractManagerRegistry and making your own container property within the custom ManagerRegistry.

Then it's just a matter of registering the Form extension just like any other extension (ValidatorExtension, HttpFoundationExtension, etc).

The ManagerRegistry

use \Doctrine\Common\Persistence\AbstractManagerRegistry;

class ManagerRegistry extends AbstractManagerRegistry
{

    /**
     * @var array
     */
    protected $container = [];

    public function __construct($name, array $connections, array $managers, $defaultConnection, $defaultManager, $proxyInterfaceName)
    {
        $this->container = $managers;
        parent::__construct($name, $connections, array_keys($managers), $defaultConnection, $defaultManager, $proxyInterfaceName);
    }

    protected function getService($name)
    {   
        return $this->container[$name];
       //alternatively supply the entity manager here instead
    }

    protected function resetService($name)
    {
        //unset($this->container[$name]);
        return; //don't want to lose the manager
    }


    public function getAliasNamespace($alias)
    {
        throw new \BadMethodCallException('Namespace aliases not supported');
    }

}

Create the Form

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class UserType extends AbstractType 
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
       $builder->add('field_name', EntityType::class, [
           'class' => YourEntity::class,
           'choice_label' => 'id'
       ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
       $resolver->setDefaults(['data_class' => YourAssociatedEntity::class]);
    }
}

Configure the Form Builder to use the extension and use the Form

$managerRegistry = new \ManagerRegistry('default', [], ['default' => $entityManager], null, 'default', 'Doctrine\\ORM\\Proxy\\Proxy');

$extension = new \Symfony\Bridge\Doctrine\Form\DoctrineOrmExtension($managerRegistry);

$formBuilder = \Symfony\Component\Form\FormFactoryBuilder::createFormFactoryBuilder();
$formBuilder->addExtension($extension);

$formFactory = $formBuilder->getFormFactory();

$form = $formFactory->create(new \UserType, $data, $options);

The above is intended for demonstration purposes only! While it does function, it is considered best practice to avoid using Doctrine Entities inside of Forms. Use a [DTO (Data Transfer Object) instead.

Doctrine 2.5+ "NEW" Operator Syntax

class CustomerDTO
{
    public function __construct($name, $email, $city, $value = null)
    {
        // Bind values to the object properties.
    }
}
$query = $em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city) FROM Customer c JOIN c.email e JOIN c.address a');
$users = $query->getResult(); // array of CustomerDTO