Cannot load DI inside controller constructor

98 Views Asked by At

I am trying to follow the Build you own framework tutorial. I get stuck when I want to use DI inside my controller.

I have found this question (Controller (Service) not having dependencies injected on Symfony project) on stack overflow that got me as far as I am now but still cannot resolve the following issue:

This is my controller

<?php

namespace App\Controllers;

use App\Models\LeapYear;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

class LeapYearController
{
    private LeapYear $model;

    public function __construct(LeapYear $model)
    {
        $this->model = $model;
    }

    public function index(int $year): JsonResponse
    {
        if ($this->model->isLeapYear($year)) {
            return new JsonResponse('Yep, this is a leap year!');
        }

        return new JsonResponse('Nope, this is not a leap year.');
    }
}

This is my model:

<?php

namespace App\Models;

class LeapYear
{
    public function isLeapYear(int $year = null): bool
    {
        if (null === $year) {
            $year = date('Y');
        }

        return 0 === $year % 400 || (0 === $year % 4 && 0 !== $year % 100);
    }
}

They are both in ./src/controllers and ./src/models

This is my container.php

<?php

use App\Controllers\LeapYearController;
use App\Models\LeapYear;
use GGPHP\Framework;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
use Symfony\Component\HttpKernel\EventListener\ResponseListener;
use Symfony\Component\HttpKernel\EventListener\RouterListener;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;

$container = new ContainerBuilder();
$loader = new YamlFileLoader($container, new FileLocator(__DIR__));
$loader->load('services.yml');

$container->register('context', RequestContext::class);
$container->register('matcher', UrlMatcher::class)
    ->setArguments([$routes, new Reference('context')]);

$container->register('request_stack', RequestStack::class);
$container->register('controller_resolver', ContainerControllerResolver::class)
    ->setArguments([$container]);
$container->register('argument_resolver', ArgumentResolver::class);

$container->register('listener.router', RouterListener::class)
    ->setArguments([new Reference('matcher'), new Reference('request_stack')]);
$container->register('listener.response', ResponseListener::class)
    ->setArguments(['UTF-8']);

$container->register('dispatcher', EventDispatcher::class)
    ->addMethodCall('addSubscriber', [new Reference('listener.router')])
    ->addMethodCall('addSubscriber', [new Reference('listener.response')]);

$container->register('framework', Framework::class)
    ->setArguments([
        new Reference('dispatcher'),
        new Reference('controller_resolver'),
        new Reference('request_stack'),
        new Reference('argument_resolver'),
    ]);

return $container;

And this is my front controller index.php

<?php

require_once dirname(__DIR__).'/vendor/autoload.php';

use Symfony\Component\HttpFoundation\Request;

$request = Request::createFromGlobals();
$routes = include dirname(__DIR__).'/routes.php';
$container = include dirname(__DIR__).'/container.php';

$response = $container->get('framework')->handle($request);
$response->send();

my services.yaml is:

services:
  App\Models\LeapYear:
    arguments:
  App\Controllers\LeapYearController:
    arguments:
      $model: '@App\Models\LeapYear'

The error I get is:

Fatal error: Uncaught ReflectionException: Class "" does not exist in C:\Users\.......\vendor\symfony\dependency-injection\ContainerBuilder.php:1131 Stack

I am not sure what to do anymore. I have removed the model from the services.yaml. Tried to load them manually by registering, but nothing works, always get this error.

1

There are 1 best solutions below

2
On BEST ANSWER

The rather obscure Class "" does not exist comes from the fact that you are not specifying the class parameter when defining your services. The Symfony framework has a bit of magic to overcome this but standalone means it is up to you.

services:
  App\Models\LeapYear:
    class: App\Models\LeapYear

  App\Controllers\LeapYearController:
    class: App\Controllers\LeapYearController
    arguments:
      $model: '@App\Models\LeapYear'

This was my original workaround which involves skipping the config file completely. You might still want to consider using it just to streamline your framework even further. No need for symfony/config or symfony/yaml with this approach.

$container = new ContainerBuilder();
//$loader = new YamlFileLoader($container, new FileLocator(__DIR__));
//$loader->load('services.yml');

$container->register(LeapYear::class,LeapYear::class);

$container->register(LeapYearController::class, LeapYearController::class)
    ->setArguments([
        new Reference(LeapYear::class)
    ]);