Symfony 2: создание сервиса из репозитория

Я изучаю Symfony, и я пытаюсь создать сервис, используя репозиторий. Я создал свои репозитории и сущности из generate: entity, поэтому они должны быть в порядке.

пока что я получил в моих услугах.yml является:

parameters:
    mytest.entity: TestTestBundle:Brand
    mytest.class:  TestTestBundleEntityBrand
    default_repository.class: DoctrineORMEntityRepository

services:
     myservice:
          class: %default_repository.class%
          factory-service: doctrine.orm.default_entity_manager
          factory-method: getRepository
          arguments:
            - %mytest.entity%

но когда я пытаюсь вызвать службу, я получаю эту ошибку:

Catchable Fatal Error: Argument 2 passed to DoctrineORMEntityRepository::__construct() must be an instance of DoctrineORMMappingClassMetadata, none given, called in 

затем я попытался создать службу, просто используя сущность. Свои услуги.далее код будет выглядеть так:

services:
     myservice:
          class: %mytest.class%
          factory-service: doctrine.orm.default_entity_manager
          factory-method: getRepository
          arguments:
            - %mytest.entity%

но для этого, я получить:

Error: Call to undefined method 
                TestTestBundleEntityBrand::findAll

кто-нибудь знает, что я делаю не так?

спасибо

7 ответов


вот как мы это сделали в KnpRadBundle: https://github.com/KnpLabs/KnpRadBundle/blob/develop/DependencyInjection/Definition/DoctrineRepositoryFactory.php#L9

наконец, это должно быть:

my_service:
    class: Doctrine\Common\Persistence\ObjectRepository
    factory_service: doctrine # this is an instance of Registry
    factory_method: getRepository
    arguments: [ %mytest.entity% ]

обновление

С 2.4, учение позволяет переопределить repositor заводские.

вот возможный способ реализовать его в symfony:https://gist.github.com/docteurklein/9778800


ПРЕДУПРЕЖДЕНИЕ ОБ УСТАРЕВАНИИ: не больше factory_service и factory_method. Вот как вы должны это делать, так как Symfony 2.6 (для Symfony 3.3+ проверьте ниже):

parameters:
    entity.my_entity: "AppBundle:MyEntity"

services:
    my_entity_repository:
        class: AppBundle\Repository\MyEntityRepository
        factory: ["@doctrine", getRepository]
        arguments:
            - %entity.my_entity%

новая setFactory() метод был введен в Symfony 2.6. См. более старые версии синтаксиса для фабрик до 2.6.

http://symfony.com/doc/2.7/service_container/factories.html

EDIT: похоже, они продолжают менять это, так как Symfony 3.3 появился новый синтаксис:

# app/config/services.yml
services:
    # ...

    AppBundle\Email\NewsletterManager:
        # call the static method
        factory: ['AppBundle\Email\NewsletterManagerStaticFactory', createNewsletterManager]

проверьте это:http://symfony.com/doc/3.3/service_container/factories.html


возможно, вы использовали неправильные ключи YAML. Ваша первая конфигурация отлично работает для меня, используя

  • factory_service вместо factory-service
  • factory_method вместо factory-method

С 2017 года и Symfony 3.3+ теперь это намного проще.

Примечание: старайтесь избегать общих команд, как generate:entity. Они предназначены для нищих, чтобы заставить проект работать быстро. Они имеют тенденцию обнажать плохие практики и требуют очень много времени, чтобы измениться.

проверьте мой пост как использовать репозиторий с доктриной в качестве сервиса в Symfony для более общего описания.

в коде:

1. Обновите регистрацию конфигурации для использования авторегистрация на основе PSR-4

# app/config/services.yml
services:
    _defaults:
        autowire: true

    Test\TestBundle\:
        resource: ../../src/Test/TestBundle

2. Композиция над наследованием-создайте собственный репозиторий без прямой зависимости от доктрины

<?php

namespace Test\TestBundle\Repository;

use Doctrine\ORM\EntityManagerInterface;

class BrandRepository
{
    private $repository;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->repository = $entityManager->getRepository(Brand::class);
    }

    public function findAll()
    {
        return $this->repository->findAll();
    }
}

3. Используйте в любой службе или контроллере через инъекцию конструктора

use Test\TestBundle\Repository\BrandRepository;

class MyController
{
    /**
     * @var BrandRepository
     */
    private $brandRepository;

    public function __construct(BrandRepository $brandRepository)
    {
        $this->brandRepository = $brandRepository;
    }

    public function someAction()
    {
        $allBrands = $this->brandRepository->findAll();
        // ...
    }

}

преобразовать службу.yml для обслуживания.xml и расширение DependencyInjection обновления, все работает для меня. Я не знаю, почему, но YML config будет выброшен уловимой фатальной ошибкой. Вы можете попробовать использовать xml config для конфигурации службы.

сервис.в формате YML:

services:
    acme.demo.apikey_userprovider:
        class: Acme\DemoBundle\Entity\UserinfoRepository
        factory-service: doctrine.orm.entity_manager
        factory-method: getRepository
        arguments: [ AcmeDemoBundle:Userinfo ]

    acme.demo.apikey_authenticator:
        class: Acme\DemoBundle\Security\ApiKeyAuthenticator
        arguments: [ "@acme.demo.apikey_userprovider" ]

сервис.XML-код:

<services>
    <service id="acme.demo.apikey_userprovider" class="Acme\DemoBundle\Entity\UserinfoRepository"  factory-service="doctrine.orm.entity_manager" factory-method="getRepository">
        <argument>AcmeDemoBundle:Userinfo</argument>
    </service>

    <service id="acme.demo.apikey_authenticator" class="Acme\DemoBundle\Security\ApiKeyAuthenticator">
        <argument type="service" id="acme.demo.apikey_userprovider" />
    </service>
</services>

Symfony 3.3 и доктрина-пакет 1.8 есть Doctrine\Bundle\DoctrineBundle\Repository\ContainerRepositoryFactory что помогает создать репозиторий как сервис.

пример

что мы хотим

$rep = $kernel->getContainer()
    ->get('doctrine.orm.entity_manager')
    ->getRepository(Brand::class);

ORM описание

# Brand.orm.yaml
...
repositoryClass: App\Repository\BrandRepository
...

описание услуг

# service.yaml

App\Repository\BrandRepository:
    arguments:
      - '@doctrine.orm.entity_manager'
      - '@=service("doctrine.orm.entity_manager").getClassMetadata("App\Entity\Brand")'
    tags:
        - { name: doctrine.repository_service }
    calls:
        - method: setDefaultLocale
          arguments:
              - '%kernel.default_locale%'
        - method: setRequestStack
          arguments:
              - '@request_stack'

sf 2.6+

parameters:
    mytest.entity: TestTestBundle:Brand
    mytest.class:  Test\TestBundle\Entity\Brand
    default_repository.class: Doctrine\ORM\EntityRepository

services:
     myservice:
          class: %default_repository.class%
          factory: ["@doctrine.orm.default_entity_manager", "getRepository"]
          arguments:
            - %mytest.entity%