phpsymfonyno-framework

Symfony Components without the full stack framework


I'm using Symfony DI, Http, Kernel, Routing in my project following Create your own PHP Framework (https://symfony.com/doc/current/create_framework/index.html). It's fine and ok with is_leap_year App demo purpose.

I'm trying to figure out how I can inject services and container, into a custom controller defined in routes using only Symfony components, not framework bundle.

container.php

// add demo service into the service container
$containerBuilder->register('demo.service', '\Demo\DemoService');

// add dependent service into the controller container
$containerBuilder->register('dependent.controller', '\Demo\DemoController')
    ->setArguments([new Reference('demo.service')]);

// fetch service from the service container
// Echoing Works fine! But no service in controller
//echo $containerBuilder->get('dependent.controller')->helloWorld();

App.php

// nok with dependency
$routes->add('hello', new Routing\Route('/hello', [
    '_controller' => 'Demo\DemoController::helloWorld',
]));

// ok with no dependency
$routes->add('hello2', new Routing\Route('/hello2', [
    '_controller' => 'Demo\DemoService::helloWorld',
]));

And DemoController.php

<?php declare(strict_types=1);

namespace Demo;

class DemoController
{
  private $demo_service;

  public function __construct(\Demo\DemoService $demoService)
  {
    $this->demo_service = $demoService;
  }

  public function helloWorld()
  {
    return $this->demo_service->helloWorld();
  }
}

Returns

Fatal error: Uncaught ArgumentCountError: Too few arguments to function Demo\DemoController::__construct(), 0 passed

How can I get this working? Or, how can i inject container into the Controller Constructor ?

Example here https://github.com/Monnomcjo/symfony-simplex


Solution

  • You actually got pretty close so well done there. I think you mixed ContainerAwareInterface with the ContainerControllerResolver suggestion. Two different concepts really. Looks like you also tried making your own ControllerResolver class but you did not update container.php to use it. In any event, there is no need for a custom resolver at this point.

    I also accidentally misled you with the suggestion that there was a service called 'container'. It is actually called 'service_container'.

    # container.php
    $containerBuilder->register('container_controller_resolver', HttpKernel\Controller\ContainerControllerResolver::class)
        ->setArguments([new Reference('service_container')]); 
    
    $containerBuilder->register('framework', Framework::class)
        ->setArguments([
            new Reference('dispatcher'),
            new Reference('container_controller_resolver'), // Changed
            new Reference('request_stack'),
            new Reference('argument_resolver'),
            //new Reference('demo.service'), // No need for these
            //new Reference('dependent.controller'),
        ])
    ;
    

    Also, by convention, some of the framework services use id's like 'framework' or what not. But most of the time your application level stuff should just use the class name as the service id. In particular your need to use the controller class name to allow the ContainerControllerResolver to find it. It will also be useful when you venture into using the automatic wiring capabilities of the container.

    // add demo service into the service container
    $containerBuilder->register(\Demo\DemoService::class, \Demo\DemoService::class);
    
    // add dependent service into the controller container
    $containerBuilder->register(\Demo\DemoController::class,\Demo\DemoController::class)
        ->setArguments([new Reference(\Demo\DemoService::class)]);
    

    And that should do it. Enjoy.