diff --git a/.env.example b/.env.example index 88db34a..9a09b4a 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,10 @@ +# Environnement de l'application APP_ENV=development -# APP_ENV=production + +# Chemin de cache Twig (laisser vide en développement pour désactiver le cache) +# Exemples : +# TWIG_CACHE=var/cache/twig +# TWIG_CACHE=/srv/www/myapp/var/cache/twig +TWIG_CACHE= + +# (Optionnel) autres variables d'environnement peuvent être ajoutées ici diff --git a/public/index.php b/public/index.php index ac61ba0..237dc65 100644 --- a/public/index.php +++ b/public/index.php @@ -12,15 +12,23 @@ use Medoo\Medoo; use Dotenv\Dotenv; use Throwable; -// Charger .env (tolérant l'absence du fichier) +/** + * Charger les variables d'environnement si présentes (tolérant l'absence du fichier). + */ $dotenv = Dotenv::createImmutable(__DIR__ . '/../'); $dotenv->safeLoad(); -// Configuration centralisée (valeurs raisonnables par défaut) +/** + * Configuration centrale avec valeurs par défaut raisonnables. + * + * - 'env' : environnement d'exécution ('production' par défaut) + * - 'twig.cache' : résolu plus bas à partir de TWIG_CACHE ou par défaut selon l'environnement + * - 'db.file' et 'db.file_mode' : fichier SQLite et permissions + */ $config = [ - 'env' => strtolower($_ENV['APP_ENV'] ?? $_SERVER['APP_ENV'] ?? 'production'), + 'env' => strtolower((string) ($_ENV['APP_ENV'] ?? $_SERVER['APP_ENV'] ?? 'production')), 'twig' => [ - 'cache' => false, // => mettre un chemin en production, ex: __DIR__ . '/../var/cache/twig' + 'cache' => null, ], 'db' => [ 'file' => __DIR__ . '/../database/app.sqlite', @@ -28,9 +36,25 @@ $config = [ ], ]; -$isDebug = ($config['env'] === 'development' || $config['env'] === 'dev'); +/** + * Résolution de la valeur twig.cache depuis la variable d'environnement TWIG_CACHE. + * Si TWIG_CACHE est vide : false en dev, chemin par défaut en production. + */ +$envTwigCache = $_ENV['TWIG_CACHE'] ?? $_SERVER['TWIG_CACHE'] ?? null; +if ($envTwigCache !== null && $envTwigCache !== '') { + $config['twig']['cache'] = (string) $envTwigCache; +} else { + $devEnvs = ['development', 'dev']; + $config['twig']['cache'] = in_array($config['env'], $devEnvs, true) + ? false + : __DIR__ . '/../var/cache/twig'; +} -// Affichage des erreurs selon l'environnement +$isDebug = in_array($config['env'], ['development', 'dev'], true); + +/** + * Affichage et rapport d'erreurs selon l'environnement. + */ if ($isDebug) { ini_set('display_errors', '1'); ini_set('display_startup_errors', '1'); @@ -44,26 +68,36 @@ if ($isDebug) { // ------------------------- // Base de données (SQLite) // ------------------------- + $dbFile = $config['db']['file']; + +/** + * Créer le fichier de base de données si nécessaire et appliquer les permissions. + */ if (!file_exists($dbFile)) { - if (!is_dir(dirname($dbFile))) { - mkdir(dirname($dbFile), 0755, true); + $dbDir = dirname($dbFile); + if (!is_dir($dbDir)) { + mkdir($dbDir, 0755, true); } touch($dbFile); - chmod($dbFile, $config['db']['file_mode']); + @chmod($dbFile, $config['db']['file_mode']); } -// Options Medoo (SQLite) +/** + * Options Medoo pour SQLite. + */ $medooOptions = [ 'database_type' => 'sqlite', - 'database_file' => $dbFile, - 'database_name' => $dbFile, // nécessaire pour certaines versions de Medoo + 'database_name' => $dbFile, 'charset' => 'utf8', ]; -// Instancier Medoo + +/** @var Medoo $database */ $database = new Medoo($medooOptions); -// Créer la table si nécessaire (schéma minimal) +/** + * Schéma minimal : création de la table 'post' si elle n'existe pas. + */ $database->query( <<<'SQL' CREATE TABLE IF NOT EXISTS post ( @@ -77,25 +111,37 @@ SQL // ------------------------- // Services (container simple) // ------------------------- -/** @var array{view: Twig, postRepository: \App\Repositories\PostRepositoryMedoo} $container */ + +/** + * Container simple (table associative de services). + * + * @var array $container + */ $container = []; /** * Construire les services et les retourner dans le container. * - * Reste modulaire : la fonction reste locale et conserve la variable $container = []. + * Cette fonction reste locale pour préserver l'encapsulation. * * @param array $config * @param Medoo $database - * @return array + * @return array */ -$container = (function (array $config, Medoo $database): array { +$container = (static function (array $config, Medoo $database): array { $services = []; - // Vue Twig - $services['view'] = new Twig(new FilesystemLoader(__DIR__ . '/../views'), ['cache' => $config['twig']['cache']]); + // Résoudre le cache Twig et créer le dossier si nécessaire. + $twigCache = $config['twig']['cache']; + if ($twigCache && $twigCache !== false && !is_dir((string) $twigCache)) { + mkdir((string) $twigCache, 0755, true); + } - // Repository Post (Medoo) + // Vue Twig + $loader = new FilesystemLoader(__DIR__ . '/../views'); + $services['view'] = new Twig($loader, ['cache' => $config['twig']['cache']]); + + // Repository Post (implémentation Medoo) $services['postRepository'] = new App\Repositories\PostRepositoryMedoo($database); return $services; @@ -104,16 +150,21 @@ $container = (function (array $config, Medoo $database): array { // ------------------------- // Slim app // ------------------------- + $app = AppFactory::create(); -// Error middleware +/** + * Middleware d'erreurs. + * + * Les trois flags correspondent à : displayErrorDetails, logErrors, logErrorDetails. + */ $errorMiddleware = $app->addErrorMiddleware($isDebug, $isDebug, $isDebug); if (!$isDebug) { $errorHandler = $errorMiddleware->getDefaultErrorHandler(); - // Renderer générique en production - $errorHandler->registerErrorRenderer('text/html', function (Throwable $exception, bool $displayErrorDetails) { - return 'Erreur

Erreur serveur

Une erreur est survenue. Veuillez réessayer plus tard.

'; + // Renderer HTML générique en production pour masquer les détails d'exception. + $errorHandler->registerErrorRenderer('text/html', static function (Throwable $exception, bool $displayErrorDetails): string { + return 'Erreur

Erreur serveur

Une erreur est survenue. Veuillez réessayer plus tard.

'; }); } @@ -121,8 +172,18 @@ if (!$isDebug) { $app->addBodyParsingMiddleware(); $app->add(TwigMiddleware::create($app, $container['view'])); -// Charger routes (web.php reçoit le container) -(require __DIR__ . '/../src/Routes/web.php')($app, $container); +/** + * Charger les routes : le fichier web.php reçoit l'application et le container. + * On utilise require pour que toute exception remonte à Slim / au handler d'erreurs. + */ +$routesPath = __DIR__ . '/../src/Routes/web.php'; +if (file_exists($routesPath)) { + /** @var callable $routes */ + $routes = require $routesPath; + $routes($app, $container); +} else { + // En cas d'absence du fichier de routes, on peut laisser l'application démarrer sans routes. + // (Conserver le comportement antérieur — aucune exception levée ici) +} -// Lancer l'app $app->run();