Symfony 2: создание службы из репозитория
Я изучаю Symfony, и я пытаюсь создать службу, используя репозиторий.
Я создал свои репозитории и сущности из generate: entity, поэтому они должны быть в порядке.
До сих пор, что я получил в моих services.yml:
parameters:
mytest.entity: TestTestBundle:Brand
mytest.class: Test\TestBundle\Entity\Brand
default_repository.class: Doctrine\ORM\EntityRepository
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 Doctrine\ORM\EntityRepository::__construct() must be an instance of Doctrine\ORM\Mapping\ClassMetadata, none given, called in
Затем я попытался создать сервис, используя только объект. Мои services.yml будут выглядеть так:
services:
myservice:
class: %mytest.class%
factory-service: doctrine.orm.default_entity_manager
factory-method: getRepository
arguments:
- %mytest.entity%
Но для этого я получаю:
Error: Call to undefined method
Test\TestBundle\Entity\Brand::findAll
Кто-нибудь знает, что я делаю неправильно?
Спасибо
Ответы
Ответ 1
Вот как мы это сделали в 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% ]
UPDATE
Начиная с версии 2.4 доктрина позволяет переопределить репозиторий по умолчанию factory.
Вот возможный способ реализовать его в symfony: https://gist.github.com/docteurklein/9778800
Ответ 2
ПРЕДУПРЕЖДЕНИЕ О ДЕПРЕКАЦИИ: Больше 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%
В Symfony 2.6 был введен новый метод setFactory(). Обратитесь к старым версиям для синтаксиса для фабрик до 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
Ответ 3
Возможно, вы использовали неправильные клавиши YAML. Ваша первая конфигурация работает отлично для меня, используя
- factory_service вместо factory -сервис
- factory_method вместо factory -method
Ответ 4
С 2017 года и Symfony 3.3 + теперь это намного проще.
Примечание. Старайтесь избегать общих команд типа generate:entity
. Они предназначены для начинающих, чтобы сделать работу над проектом быстрой. Они склонны огорчать плохие практики и очень долгое время менять.
Отметьте мой пост Как использовать репозиторий с Doctrine как услугу в Symfony для более общего описания.
К вашему коду:
1. Обновите свою регистрацию конфигурации, чтобы использовать Автозагрузка на основе PSR-4
# app/config/services.yml
services:
_defaults:
autowire: true
Test\TestBundle\:
resource: ../../src/Test/TestBundle
2. Композиция над наследованием - Создайте собственный репозиторий без прямой зависимости от Doctrine
<?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();
// ...
}
}
Ответ 5
Я конвертирую service.yml в service.xml и обновляю ExtendencyInjection Extension, все работает для меня. Я не знаю, почему, но yml config будет выброшен Catchable Fatal Error. Вы можете попробовать использовать конфигурацию xml для конфигурации службы.
service.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" ]
service.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>
Ответ 6
Symfony 3.3 и doctrine-bundle 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'
Ответ 7
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%