【问题标题】:Symfony2 Form Events Listener and Data Transformer Error Cannot instantiate interface Doctrine\....\ObjectManagerSymfony2 表单事件侦听器和数据转换器错误无法实例化接口 Doctrine\....\ObjectManager
【发布时间】:2016-01-21 14:35:56
【问题描述】:

我正在开发一个 Symfony 2.3 表单,它要求一个字段只能在“创建新”模式下使用。

该字段是多对一关系中的链接,我已经设法通过使用 jQuery AutoComplete 更改下拉列表,以便通过 FormEvents::PRE_SET_DATA 事件使用,但是 FormEvents::PRE_SUBMIT 是将提供的 ID 转换为对象需要 Doctrine ObjectManager。 转为接口,抛出'Cannot instantiate interface Doctrine\Common\Persistence\ObjectManager'
我已经查看了以下类似的问题和文档(Form EventsForm Events DropdownDoctrine Data TransformerDynamic Form Modification),但是已经接近尾声(而且是 php 和 symfony 的新手)我不想重新- 写这篇文章。

您可以在下面找到我的事件侦听器和数据转换器类:

namespace XXXXXXXBundle\Form\EventListener;

use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use XXXXXXXXXXXXXBundle\Form\DataTransformer\rneToEcoleTransformer;

class AddFieldSubscriber implements EventSubscriberInterface {

private $manager;

public static function getSubscribedEvents() {
    // Tells the dispatcher that you want to listen on the form.pre_set_data
    // event and that the preSetData method should be called.
    return array(\Symfony\Component\Form\FormEvents::PRE_SET_DATA => 'preSetData',
        \Symfony\Component\Form\FormEvents::PRE_SUBMIT => 'preSubmit');
}

public function preSetData(\Symfony\Component\Form\FormEvent $event) {
    $parents = $event->getData();
    $form = $event->getForm();

    //Verifie si le parent d'eleve est un nouveau 
    //ou s'il s'agit d' une mise à jour
    if (!$parents || null === $parents->getId()) {
        $form->add('ecole', 'text', array('invalid_message' => 'Ce RNE n\'est pas valide',
            'attr' => array('data-id' => 'ecoles',
                'data-url' => 'parents_json_ecoles'
            )
                )
        );
    }
}

public function preSubmit(\Symfony\Component\Form\FormEvent $event) {
    $this->manager = new \Doctrine\Common\Persistence\ObjectManager;

    $parents = $event->getData();
    if (empty($parents['ecole'])) {
        return;
    }
    $event->getForm()->get('ecole')->getConfig()->addModelTransformer(new rneToEcoleTransformer($this->manager));
}}

namespace XXXXXXXBundle\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;

class rneToEcoleTransformer implements DataTransformerInterface {

private $manager;

public function __construct(\Doctrine\Common\Persistence\ObjectManager $manager) {
    $this->manager = $manager;
}


public function transform($ecole) {
    if (null === $ecole) {
        return '';
    }
    return $ecole->getRne();
}


public function reverseTransform($rneNumber) {
    if (!$rneNumber) {
        return;
    }

    $ecole = $this->manager
            ->getRepository('XXXXXXXBundle:Ecole')
            ->find($rneNumber);
    if (null === $ecole) {
          throw new TransformationFailedException(sprintf(
                'No matching data was found "%s" !', $rneNumber
        ));
    }

    return $ecole;
}}

这是使用的操作:

private function createCreateForm(Parents $entity) {
    $manager = $this->getDoctrine()->getManager();
    $form = $this->createForm(new ParentsType($manager), $entity, array(
        'action' => $this->generateUrl('parents_create'),
        'method' => 'POST',
    ));

    $form->add('submit', 'submit', array('label' => 'Add'));

    return $form;
}

表单类型:

class XXXXType extends AbstractType {

private $manager;

public function __construct(\Doctrine\Common\Persistence\ObjectManager $manager) {
    $this->manager = $manager;
}

/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder
            ->add('nom', 'text', array('label' => 'Nom *',
                'attr' => array('placeholder' => 'Nom ',
                    'maxlength' => 250,
                    'trim' => true)
                    )
            )
            ->add('prenoms', 'text', array('label' => 'Prénom(s) *',
                'attr' => array('placeholder' => 'Prénom(s)',
                    'maxlength' => 250,
                    'trim' => true)
                    )
            )
            ->add('date_de_naiss', 'date', array('widget' => 'single_text', 'format' => 'dd-MM-yyyy',
                'label' => 'Date de naissance ',
                'required' => false, 'data' => null,
                'attr' => array('name' => 'datepicker')
                    )
            )
            ->add('telephone', 'text', array('label' => 'Telephone *',
                'attr' => array('placeholder' => '123-456-7890 or 1234567890')
                    )
            )
            ->add('email', 'email', array('attr' => array('placeholder' => 'xxxx@xxxx.com',),
                'trim' => true,
                'required' => false,
                'data' => null
                    )
                  );


    $builder->addEventSubscriber(new AddFieldSubscriber($manager));
}

/**
 * @param OptionsResolverInterface $resolver
 */
public function setDefaultOptions(OptionsResolverInterface $resolver) {
    $resolver->setDefaults(array(
        'data_class' => 'XXXXXXBundle\Entity\Parents'
    ));
}

/**
 * @return string
 */
public function getName() {
    return 'XXXXXXXXXsbundle_parents';
}

}

【问题讨论】:

  • 你的服务文件中这个订阅者的定义是什么?您应该从容器中获取 ObjectManager 实例并将其注入到 AddFieldSubscriber 构造函数中。
  • 我还没有使用服务文件,但正在研究它
  • 你在哪里定义这个类是订阅者?以编程方式?
  • 是的,基于此symfony.com/doc/current/cookbook/form/…以编程方式进行
  • 好的,在这种情况下,您必须将 ObjectManager 传递给表单构造函数,然后将其注入您的 AddFieldSubscriber

标签: php jquery symfony doctrine-orm doctrine


【解决方案1】:

试试这个:

class AddFieldSubscriber implements EventSubscriberInterface {

   private $manager;

   public function __constructor(ObjectManager $manager){
      $this->manager = $manager;
   }
   .
   .
   .
}

在你的 service.yml 定义中:

<service_name>:
      class: XXXXXXXBundle\Form\EventListener\AddFieldSubscriber
      arguments: ["@doctrine.orm.entity_manager"]
      tags:
        - { name: kernel.event_subscriber }

如果您打算只使用 ObjectManager 中的一个存储库,我建议您只注入这个特定的存储库。

在这种情况下,您的班级将更改为:

class AddFieldSubscriber implements EventSubscriberInterface {

   private $ecoleRepository;

   public function __constructor(EntityRepository $ecoleRepository){
      $this->ecoleRepository = $ecoleRepository;
   }
   .
   .
   .
}

在你的 service.yml 中:

xxx.ecole.repository:
    class: Doctrine\ORM\EntityRepository
    factory_service: doctrine.orm.default_entity_manager
    factory_method: getRepository
    arguments:
        - XXXXXXXBundle\Entity\Ecole

<service_name>:
      class: XXXXXXXBundle\Form\EventListener\AddFieldSubscriber
      arguments: ["@xxx.ecole.repository"]
      tags:
        - { name: kernel.event_subscriber }

【讨论】:

  • 在我的控制器中是否必须使用 Service.yml,我在 creaeteForm 方法中包含了`$manager = $this->getDoctrine()->getManager();`。跨度>
  • 这不是强制性的,但它使复杂对象的实例化保持简单。在订阅者的情况下,您必须在某处(DependencyInjection 文件夹中的类、service.yml 或 service.xml)定义它是 event_subscriber,否则在调度事件时它不会被激活。
  • 容器服务还可以帮助您不重复自己(DRY)。但要小心,因为如果你定义了很多服务,service.yml 文件往往会变得一团糟。
  • 这篇文章解释了如何在所有这三种方法中注册订阅者symfony.com/doc/2.4/cookbook/doctrine/…
【解决方案2】:

我终于设法通过使用数据转换器而不是事件订阅者来使其工作,如下所示:
`

class ParentsType extends AbstractType {

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options) {

       $builder
                ->add('nom', 'text', array('label' => 'Nom *',
                    'attr' => array('placeholder' => 'Nom du Parent d\'élève',
                        'maxlength' => 250,
                        'trim' => true)
                        )
                )
                ->add('prenoms', 'text', array('label' => 'Prénom(s) *',
                    'attr' => array('placeholder' => 'Prénom(s) du parent d\' élève',
                        'maxlength' => 250,
                        'trim' => true)
                        )
                )
                ->add('date_de_naiss', 'date', array('widget' => 'single_text', 'format' => 'dd-MM-yyyy',
                    'label' => 'Date de naissance ',
                    'required' => false, 'data' => null,
                    'attr' => array('name' => 'datepicker')
                        )
                )
                ->add('telephone', 'text', array('label' => 'Telephone *',
                    'attr' => array('placeholder' => '123-456-7890 or 1234567890')
                        )
                )
                ->add('email', 'email', array('attr' => array('placeholder' => 'xxxx@xxxx.com',),
                    'trim' => true,
                    'required' => false,
                    'data' => null
                                 )
                    );
      $entityManager = $options['em'];
      $transformer = new idToEcoleTransformer($entityManager);

      $builder->add(
            $builder->create('ecole','text',array('required' => true,
                                                  'attr' => array( 'data-id'=>'ecoles',
                                                                    'data-url'=>'parents_json_ecoles',)
                                                  )
                             )->addModelTransformer($transformer)
            );


  }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'XXXXXXXXBundle\Entity\Parents',
            'csrf_protection'   => false,
            'validation_groups' => array('filtering')
        ));
        $resolver->setRequired(array('em'));
        $resolver->setAllowedTypes(array('em'=>'Doctrine\Common\Persistence\ObjectManager',));
    }

    /**
     * @return string
     */
    public function getName() {
        return 'parentsbundle_parents';
    }

`

有了这个,我不需要通过构造函数传递 ObjectManager,而只是使用 Resolver

【讨论】:

    猜你喜欢
    • 2019-12-02
    • 1970-01-01
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 2021-11-04
    • 1970-01-01
    • 2013-10-23
    • 2023-04-03
    相关资源
    最近更新 更多