Slim Framework 4 and Symfony Dependency Injection Component

Slim Framework 4 supports dependency injection containers that implement PSR-11 like Symfony DI or PHP-DI so you can choose which one to use.

In all official examples, the PHP-DI is favored against Symfony Dependency Injection Container.
PHP-DI is very nice, easy to use and “for humans” as they say. But in situations when you have multiple dependencies to be configured, the PHP-DI configuration file will become messy and not so “for humans”.

Experienced developers that have multiple frameworks working background will prefer loading config and wiring files from YAML files.

I had created a GitHub repository where I am demonstrating how easy is to use Symfony Dependency Injection Container with Slim Framework v4.

Symfony Dependency Injection Container

Symfony Dependency Injection is based on Symfony Service Container and all dependencies are configured in YAML files.

I chose to use the Symfony DOTENV package too because it is easier to change the configuration based on the environment.

/** composer.json */
"require": {
"slim/slim": "^4.1",
...
"symfony/config": "^5.0",
"symfony/dependency-injection": "^5.0",
"symfony/dotenv": "^5.0",
"symfony/yaml": "^5.0"
},

Swap the PHP-DI with the Symfony DI in the Slim Application

First, init the DotEnv and add the .env.dist file.

 
/** public/index.php */

$dotenv = new Dotenv();
$dotenv->loadEnv(__DIR__ . '/../.env');
 
/** .env.dist */

APP_ENV=dev
APP_DEBUG=true
LOGGER_NAME=slim-app
LOGGER_PATH=/var/www/logs/app.log
LOGGER_LEVEL=DEBUG

Then, move the PHP-DI from index.php file to a separate file:

/** public/index.php */

//$container = require __DIR__ . '/../app/did-container.php';
$container = require __DIR__ . '/../app/symfony-container.php';

Next, create the app/symfony-container.php file. The Symfony ConfigCache will load the already compiled container if the APP_DEBUG environment variable is set to FALSE.

 
/** app/symfony-container.php */

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
use Symfony\Component\Config\ConfigCache;

$file = __DIR__ . '/../var/cache/symfony-container.php';
$containerConfigCache = new ConfigCache($file, $_ENV['APP_DEBUG']);

if (!$containerConfigCache->isFresh()) {
    $containerBuilder = new ContainerBuilder();
    $fileLoader = new YamlFileLoader($containerBuilder, new FileLocator());
    $fileLoader->load(__DIR__ . '/settings.yaml');
    $fileLoader->load(__DIR__ . '/services.yaml');
    $containerBuilder->compile();

    $dumper = new PhpDumper($containerBuilder);
    $containerConfigCache->write(
        $dumper->dump(),
        $containerBuilder->getResources()
    );
}

require_once $file;
return new ProjectServiceContainer();

Create the setings.yaml and services.yaml files.

/** app/settings.yaml */

parameters:
  app.env: '%env(string:APP_ENV)%'
  app.debug: '%env(bool:APP_DEBUG)%'

  logger.name: '%env(string:LOGGER_NAME)%'
  logger.path: '%env(string:LOGGER_PATH)%'
  logger.level: '%env(string:LOGGER_LEVEL)%'

/** app/services.yaml */

parameters:

services:
  _defaults:
    autowire: true
    autoconfigure: true
    public: false

  App\:
    resource: '../src/*'

  Monolog\Processor\UidProcessor:
    class: \Monolog\Processor\UidProcessor
    public: true

  log_handler:
    class: \Monolog\Handler\StreamHandler
    public: true
    arguments:
      - '%logger.path%'
      - '%logger.level%'

  logger:
    class: \Monolog\Logger
    public: true
    arguments: ['%logger.name%']
    calls:
      - [pushHandler, ['@log_handler']]
      - [pushProcessor, ['@Monolog\Processor\UidProcessor']]

  App\Domain\User\UserRepository:
    class: \App\Infrastructure\Persistence\User\InMemoryUserRepository
    public: true

  App\Application\Actions\User\ListUsersAction:
    class: \App\Application\Actions\User\ListUsersAction
    public: true
    arguments:
      - '@logger'
      - '@App\Domain\User\UserRepository'

  App\Application\Actions\User\ViewUserAction:
    class: \App\Application\Actions\User\ViewUserAction
    public: true
    arguments:
      - '@logger'
      - '@App\Domain\User\UserRepository'

That’s it!

Test the following routes: home, users list, user view.

You can see all the modifications in this compared view:
https://github.com/slimphp/Slim-Skeleton/compare/master…floringavrila:master