Reputation: 1910
Trying to upgrade an existing Symfony 3.3.2 project to use autowiring.
Followed the instructions here: https://symfony.com/doc/current/service_container/3.3-di-changes.html#content_wrapper.
What is not working for me is being able to set all services in a directory to public.
Important: My services.yml file is in src/SiteBundle/Resources/config, not app/config.
# src/SiteBundle/Resources/config/services.yml
services:
_defaults:
autowire: true
autoconfigure: true
public: false
SiteBundle\Service:
resource: '../../Service'
public: true
CustomerOrderMasterRepository:
class: Doctrine\ORM\EntityRepository
factory: ["@doctrine.orm.entity_manager", get_repository]
arguments:
- SiteBundle\Entity\CustomerMaster
SiteBundle\Service\CustomersService:
arguments:
- '@doctrine.orm.entity_manager'
- '@CustomerMasterRepository'
If I then do a console debug:container | grep -i service, it shows only the output header and the Symfony service container. None of the classes in the src/SiteBundle/Service directory are being picked up.
Symfony Container Public Services Service ID
Class name service_container
Symfony\Component\DependencyInjection\ContainerInterface
If I add --show-private, then they are displayed (along with a lot of other stuff).
Symfony Container Public and Private Services Service ID
Class name
1_bcf140bb848ef41617942628c8525b4872574e826d00fee6aaabbf2ede89fbb8
Symfony\Component\DependencyInjection\ServiceLocator
Psr\Container\ContainerInterface
alias for "service_container"
SiteBundle\Service\CustomerOrdersService
SiteBundle\Service\CustomerOrdersService
SiteBundle\Service\CustomersService
SiteBundle\Service\CustomersService
SiteBundle\Service\InventoryItemsService
SiteBundle\Service\InventoryItemsService
SiteBundle\Service\VendorOrdersService
SiteBundle\Service\VendorOrdersService
SiteBundle\Service\VendorsService
SiteBundle\Service\VendorsService
SiteBundle\Service\WorkOrdersService
SiteBundle\Service\WorkOrdersService
Symfony\Component\DependencyInjection\ContainerInterface
alias for "service_container" argument_resolver.service
Symfony\Component\HttpKernel\Controller\ArgumentResolver\ServiceValueResolver routing.loader.service
Symfony\Component\Routing\Loader\DependencyInjection\ServiceRouterLoader security.authentication.rememberme.services.abstract
security.authentication.rememberme.services.persistent
Symfony\Component\Security\Http\RememberMe\PersistentTokenBasedRememberMeServices security.authentication.rememberme.services.simplehash
Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices service_container
Symfony\Component\DependencyInjection\ContainerInterface
service_locator.1712c3a50d1ec2c742b2ead0f03bb76c
Symfony\Component\DependencyInjection\ServiceLocator
service_locator.26ac001b3ede28481ac0de703666b4d7
Symfony\Component\DependencyInjection\ServiceLocator
service_locator.39e66930232432ca5ba91e98fdd8a17b
Symfony\Component\DependencyInjection\ServiceLocator
service_locator.6f24348b77840ec12a20c22a3f985cf7
Symfony\Component\DependencyInjection\ServiceLocator
service_locator.8925f20c49cbd61fcb37adf8c595459e
Symfony\Component\DependencyInjection\ServiceLocator
service_locator.b8d2046fb854cde05549fb309e1a80d2
alias for "1_bcf140bb848ef41617942628c8525b4872574e826d00fee6aaabbf2ede89fbb8"
service_locator.ceb8bbb9f48e8bfd1c8ec2d209eabdca
Symfony\Component\DependencyInjection\ServiceLocator
If I comment out the SiteBundle\Service\CustomerService definition, the debug:container command throws this exception:
PHP Fatal error: Uncaught Symfony\Component\DependencyInjection\Exception\AutowiringFailedException: Cannot autowire service "SiteBundle\Entity\CustomerMasterRepository": argument "$em" of method "Doctrine\ORM\EntityRepository::__construct()" must have a type-hint or be given a value explicitly. Which, frankly, I can't make heads nor tails of.
Suggestions? Thanks.
Upvotes: 2
Views: 5117
Reputation: 24280
This is the main issue:
PHP Fatal error: Uncaught Symfony\Component\DependencyInjection\Exception\AutowiringFailedException: Cannot autowire service "SiteBundle\Entity\CustomerMasterRepository": argument "$em" of method "Doctrine\ORM\EntityRepository::__construct()" must have a type-hint or be given a value explicitly. Which, frankly, I can't make heads nor tails of.
That happens, when you use EntityRepository as s service, but inherit from the Doctrine BaseRepository. This combination should never happen.
The repository should use composition, to get to Doctrine Like this:
<?php
namespace AppBundle\EntityRepository;
use AppBundle\Entity\Channel;
use Doctrine\ORM\EntityManager;
class ChannelRepository
{
private $repository;
public function __construct(EntityManager $entityManager)
{
$this->repository = entityManager->getRepository(Channel::class);
}
public function getOneByName(string $name)
{
return $this->repository->findOneBy(['name' => $name]);
}
}
There is a post with nice code examples if you want to know more: How to use Repository with Doctrine as Service in Symfony
Upvotes: 1
Reputation: 2989
To make a custom repository work I had to override the __construct
method to provide the EntityManager
and the ClassMetadata
as shown below:
app/config/services.yml
services:
_defaults:
autowire: true
autoconfigure: true
public: false
app.repository.channel:
class: \AppBundle\EntityRepository\ChannelRepository
src/AppBundle/EntityRepository/ChannelRepository.php:
<?php
namespace AppBundle\EntityRepository;
use AppBundle\Entity\Channel;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
class ChannelRepository extends RepositoryFactory
{
public function __construct(EntityManager $entityManager)
{
parent::__construct($entityManager, new ClassMetadata(Channel::class));
}
public function getOneByName(string $name)
{
return $this->findOneBy(['name' => $name]);
}
}
src/AppBundle/Entity/Channel.php
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="channel")
* @ORM\Entity(repositoryClass="\AppBundle\EntityRepository\ChannelRepository")
*
*/
class Channel
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @return int
*/
public function getId()
{
return $this->id;
}
}
Upvotes: 0