Symfony forms (as standalone component with Doctri

2019-04-29 10:27发布

I'm using Symfony forms (v3.0) without the rest of the Symfony framework. Using Doctrine v2.5.

I've created a form, here's the form type class:

class CreateMyEntityForm extends BaseFormType {

    public function buildForm(FormBuilderInterface $builder, array $options){
        $builder->add('myEntity', EntityType::class);
    }
}

When loading the page, I get the following error.

Argument 1 passed to Symfony\Bridge\Doctrine\Form\Type\DoctrineType::__construct() must be an instance of Doctrine\Common\Persistence\ManagerRegistry, none given, called in /var/www/dev3/Vendor/symfony/form/FormRegistry.php on line 85

I believe there's some configuration that needs putting in place here, but I don't know how to create a class that implements ManagerRegistryInterface - if that is the right thing to do.

Any pointers?

Edit - here is my code for setting up Doctrine

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;

class Bootstrap {

    //...some other methods, including getCredentials() which returns DB credentials for Doctrine

    public function getEntityManager($env){

        $isDevMode = $env == 'dev';

        $paths = [ROOT_DIR . '/src'];

        $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, null, null, false);

        $dbParams = $this->getCredentials($env);

        $em = EntityManager::create($dbParams, $config);

        return $em;
    }
}

3条回答
女痞
2楼-- · 2019-04-29 10:41

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');
    }

}


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

Configure the Forms to use the extension

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

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

$formFactory = $formBuilder->getFormFactory();

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]);
    }
}


$form = $formFactory->create(new \UserType, $data, $options);
查看更多
Ridiculous、
3楼-- · 2019-04-29 10:51

The easiest way to solve your issue is by registering the DoctrineOrmExtension from the Doctrine bridge which makes sure that the entity type is registered with the needed dependencies.

So basically, the process of bootstrapping the Form component would look like this:

// a Doctrine ManagerRegistry instance (you will probably already build this somewhere else)
$managerRegistry = ...;

$doctrineOrmExtension = new DoctrineOrmExtension($managerRegistry);

// the list of form extensions
$extensions = array();

// register other extensions
// ...

// add the DoctrineOrmExtension
$extensions[] = $doctrineOrmExtension;

// a ResolvedFormTypeFactoryInterface instance
$resolvedTypeFactory = ...;

$formRegistry = new FormRegistry($extensions, $resolvedTypeFactory);
查看更多
欢心
4楼-- · 2019-04-29 11:01

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!

查看更多
登录 后发表回答