Container.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\App;
  4. use App\Application\Admin\MeController;
  5. use App\Application\Auth\AuthController;
  6. use App\Domain\Auth\Role;
  7. use App\Domain\Auth\TokenHasher;
  8. use App\Domain\Auth\TokenIssuer;
  9. use App\Infrastructure\Auth\RoleMappingRepository;
  10. use App\Infrastructure\Auth\ServiceTokenBootstrap;
  11. use App\Infrastructure\Auth\TokenRepository;
  12. use App\Infrastructure\Auth\UserRepository;
  13. use App\Infrastructure\Db\ConnectionFactory;
  14. use App\Infrastructure\Http\JsonErrorHandler;
  15. use App\Infrastructure\Http\Middleware\ImpersonationMiddleware;
  16. use App\Infrastructure\Http\Middleware\TokenAuthenticationMiddleware;
  17. use function DI\autowire;
  18. use DI\ContainerBuilder;
  19. use function DI\factory;
  20. use Doctrine\DBAL\Connection;
  21. use Monolog\Formatter\JsonFormatter;
  22. use Monolog\Handler\StreamHandler;
  23. use Monolog\Logger;
  24. use Psr\Container\ContainerInterface;
  25. use Psr\Http\Message\ResponseFactoryInterface;
  26. use Psr\Log\LoggerInterface;
  27. use Slim\Psr7\Factory\ResponseFactory;
  28. /**
  29. * Builds the api's DI container.
  30. *
  31. * Adds in M03: token domain helpers, repositories, middlewares, the JSON
  32. * error handler, and the controllers. Wiring is autowire-friendly except
  33. * where we need to inject a primitive (the OIDC default Role) or pull a
  34. * value out of `settings`.
  35. */
  36. final class Container
  37. {
  38. /**
  39. * @param array<string, mixed>|null $settings Optional override (tests pass in fixtures).
  40. */
  41. public static function build(?array $settings = null): ContainerInterface
  42. {
  43. $settings ??= require __DIR__ . '/../../config/settings.php';
  44. $builder = new ContainerBuilder();
  45. $builder->useAutowiring(true);
  46. $builder->addDefinitions([
  47. 'settings' => $settings,
  48. 'settings.db' => $settings['db'],
  49. 'settings.ui_service_token' => $settings['ui_service_token'] ?? '',
  50. 'settings.app_env' => $settings['app_env'] ?? 'production',
  51. 'settings.log_level' => $settings['log_level'] ?? \Monolog\Level::Info,
  52. 'settings.oidc_default_role' => $settings['oidc_default_role'] ?? Role::Viewer,
  53. ConnectionFactory::class => factory(static function (ContainerInterface $c): ConnectionFactory {
  54. /** @var array{driver: string, sqlite_path: string, mysql_host: string, mysql_port: int, mysql_database: string, mysql_username: string, mysql_password: string} $db */
  55. $db = $c->get('settings.db');
  56. return new ConnectionFactory($db);
  57. }),
  58. Connection::class => factory(static function (ContainerInterface $c): Connection {
  59. /** @var ConnectionFactory $factory */
  60. $factory = $c->get(ConnectionFactory::class);
  61. return $factory->create();
  62. }),
  63. LoggerInterface::class => factory(static function (ContainerInterface $c): LoggerInterface {
  64. $logger = new Logger('api');
  65. /** @var \Monolog\Level $level */
  66. $level = $c->get('settings.log_level');
  67. $handler = new StreamHandler('php://stdout', $level);
  68. $handler->setFormatter(new JsonFormatter());
  69. $logger->pushHandler($handler);
  70. return $logger;
  71. }),
  72. ResponseFactoryInterface::class => autowire(ResponseFactory::class),
  73. TokenHasher::class => autowire(),
  74. TokenIssuer::class => autowire(),
  75. TokenRepository::class => autowire(),
  76. RoleMappingRepository::class => autowire(),
  77. UserRepository::class => autowire(),
  78. ServiceTokenBootstrap::class => autowire(),
  79. TokenAuthenticationMiddleware::class => autowire(),
  80. ImpersonationMiddleware::class => autowire(),
  81. JsonErrorHandler::class => factory(static function (ContainerInterface $c): JsonErrorHandler {
  82. /** @var ResponseFactoryInterface $factory */
  83. $factory = $c->get(ResponseFactoryInterface::class);
  84. /** @var LoggerInterface $logger */
  85. $logger = $c->get(LoggerInterface::class);
  86. return new JsonErrorHandler(
  87. $factory,
  88. $logger,
  89. $c->get('settings.app_env') === 'development',
  90. );
  91. }),
  92. AuthController::class => factory(static function (ContainerInterface $c): AuthController {
  93. /** @var Role|null $role */
  94. $role = $c->get('settings.oidc_default_role');
  95. /** @var UserRepository $users */
  96. $users = $c->get(UserRepository::class);
  97. return new AuthController($users, $role ?? Role::Viewer);
  98. }),
  99. MeController::class => autowire(),
  100. ]);
  101. return $builder->build();
  102. }
  103. }