PackageBuilder was always sort of meta package with all the cool and shiny features anyone can use. After all, it's the most downloaded Symplify package hitting almost 1000 downloads a day.
In Symplify 5 now it allows you to drop manual binds from Symfony configs, separate files from directories in one method and merge nested YAML parameters with 1 service.
You don't have this package installed yet?
composer require symplify/package-builder
Now enjoy the news ↓
You can add parameter binding since Symfony 3.4:
services:
_defaults:
bind:
$meetupComApiKey: '%meetup_com_api_key%'
That's nice. But what if you have multiple configs that use multiple parameters?
services:
_defaults:
bind:
$meetupComApiKey: '%meetup_com_api_key%'
$facebookApiKey: '%facebook_api_key%'
$maxPostOnHomepage: '%max_post_on_homepage%'
App\FirstPackage\:
resource: ..
services:
_defaults:
bind:
$facebookApiKey: '%facebook_api_key%'
$maxPostOnHomepage: '%max_post_on_homepage%'
App\SecondPackage\:
resource: ..
This way you'll be writing more bindings than there are parameters. And there is more! When you remove autodiscovered service that depends on a bound parameter, you'll get this "nice" exception:
Unused binding "maxPostOnHomepage" in service "App\SomeUnterlatedService"
You can solve this all by having a huge config with all parameters, binding and services. Even if the config would be shorter than 100 lines, you still have to maintain parameters, bindings and services and it teaches other programmers to put-everything-to-one-place instead of SOLID principles.
Would you like to get rid of this all extra maintenance, and just code cleanly instead? I would!
So, have you noticed the pattern?
$variableName
<=> %parameter_name
camelCase
<=> underscore_case
And exactly this can be automated! Just add Symplify\PackageBuilder\DependencyInjection\CompilerPass\AutoBindParametersCompilerPass
compiler pass:
<?php
// ...
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;
+use Symplify\PackageBuilder\DependencyInjection\CompilerPass\AutoBindParametersCompilerPass;
final class YourAppKernel extends Kernel
{
// ...
+ protected function build(ContainerBuilder $containerBuilder): void
+ {
+ $containerBuilder->addCompilerPass(new AutoBindParametersCompilerPass());
+ }
}
And if you keep this convention, you can keep yours configs clear and minimalistic:
services:
- _defaults:
- bind:
- $meetupComApiKey: '%meetup_com_api_key%'
- $facebookApiKey: '%facebook_api_key%'
- $maxPostOnHomepage: '%max_post_on_homepage%'
Of course you can bind your parameters manually:
services:
_defaults:
bind:
$anotherName: '%non_standard_parameter_naming%'
SomeClass:
arguments:
- '%very_specfici_meetup_com_api_key%'
Do you need to work multiple file/directories arguments?
vendor/bin/ecs check src tests/ThisFile.php
Just use Symplify\PackageBuilder\FileSystem\FileSystem
:
<?php
$sources = [
__DIR__ . '/SomeDirectory',
__DIR__ . '/SomeFile.php'
];
$symplifyFileSystem = new Symplify\PackageBuilder\FileSystem\FileSystem;
[$files, $directories] = $symplifyFileSystem->separateFilesAndDirectories($sources);
// ...
At the moment, Symfony is unable to merge nested parameters for historical and other reasons:
# config.yml
imports:
- { resource: 'imported-file.yml' }
parameters:
festivals:
- three
# imported-file.yml
parameters:
festivals:
- one
- two
This will end up with just 1 festival in classic Symfony Applicatoin. Do you want to use the full power of YAML, glob and imports and still keep all the parameters?
Use Symplify\PackageBuilder\Yaml\ParameterMergingYamlLoader
:
<?php
$parametersMergingYamlLoader = new Symplify\PackageBuilder\Yaml\ParameterMergingYamlLoader;
$parameterBag = $parametersMergingYamlLoader->loadParameterBagFromFile(
__DIR__ . '/config.yml'
);
var_dump($parameterBag->get('festivals'));
// ['one', 'two', 'three']
And that's all folks!
Happy tuning of your code!
Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors.
I'd really appreciate it!