简体   繁体   中英

Symfony2 FormType Dependency Injection

I have used DI in Controller, Repository. All repository extend with BaseRepository. But when using a FormType gives the error. Error Message:

ContextErrorException: Catchable Fatal Error: Argument 2 passed to Personal\SiteBundle\Repository\BaseRepository::__construct() must be an instance of Memcache, instance of Doctrine\ORM\Mapping\ClassMetadata given, called in /home/personal/www/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php on line 75 and defined in /home/personal/www/src/Personal/SiteBundle/Repository/BaseRepository.php line 22

How do I think? Structure as follows

AdminBundle/services.yml

personaladmin.towncontroller:
    class: Personal\AdminBundle\Controller\TownController
    arguments: ["@personalsite.townrepository", "@doctrine.orm.entity_manager", "@personalsite.townformtype"]
    parent: "personaladmin.basecontroller"

SiteBundle/services.yml

services:
memcache:
    class: Memcache
    calls:
        - [addServer , [127.0.0.1, 11211]]
personalsite.baserepository:
    class: Personal\SiteBundle\Repository\BaseRepository
    arguments:
        entityManager: "@doctrine.orm.entity_manager"
        memcacheProvider: "@memcache"
personalsite.cityrepository:
    class: Personal\SiteBundle\Repository\CityRepository
    parent: personalsite.baserepository
personalsite.townrepository:
    class: personal\SiteBundle\Repository\TownRepository
    parent: personalsite.baserepository

personalsite.townformtype:
        class: personal\SiteBundle\Form\TownType
        arguments: ["@personalsite.cityrepository"]

BaseRepository.php

    <?php
namespace Personal\SiteBundle\Repository;

use Doctrine\ORM\EntityManager;
use \Memcache;

class BaseRepository
{

    protected $_memcacheProvider;

    /**
     * Connection
     *
     * @var \Doctrine\ORM\EntityManager
     */
    protected $_em;

    public function __construct(
        EntityManager $entityManager,
        Memcache $memcachedProvider
    )
    {
        $this->_memcacheProvider = $memcachedProvider;
        $this->_em  = $entityManager;
    }

}

TownController.php

<?php

namespace Personal\AdminBundle\Controller;

use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;


use Symfony\Component\HttpFoundation\Request;
use Personal\AdminBundle\Controller\BaseController;
use Personal\SiteBundle\Form\TownType;
use Personal\SiteBundle\Entity\Town;
use Personal\SiteBundle\Repository\TownRepository;

/**
 * @Route("/town", service="personaladmin.towncontroller")
 */
class TownController extends BaseController
{

    protected $_townRepository;
    protected $_entityManager;

    public function __construct(
        TownRepository $townRepository,
        EntityManager $entityManager,
        TownType $townType
    )
    {
        $this->_townRepository  = $townRepository;
        $this->_entityManager   = $entityManager;
        $this->_townType        = $townType;
    }

    /**
     * @Route("/list", name="managerv3_town_list")
     * @Template()
     */
    public function townsAction()
    {
        $contents = $this->_townRepository->getAll();

        return $this->render('PersonalAdminBundle:Town:list.html.twig', array('contents' => $contents));
    }

    /**
     * @Route("/add", name="managerv3_town_add", defaults={"id" = null})
     * @Route("/edit/{id}", name="managerv3_town_edit", defaults={"id" = null})
     * @Template()
     */
    public function townAction(Request $request, $id)
    {
        if( is_null($id) )
        {
            $content = new Town();
        }
        else
        {
            $content = $this->_townRepository->getSingle(array( 'id' => $id ));
        }
        $form = $this->createForm($this->_townType, $content);

        if($request->getMethod() == 'POST')
        {
            $form->bind($request);
            if($form->isValid())
            {
                $this->_entityManager->persist($content);
                $this->_entityManager->flush();
                return $this->redirect( $this->generateUrl('managerv3_town_list') );
            }
        }

        return $this->render('PersonalAdminBundle:Town:form.html.twig', array('form' => $form->createView()));
    }

TownRepository.php

<?php

namespace Personal\SiteBundle\Repository;

use Doctrine\ORM\EntityRepository;
use Personal\SiteBundle\Repository\BaseRepository;
use Doctrine\ORM\Query;

/**
 * TownRepository
 *
 * This class was generated by the Doctrine ORM. Add your own custom
 * repository methods below.
 */
class TownRepository extends BaseRepository
{
    function getAll( $orderBy = array('town.title' => 'ASC'), $hydrateMode = false )
    {
        $towns =
            $this->_em
                ->createQueryBuilder()
                ->select('town,city')
                ->from('PersonalSiteBundle:Town', 'town')
                ->leftJoin('town.city','city');

        foreach( $orderBy as $oKey => $oVal )
        {
            $towns->orderBy($oKey, $oVal);
        }

        $result = $towns->getQuery()
            ->getResult();

        return $result;
    }

    function getSingle( $where = array(), $hydrateMode = null )
    {
        $content =
            $this->_em
                ->createQueryBuilder()
                ->select('town,city')
                ->from('PersonalSiteBundle:Town', 'town')
                ->leftJoin('town.city', 'city');

        foreach( $where as $condKey => $condVal )
        {
            $parameterKey = 'town_' . $condKey;

            $content->andWhere("town.{$condKey} = :{$parameterKey}");
            $content->setParameter($parameterKey, $condVal);
        }

        $result = $content->getQuery();

        if( $hydrateMode )
            return $result->getSingleResult(Query::HYDRATE_ARRAY);

        return $result->getSingleResult();
    }

}

TownType.php

<?php

namespace Personal\SiteBundle\Form;

use Personal\SiteBundle\Repository\CityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Personal\SiteBundle\Entity\City;

class TownType extends AbstractType
{
    private $_cityrepository;
    public function __construct(CityRepository $cityRepository)
    {
        $this->_cityrepository = $cityRepository;
    }

     /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title', 'text', array(
                'label' => 'İlçe Adı',
                'horizontal_label_class' => 'col-lg-2',
                'horizontal_input_wrapper_class' => 'col-lg-6',
                'widget_type' => 'inline'
            ))
            ->add('slug')
            ->add('city', 'entity', array(
                'empty_value'   => 'Şehir Seçiniz',
                'class' => 'PersonalSiteBundle:City',
                'query_builder' => function(){
                    return $this->_cityrepository->getAll();
                },
                'property' => 'title',
                'label' => 'Şehir',
                'horizontal_label_class' => 'col-lg-2',
                'horizontal_input_wrapper_class' => 'col-lg-3',
            ))
        ;
    }

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

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

Thanks for your help.

So your BaseRepository needs to extend DoctrineReposotory. Doctrine creates repositories using a factory getRepository method. There is no easy way to coax it to pass memcache along. Instead we need to use setter injection.

use Doctrine\ORM\EntityRepository;
class BaseRepository extends EntityRepository
{
    // No constructor needed

    // Setter injection
    setMemcachedProvider(Memcache $memcachedProvider)
    {
        $this->_memcacheProvider = $memcachedProvider;
    }

In your services.yml file get rid of the BaseRepository services and then edit your repository services:

personalsite.cityrepository:
    class: Personal\SiteBundle\Repository\CityRepository
    factory_service: 'doctrine.orm.default_entity_manager'
    factory_method:  'getRepository'
    arguments:  
        - 'Personal\SiteBundle\Entity\City'
    calls:
         - [setMemcachedProvider, ['@memcache']]

That should do the trick.

I am a little bit curious as to why you are injecting memcache. I am assuming you have some custom repository code that uses it? Doctrine will ignore it. If you are trying to configure Doctrine to use memcache then that is a different process altogether.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM