From f857fa475239729cb9068ba745a82cd955c34917 Mon Sep 17 00:00:00 2001 From: lubiana Date: Tue, 31 May 2022 17:48:26 +0200 Subject: [PATCH] simplify chapter 12 --- 12-configuration.md | 216 ++++++++++++-------------------------------- 1 file changed, 59 insertions(+), 157 deletions(-) diff --git a/12-configuration.md b/12-configuration.md index 4b60c19..bb3920d 100644 --- a/12-configuration.md +++ b/12-configuration.md @@ -4,197 +4,99 @@ In the last chapter we added some more definitions to our dependencies.php in that definitions we needed to pass quite a few configuration settings and filesystem strings to the constructors -of the classes. This might work for a small projects, but if we are growing we want to source that out to a more explicit file that holds all the configuration valuse for our project. +of the classes. This might work for a small projects, but if we are growing we want to source that out to a more +explicit file that holds all the configuration values for our project. -As this is not a problem unique to our project there are already a some options available. Some projects use [.env](https://github.com/vlucas/phpdotenv) files, others use [.ini](https://www.php.net/manual/de/function.parse-ini-file.php), there is [yaml](https://www.php.net/manual/de/function.yaml-parse-file.php) as well some frameworks have implemented complex Readers for many configuration file formats that can be used, take a look at the [laminas config component](https://docs.laminas.dev/laminas-config/reader/) for example. +As this is not a problem unique to our project there are already a some options available. Some projects use +[.env](https://github.com/vlucas/phpdotenv) files, others use +[.ini](https://www.php.net/manual/de/function.parse-ini-file.php), there is +[yaml](https://www.php.net/manual/de/function.yaml-parse-file.php) as well some frameworks have implemented complex +Readers for many configuration file formats that can be used, take a look at the +[laminas config component](https://docs.laminas.dev/laminas-config/reader/) for example. -As i am a big fan of writing everything in php, which gives our IDE the chance to autocomplete our code better I am quite happy the PHP8 gives us some tools to achieve easy to use configuration via php. You can take a look at [this blogpost](https://stitcher.io/blog/what-about-config-builders) to read about some considerations on that topic before moving on. +As I am a big fan of writing everything in php, which gives our IDE the chance to autocomplete our code better I am +quite happy that PHP8 gives us some tools to achieve easy to use configuration via php. You can take a look at +[this blogpost](https://stitcher.io/blog/what-about-config-builders) to read about some considerations on that topic +before moving on. -Lets create a 'Settings' class in our './src' Folder: +For the purpose of this Tutorial I will use a simple ValueObject that has all our configuration values as properties. +create a `Configuration.php` class in the `./src` folder: ```php fn (Configuration $c) => simpleDispatcher(require $c->routesFile), + Mustache_Loader_FilesystemLoader::class => fn (Configuration $c) => new Mustache_Loader_FilesystemLoader( + $c->templateDir, + [ + 'extension' => $c->templateExtension, + ] + ), +``` + +Magically this is all we need to do, as the PHP-DI container knows that all constructor parameters of our configuration +class have default values and can create the needed object on its own. + +There is one small problem: If we want to change environment from `dev` to `prod` we would need to update the +configuration class in the src directory. This is something we don't want to do on every deployment. So lets add a file +in our `./config` directory called `settings.php` that returns a Configuration object. ```php fn () => require __DIR__ . '/settings.php', ``` -And write a simple implementation that uses our settings.php to provide our App with the Settingsobject: - +One small oversight to fix is in the registration of our error-handler in the bootstrap-file. There we read the +environment with the getenv-method. Lets change the line: ```php -filePath; - } -} +$environment = getenv('ENVIRONMENT') ?: 'dev'; ``` -If we later want to use yaml or ini files for our Settings we can easily write a different provider to read those files -and craft a settings object from them. - -As we have now created a completely new Namespace and Folder and our SettingsProvider is all alone we could add another -factory for our Container because everyone should have a Friend :) - +to: ```php -environment; ``` -And a simple implementation that uses our new Settingsprovider to build the container: - -```php -settingsProvider->getSettings(); - $dependencies = require $settings->dependenciesFile; - $dependencies[Settings::class] = fn () => $settings; - $builder->addDefinitions($dependencies); - return $builder->build(); - } -} -``` - -For this to work we need to change our dependencies.php file to just return the array of definitions: -And here we can instantly use the Settings object to create our template engine. - -```php - fn (ResponseFactory $rf) => $rf->createResponse(), - ServerRequestInterface::class => fn (ServerRequestFactory $rf) => $rf::fromGlobals(), - Now::class => fn (SystemClockNow $n) => $n, - Renderer::class => fn (Mustache_Engine $e) => new MustacheRenderer($e), - MLF::class => fn (Settings $s) => new MLF($s->templateDir, ['extension' => $s->templateExtension]), - ME::class => fn (MLF $mfl) => new ME(['loader' => $mfl]), -]; -``` - -Now we can change our Bootstrap.php file to use the new Factories for the creation of the Initial Objects: - -```php -... -error_reporting(E_ALL); - -$settingsProvider = new FileSystemSettingsProvider(__DIR__ . '/../config/settings.php'); -$container = (new SettingsContainerProvider($settingsProvider))->getContainer(); - -$settings = $settingsProvider->getSettings(); - -$whoops = new Run; -if ($settings->environment === 'dev') { - $whoops->pushHandler(new PrettyPageHandler); -} else { - $whoops->pushHandler(function (Throwable $e): void { - error_log('Error: ' . $e->getMessage(), $e->getCode()); - echo 'An Error happened'; - }); -} -$whoops->register(); -... -``` - -Check if everything still works, run your code quality checks and commit the changes before moving on the the next chapter. +Check if everything still works, run your code quality checks and commit the changes before moving on the next chapter. +You might notice that phpstan throws an error as there is a documented violation missing. You can either regenerate the +baseline, or simply remove that line from the `phpstan-baseline.neon` file. [<< previous](11-templating.md) | [next >>](13-refactoring.md)