Home » Php » php – Symfony 2 – how to parse %parameter% in my own Yaml file loader?

php – Symfony 2 – how to parse %parameter% in my own Yaml file loader?

Posted by: admin July 12, 2020 Leave a comment

Questions:

I have a Yaml loader that loads additional config items for a “profile” (where one application can use different profiles, e.g. for different local editions of the same site).

My loader is very simple:

# YamlProfileLoader.php

use Symfony\Component\Config\Loader\FileLoader;
use Symfony\Component\Yaml\Yaml;

class YamlProfileLoader extends FileLoader
{
    public function load($resource, $type = null)
    {
        $configValues = Yaml::parse($resource);
        return $configValues;
    }

    public function supports($resource, $type = null)
    {
        return is_string($resource) && 'yml' === pathinfo(
            $resource,
            PATHINFO_EXTENSION
        );
    }
}

The loader is used more or less like this (simplified a bit, because there is caching too):

$loaderResolver = new LoaderResolver(array(new YamlProfileLoader($locator)));
$delegatingLoader = new DelegatingLoader($loaderResolver);

foreach ($yamlProfileFiles as $yamlProfileFile) {
    $profileName = basename($yamlProfileFile, '.yml');
    $profiles[$profileName] = $delegatingLoader->load($yamlProfileFile);
}

So is the Yaml file it’s parsing:

# profiles/germany.yml

locale: de_DE
hostname: %profiles.germany.host_name%

At the moment, the resulting array contains literally '%profiles.germany.host_name%' for the 'hostname' array key.

So, how can I parse the % parameters to get the actual parameter values?

I’ve been trawling through the Symfony 2 code and docs (and this SO question and can’t find where this is done within the framework itself. I could probably write my own parameter parser – get the parameters from the kernel, search for the %foo% strings and look-up/replace… but if there’s a component ready to be used, I prefer to use this.

To give a bit more background, why I can’t just include it into the main config.yml: I want to be able to load app/config/profiles/*.yml, where * is the profile name, and I am using my own Loader to accomplish this. If there’s a way to wildcard import config files, then that might also work for me.

Note: currently using 2.4 but just about ready to upgrade to 2.5 if that helps.

How to&Answers:

I’ve been trawling through the Symfony 2 code and docs (and this SO question and can’t find where this is done within the framework itself.

Symfony’s dependency injection component uses a compiler pass to resolve parameter references during the optimisation phase.

The Compiler gets the registered compiler passes from its PassConfig instance. This class configures a few compiler passes by default, which includes the ResolveParameterPlaceHoldersPass.

During container compilation, the ResolveParameterPlaceHoldersPass uses the Container’s ParameterBag to resolve strings containing %parameters%. The compiler pass then sets that resolved value back into the container.

So, how can I parse the % parameters to get the actual parameter values?

You’d need access to the container in your ProfileLoader (or wherever you see fit). Using the container, you can recursively iterate over your parsed yaml config and pass values to the container’s parameter bag to be resolved via the resolveValue() method.


Seems to me like perhaps a cleaner approach would be for you to implement this in your bundle configuration. That way your config will be validated against a defined structure, which can catch configuration errors early. See the docs on bundle configuration for more information (that link is for v2.7, but hopefully will apply to your version also).

I realise this is an old question, but I have spent quite a while figuring this out for my own projects, so I’m posting the answer here for future reference.

Answer:

I tried a lot of options to resolve %parameter% to parameters.yml but no luck at all. All I can think of is parsing %parameter% and fetch it from container, no innovation yet.

On the other hand I don’t have enough information about your environment to see the big picture but I just come up with another idea. It can be quite handy if you declare your profiles in your parameters.yml file and load it as an array in your controller or service via container.

app/config/parameters.yml

parameters:
    profiles:
        germany:
            locale: de_DE
            host_name: http://de.example.com
        uk:
            locale: en_EN
            host_name: http://uk.example.com
        turkey:
            locale: tr_TR
            host_name: http://tr.example.com 

You can have all your profiles as an array in your controller.

<?php

namespace Acme\DemoBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class DefaultController extends Controller
{
    public function indexAction()
    {


        $profiles = $this->container->getParameter('profiles');
        var_dump($profiles);

        return $this->render('AcmeDemoBundle:Default:index.html.twig');
    }
}

With this approach

  • you don’t have to code a custom YamlLoader
  • you don’t have to worry about importing parameters into other yml files
  • you can have your profiles as an array anytime you have the $container in your hand
  • you don’t have to load/cache profile files one by one
  • you don’t have to find a wildcard file loading solution

If I got your question correctly, this approach can help you.