0

I have a Symfony 5.3 project with two custom reusabale bundles.

I have created an Entity in bundle1, I want to be able to read and write to this from within bundle2

However, I cannot successfully include the Doctrine in any of my bundle controllers.

I have tried everything: extending the Controller, extending AbstractController, adding a constructor to pass the doctrine, defining controller as a service but I cant get anything working.

project/bundle1/src/Controller/testController.php:

namespace Bundle1\TestController;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;
use Bundle1\Entity;


class TestController 
{

private $entityManager;

public function __construct( EntityManagerInterface $entityManager) {
        $this->em = $entityManager;
}

     /**
     * @Route("/list", name="list")
     */
    public function listingsAction(): Response
    {


    //$this->em = $this->getDoctrine()->getManager();

    return new Response(
            '<html><body><h1>List from DB</h1> 
            
            </body></html>'
        );
    }
}

Error:

The controller for URI "/list" is not callable: Controller "Bundle1\TestController\TestController" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?

EDIT** The below has been amended according to help from @Cerad but unfortunately the same error message persists.

I am using autowiring and I have the following services.xml being loaded via dependency injection:

project/bundle1/Resources/config/services.xml:

        <?xml version="1.0" encoding="UTF-8" ?>
        <container xmlns="http://symfony.com/schema/dic/services"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://symfony.com/schema/dic/services
                https://symfony.com/schema/dic/services/services-1.0.xsd">
 <services>
             <service 
                id="Bundle1\Controller\TestController\TestController" 
               public="true">
     <call method="setContainer">
                <argument type="service" id="doctrine.orm.entity_manager"/>
     </call>
                <tag name="controller.service_arguments"/>
            </service>
</services>
        </container>

I have used annotaions for routing

project/config/routes/annotations.yaml file:

controllers-bundle1:
    resource: ../../bundle1/src/Controller/
    type: annotation

When I run php bin/console debug:container 'bundle1.controller.test_controller' in the console, I get:

No services found that match "bundle1.controller.test_controller".

project/bundle1/src/Bundle1.php

namespace Bundle1;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class Bundle1 extends Bundle
{
    public function getPath(): string
    {
        return \dirname(__DIR__);
    }
}

project/config/bundles.php

return [
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
    Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
    Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
    Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
    Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
    Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
    Bundle1\Bundle1::class => ['all' => true],
];

It seems to be that I have not correctly defined my controllers as services but cannot find clear information in the documentation on how to do this.

**UPDATE:


just found this in the error stack**

ArgumentCountError Too few arguments to function Bundle1\TestController\TestController::__construct(), 0 passed in /home/Project/vendor/symfony/http-kernel/Controller/ControllerResolver.php on line 147 and exactly 1 expected

in bundle1/src/Controller/TestController.php (line 17) class TestController { private $entityManager; public function __construct( EntityManagerInterface $entityManager) { $this->em = $entityManager;

10
  • You need to define the required arguments in the service definition, in your configuration file. Commented Aug 18, 2021 at 11:24
  • symfony.com/doc/current/… Commented Aug 18, 2021 at 11:30
  • Thanks but I have read that page so many times I have lost count and I still am none the wiser as to exactly what I need to add and to where. Please show using my code. Commented Aug 18, 2021 at 12:17
  • 1
    @LeeTee I know the docs are very confusing. This answer is one approach. You will need to extend the AbstractController class to make it work. It violates some of the recommended practices but it is better than floundering around. Commented Aug 18, 2021 at 12:24
  • 1
    @LeeTee In the Symfony docs, most of the container service definitions have tabs which allow you to switch between yaml, xml or php. Most of the internal Symfony stuff now uses php. I have also converted much of my own code to it. Bit verbose perhaps but it has the advantage of being a programing language. Otherwise I just use yaml. Too many traumatic xml memories from the 90s. It's always up to you unless you want to contribute to the core framework. Commented Aug 18, 2021 at 13:18

1 Answer 1

0

Let's start with an actual answer that matches the 'best practices' and then discuss a bit.

class TestController // Should not extend anything for bundle controllers
{
    // All services should be injected
    public function __construct(private EntityManagerInterface $em)
...
# Resources/config/services.xml
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        https://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service 
            id="my_bundle.controller.test_controller" 
            class="MyBundle\Controller\TestController" 
            public="true">
            <argument type="service" id="doctrine.orm.entity_manager"/>
            <tag name="controller.service_arguments"/>
        </service>
    </services>
</container>

# and since snake case service ids are recommended
# config/routes.yaml

bundle_test:
    path: /
    controller: my_bundle.controller.test_controller::index

That should give you a working page with the entity manager injected.

We use xml here because it was used in the question but php might be better. The web-profiler-bundle is a good example.

Instead of using the controller class name as the service id we spell one out per the recommended practices. Your routes will need to use it.

The public=true is very important. Symfony uses a container aware controller resolver and ultimately pulls the controller service from the container. So controller services must be public.

The tag is needed if you need to inject services into the action methods. Not sure if you are supposed to do this with bundles or not. If you don't need it then remove it.

And of course you need to manually inject any services or parameters. The container docs have more examples.

Some alternative approaches are discussed here.

Sign up to request clarification or add additional context in comments.

12 Comments

Ok I implemented the above but still get the same error, "The controller for URI "/test" is not callable: Controller "Bundle1\TestController\TestController" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?" :(
You did not make the controller service public. Use bin/console debug:container TestController to verify. And if you used the snake case service id as shown in the answer then you need to update your route to use it as well.
Yes it is public so must be the routing. And yes I used the snake case ID as you showed, So where do I add the snake case service ID? In Resources/Config/routes.yaml of the bundle?
Still no joy, I have updated the original question to replct changes t my code in case I have done something stupid. Which will proabbly be the case!
Probably time for a break. If you are determined to use annotations (not recommended for bundles) then just use the controller class name for the service id. Once you get something working then things will probably click into place.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.