first commit
This commit is contained in:
195
config/container.php
Normal file
195
config/container.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Définitions PHP-DI.
|
||||
*
|
||||
* Ce fichier déclare uniquement ce que l'autowiring ne peut pas résoudre seul :
|
||||
* - Bindings interface → classe concrète
|
||||
* - Classes nécessitant des paramètres scalaires issus de .env ou de chemins filesystem
|
||||
*
|
||||
* Tout le reste (services, repositories, contrôleurs dont toutes les dépendances
|
||||
* sont typées sur des interfaces) est résolu automatiquement par l'autowiring.
|
||||
*/
|
||||
|
||||
use App\Auth\AuthService;
|
||||
use App\Auth\AuthServiceInterface;
|
||||
use App\Auth\LoginAttemptRepository;
|
||||
use App\Auth\LoginAttemptRepositoryInterface;
|
||||
use App\Auth\PasswordResetController;
|
||||
use App\Auth\PasswordResetRepository;
|
||||
use App\Auth\PasswordResetRepositoryInterface;
|
||||
use App\Auth\PasswordResetService;
|
||||
use App\Auth\PasswordResetServiceInterface;
|
||||
use App\Category\CategoryRepository;
|
||||
use App\Category\CategoryRepositoryInterface;
|
||||
use App\Category\CategoryService;
|
||||
use App\Category\CategoryServiceInterface;
|
||||
use App\Media\MediaRepository;
|
||||
use App\Media\MediaRepositoryInterface;
|
||||
use App\Media\MediaService;
|
||||
use App\Media\MediaServiceInterface;
|
||||
use App\Post\PostRepository;
|
||||
use App\Post\PostRepositoryInterface;
|
||||
use App\Post\PostService;
|
||||
use App\Post\PostServiceInterface;
|
||||
use App\Post\RssController;
|
||||
use App\Shared\Config;
|
||||
use App\Shared\Extension\AppExtension;
|
||||
use App\Shared\Html\HtmlPurifierFactory;
|
||||
use App\Shared\Html\HtmlSanitizer;
|
||||
use App\Shared\Html\HtmlSanitizerInterface;
|
||||
use App\Shared\Http\ClientIpResolver;
|
||||
use App\Shared\Http\FlashService;
|
||||
use App\Shared\Http\FlashServiceInterface;
|
||||
use App\Shared\Http\SessionManager;
|
||||
use App\Shared\Http\SessionManagerInterface;
|
||||
use App\Shared\Mail\MailService;
|
||||
use App\Shared\Mail\MailServiceInterface;
|
||||
use App\User\UserRepository;
|
||||
use App\User\UserRepositoryInterface;
|
||||
use App\User\UserService;
|
||||
use App\User\UserServiceInterface;
|
||||
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Level;
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
use function DI\autowire;
|
||||
use function DI\factory;
|
||||
|
||||
return [
|
||||
|
||||
// ── Bindings interface → implémentation ──────────────────────────────────
|
||||
|
||||
AuthServiceInterface::class => autowire(AuthService::class),
|
||||
PostServiceInterface::class => autowire(PostService::class),
|
||||
UserServiceInterface::class => autowire(UserService::class),
|
||||
CategoryServiceInterface::class => autowire(CategoryService::class),
|
||||
CategoryRepositoryInterface::class => autowire(CategoryRepository::class),
|
||||
MediaRepositoryInterface::class => autowire(MediaRepository::class),
|
||||
PostRepositoryInterface::class => autowire(PostRepository::class),
|
||||
UserRepositoryInterface::class => autowire(UserRepository::class),
|
||||
LoginAttemptRepositoryInterface::class => autowire(LoginAttemptRepository::class),
|
||||
PasswordResetRepositoryInterface::class => autowire(PasswordResetRepository::class),
|
||||
PasswordResetServiceInterface::class => autowire(PasswordResetService::class),
|
||||
FlashServiceInterface::class => autowire(FlashService::class),
|
||||
SessionManagerInterface::class => autowire(SessionManager::class),
|
||||
HtmlSanitizerInterface::class => autowire(HtmlSanitizer::class),
|
||||
|
||||
// ── Infrastructure ────────────────────────────────────────────────────────
|
||||
|
||||
LoggerInterface::class => factory(function (): LoggerInterface {
|
||||
$isDev = strtolower($_ENV['APP_ENV'] ?? 'production') === 'development';
|
||||
$logger = new Logger('slim-blog');
|
||||
$level = $isDev ? Level::Debug : Level::Warning;
|
||||
|
||||
$logger->pushHandler(
|
||||
new StreamHandler(dirname(__DIR__) . '/var/logs/app.log', $level)
|
||||
);
|
||||
|
||||
return $logger;
|
||||
}),
|
||||
|
||||
PDO::class => factory(function (): PDO {
|
||||
$pdo = new PDO('sqlite:' . Config::getDatabasePath(), options: [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
]);
|
||||
|
||||
// strip_tags() PHP exposée comme fonction SQLite pour les triggers FTS5
|
||||
$pdo->sqliteCreateFunction('strip_tags', 'strip_tags', 1);
|
||||
$pdo->exec('PRAGMA journal_mode=WAL');
|
||||
// Attend jusqu'à 3s avant d'échouer sur une contention en écriture
|
||||
$pdo->exec('PRAGMA busy_timeout=3000');
|
||||
// Réduit les fsync sans sacrifier la cohérence en WAL mode
|
||||
$pdo->exec('PRAGMA synchronous=NORMAL');
|
||||
// Active l'application réelle des contraintes de clé étrangère.
|
||||
// Sans ce pragma, les ON DELETE SET NULL / CASCADE déclarés dans les
|
||||
// migrations sont enregistrés dans le schéma mais silencieusement ignorés
|
||||
// à l'exécution — SQLite désactive les FK par défaut pour la compatibilité.
|
||||
$pdo->exec('PRAGMA foreign_keys=ON');
|
||||
|
||||
return $pdo;
|
||||
}),
|
||||
|
||||
Twig::class => factory(function (): Twig {
|
||||
$isDev = strtolower($_ENV['APP_ENV'] ?? 'production') === 'development';
|
||||
|
||||
return Twig::create(
|
||||
dirname(__DIR__) . '/views',
|
||||
['cache' => Config::getTwigCache($isDev)],
|
||||
);
|
||||
}),
|
||||
|
||||
\HTMLPurifier::class => factory(function (): \HTMLPurifier {
|
||||
return HtmlPurifierFactory::create(dirname(__DIR__) . '/var/cache/htmlpurifier');
|
||||
}),
|
||||
|
||||
// ── Services nécessitant une configuration .env ───────────────────────────
|
||||
|
||||
MailServiceInterface::class => factory(function (Twig $twig): MailServiceInterface {
|
||||
return new MailService(
|
||||
twig: $twig,
|
||||
host: $_ENV['MAIL_HOST'] ?? '',
|
||||
port: (int) ($_ENV['MAIL_PORT'] ?? 587),
|
||||
username: $_ENV['MAIL_USERNAME'] ?? '',
|
||||
password: $_ENV['MAIL_PASSWORD'] ?? '',
|
||||
encryption: strtolower($_ENV['MAIL_ENCRYPTION'] ?? 'tls'),
|
||||
from: $_ENV['MAIL_FROM'] ?? '',
|
||||
fromName: $_ENV['MAIL_FROM_NAME'] ?? 'Slim Blog',
|
||||
);
|
||||
}),
|
||||
|
||||
MediaServiceInterface::class => factory(
|
||||
function (MediaRepositoryInterface $mediaRepository): MediaServiceInterface {
|
||||
return new MediaService(
|
||||
mediaRepository: $mediaRepository,
|
||||
uploadDir: dirname(__DIR__) . '/public/media',
|
||||
uploadUrl: '/media',
|
||||
maxSize: (int) ($_ENV['UPLOAD_MAX_SIZE'] ?? 5 * 1024 * 1024),
|
||||
);
|
||||
}
|
||||
),
|
||||
|
||||
// ── Contrôleurs nécessitant des paramètres scalaires ─────────────────────
|
||||
|
||||
RssController::class => factory(
|
||||
function (PostServiceInterface $postService): RssController {
|
||||
return new RssController(
|
||||
$postService,
|
||||
rtrim($_ENV['APP_URL'] ?? 'http://localhost', '/'),
|
||||
$_ENV['APP_NAME'] ?? 'Slim Blog',
|
||||
);
|
||||
}
|
||||
),
|
||||
|
||||
PasswordResetController::class => factory(
|
||||
function (
|
||||
Twig $twig,
|
||||
PasswordResetServiceInterface $passwordResetService,
|
||||
AuthServiceInterface $authService,
|
||||
FlashServiceInterface $flash,
|
||||
): PasswordResetController {
|
||||
return new PasswordResetController(
|
||||
$twig,
|
||||
$passwordResetService,
|
||||
$authService,
|
||||
$flash,
|
||||
rtrim($_ENV['APP_URL'] ?? 'http://localhost', '/'),
|
||||
);
|
||||
}
|
||||
),
|
||||
|
||||
ClientIpResolver::class => factory(function (): ClientIpResolver {
|
||||
$trusted = array_filter(array_map('trim', explode(',', (string) ($_ENV['TRUSTED_PROXIES'] ?? ''))));
|
||||
|
||||
return new ClientIpResolver($trusted);
|
||||
}),
|
||||
|
||||
AppExtension::class => factory(function (): AppExtension {
|
||||
return new AppExtension(rtrim($_ENV['APP_URL'] ?? 'http://localhost', '/'));
|
||||
}),
|
||||
];
|
||||
Reference in New Issue
Block a user