Browse Source

Bundles: How to Create Friendly Configuration for a Bundle.

Frederic G. MARAND 6 years ago
parent
commit
80bbdf8caa

+ 2 - 0
config/packages/dev/osinet_demo.yml

@@ -0,0 +1,2 @@
+osinet_demo:
+  prefix: 'Mon précieux développement:'

+ 2 - 0
config/packages/osinet_demo.yml

@@ -0,0 +1,2 @@
+osinet_demo:
+  prefix: 'Mon précieux'

+ 2 - 1
src/Osinet/DemoBundle/Controller/DemoController.php

@@ -3,6 +3,7 @@
 namespace Osinet\DemoBundle\Controller;
 
 use Osinet\DemoBundle\DemoCode;
+use Osinet\DemoBundle\DependencyInjection\OsinetDemoExtension;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Routing\Annotation\Route;
@@ -25,7 +26,7 @@ class DemoController extends AbstractController {
   public function homeController(DemoCode $demoCode = null) {
     $message = '';
     if (!isset($demoCode)) {
-      $demoCode = $this->get('osinet_demo.democode');
+      $demoCode = $this->get(OsinetDemoExtension::S_DEMO);
       $message .= "<p>demoCode fetched manually</p>\n";
     }
     else {

+ 4 - 1
src/Osinet/DemoBundle/DemoCode.php

@@ -9,7 +9,10 @@ class DemoCode {
   protected $message;
 
   public function __construct(ContainerInterface $container, string $codeMessage) {
-    $this->message = $container->getParameter('osinet_demo.message');
+    // Notice how $messageParameter is the unprefixed parameter, while the injected
+    // parameter includes the configured prefix.
+    $messageParameter = $container->getParameter('osinet_demo.message');
+    $this->message = $codeMessage;
   }
 
   public function getMessage() {

+ 29 - 0
src/Osinet/DemoBundle/DependencyInjection/Configuration.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace Osinet\DemoBundle\DependencyInjection;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+
+class Configuration implements ConfigurationInterface {
+
+  /**
+   * Generates the configuration tree builder.
+   *
+   * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
+   */
+  public function getConfigTreeBuilder(): TreeBuilder {
+    $treeBuilder = new TreeBuilder();
+    $rootNode = $treeBuilder->root(OsinetDemoExtension::ALIAS);
+
+    $rootNode
+      ->children()
+        ->scalarNode('prefix')
+          ->defaultValue('Say')
+          ->end()
+        ->end()
+    ;
+
+    return $treeBuilder;
+  }
+}

+ 36 - 5
src/Osinet/DemoBundle/DependencyInjection/OsinetDemoExtension.php

@@ -6,22 +6,53 @@ use Osinet\DemoBundle\Controller\DemoController;
 use Symfony\Component\Config\FileLocator;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
-use Symfony\Component\HttpKernel\DependencyInjection\Extension;
+use Symfony\Component\HttpKernel\DependencyInjection\ConfigurableExtension;
 
-class OsinetDemoExtension extends Extension {
+class OsinetDemoExtension extends ConfigurableExtension {
+  // Autogenerated by SF4: we define it too in order to have a reference point.
+  const ALIAS = 'osinet_demo';
+
+  // Service aliases, for reference during refactors.
+  const S_DEMO = self::ALIAS . '.democode';
 
   /**
-   * Loads a specific configuration.
+   * Delegate configuration loading to a loader.
    *
-   * @throws \InvalidArgumentException When provided tag is not defined in this extension
+   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
    */
-  public function load(array $configs, ContainerBuilder $container) {
+  protected function doLoad(ContainerBuilder $container) {
     $loader = new YamlFileLoader(
       $container,
       new FileLocator(__DIR__ . '/../Resources/config')
     );
     $loader->load('services.yml');
+  }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function loadInternal(array $mergedConfig, ContainerBuilder $container) {
+    $this->doLoad($container);
+    $this->override($mergedConfig, $container);
+    $this->hintAnnotations();
+  }
+
+  /**
+   * Apply the "friendly" configuration to override the bundle.
+   *
+   * @param array $mergedConfig
+   * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
+   */
+  protected function override(array $mergedConfig, ContainerBuilder $container) {
+    $def = $container->getDefinition(static::S_DEMO);
+    $overridden = '$codeMessage';
+    $def->replaceArgument($overridden, $mergedConfig['prefix'] . ' ' . $def->getArgument($overridden));
+  }
+
+  /**
+   * Help build a faster container by specifying whence to parse annotations.
+   */
+  protected function hintAnnotations() {
     $this->addAnnotatedClassesToCompile([
       DemoController::class,
     ]);

+ 4 - 0
src/Osinet/DemoBundle/DependencyInjection/README.md

@@ -1 +1,5 @@
 * This directory/namespace is used for service container extensions
+* The name of the default extension is required to be <namespace><bundle>Extension.
+* The name of the default configuration class is required to be Configuration in
+  order to allow the extension to take advantage of the ConfigurableExtension
+  mechanism.