samuelgfeller / slim-example-project

Complete Real World Slim 4 Example Project with Front- and Backend, Automated Testing, Auth System, Permissions, Localization and more.
https://samuel-gfeller.ch/slim-example-project
MIT License
36 stars 4 forks source link

Feedback / Questions #1

Closed samuelgfeller closed 1 month ago

samuelgfeller commented 1 year ago

If you have questions or suggestions, please don't hesitate to let me know here.

alexandrmazur96 commented 10 months ago

Hi, @samuelgfeller!

It seems a little bit hard to enable DI container compilation using this template. Would you happen to have any suggestions on how to make it easy?

Here's what I mean. We want to enable compilation only when in production. Still, we know it only after settings were set, but settings were available only after the container was built (I don't think we wanna require settings twice on each request) -> the built container can not be compiled.

So, in that case, the only obvious way I see to compile it is to use a separate command (CLI script) that should be used in the deployment process.

samuelgfeller commented 10 months ago

Hi @alexandrmazur96

I don't have a lot of experience with container compilation, but if I understand correctly, the issue is that settings.php sets the APP_ENV to prod only after the container is built because settings.php is required in the container definition. A way to circumvent this would be to set the APP_ENV elsewhere, e.g. the bootstrap.php file, before building the container.

Currently, in this template, the APP_ENV prod is set in the production env.php file and dev is the default fallback value if nothing is set (docs).
This isn't ideal in your case if you want to be able to know if the environment is prod before the settings are loaded. For this, you need a way to know that the application is in the production environment which is not related to settings and set the APP_ENV to prod accordingly.

There are certainly better other ways to do this, but you could, for example, create a file config/set-prod-env.php which only exists on the production server with the following content:

<?php

$_ENV['APP_ENV'] = 'prod';

Then in the bootstrap.php file, you can check if this file exists and if it does, require it.

<?php

use DI\ContainerBuilder;
use Slim\App;

require __DIR__ . '/../vendor/autoload.php';

// Set the APP_ENV to prod if the file exists
if (file_exists(__DIR__ . '/set-prod-env.php')) {
    require __DIR__ . '/set-prod-env.php';
} elseif (!isset($_ENV['APP_ENV'])) {
    // Set the APP_ENV to dev if it is not already set
    $_ENV['APP_ENV'] = 'dev';
}

// Instantiate DI ContainerBuilder
$containerBuilder = new ContainerBuilder();

// Add container definitions
$containerBuilder->addDefinitions(__DIR__ . '/container.php');

// Compile or use the cache if prod env
if ($_ENV['APP_ENV'] === 'prod') {
    $containerBuilder->enableCompilation(__DIR__ . '/var/cache');
}

$container = $containerBuilder->build();

// Create app instance
return $container->get(App::class);

Or if you don't want to create an additional file, you could extract the APP_ENV value from the secret prod env.php with file_get_contents and use this value, but this doesn't seem like a very clean solution to me.

Let me know if that helps and how you end up doing it.