[2.1] [Config] added ability to set info message to node definition #1099

Merged
merged 1 commit into from Dec 13, 2011
+236 −11
Split
@@ -31,7 +31,7 @@ class DoctrineExtension extends AbstractDoctrineExtension
{
public function load(array $configs, ContainerBuilder $container)
{
- $configuration = new Configuration($container->getParameter('kernel.debug'));
+ $configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
if (!empty($config['dbal'])) {
@@ -412,4 +412,9 @@ public function getNamespace()
{
return 'http://symfony.com/schema/dic/doctrine';
}
+
+ public function getConfiguration(array $config, ContainerBuilder $container)
+ {
+ return new Configuration($container->getParameter('kernel.debug'));
+ }
}
@@ -13,6 +13,8 @@
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
@@ -56,7 +58,7 @@ public function load(array $configs, ContainerBuilder $container)
$container->setAlias('debug.controller_resolver', 'controller_resolver');
}
- $configuration = new Configuration($container->getParameter('kernel.debug'));
+ $configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
if (isset($config['charset'])) {
@@ -146,6 +148,11 @@ public function load(array $configs, ContainerBuilder $container)
));
}
+ public function getConfiguration(array $config, ContainerBuilder $container)
+ {
+ return new Configuration($container->getParameter('kernel.debug'));
+ }
+
/**
* Loads Form configuration.
*
@@ -36,7 +36,7 @@ class MonologExtension extends Extension
*/
public function load(array $configs, ContainerBuilder $container)
{
- $configuration = new Configuration();
+ $configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
if (isset($config['handlers'])) {
@@ -48,9 +48,9 @@ public function load(array $configs, ContainerBuilder $container)
if (!array_filter($configs)) {
return;
}
-
- // normalize and merge the actual configuration
- $mainConfig = new MainConfiguration($this->factories, $this->userProviderFactories);
+
+ $mainConfig = $this->getConfiguration($configs, $container);
+
$config = $this->processConfiguration($mainConfig, $configs);
// load services
@@ -569,5 +569,11 @@ public function getNamespace()
{
return 'http://symfony.com/schema/dic/security';
}
+
+ public function getConfiguration(array $config, ContainerBuilder $container)
+ {
+ // first assemble the factories
+ return new MainConfiguration($this->factories, $this->userProviderFactories);
+ }
}
@@ -43,7 +43,7 @@ public function load(array $configs, ContainerBuilder $container)
$loader->load('swiftmailer.xml');
$container->setAlias('mailer', 'swiftmailer.mailer');
- $configuration = new Configuration($container->getParameter('kernel.debug'));
+ $configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
if (null === $config['transport']) {
@@ -145,4 +145,9 @@ public function getNamespace()
{
return 'http://symfony.com/schema/dic/swiftmailer';
}
+
+ public function getConfiguration(array $config, ContainerBuilder $container)
+ {
+ return new Configuration($container->getParameter('kernel.debug'));
+ }
}
@@ -36,7 +36,7 @@ public function load(array $configs, ContainerBuilder $container)
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('twig.xml');
- $configuration = new Configuration();
+ $configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter('twig.exception_listener.controller', $config['exception_controller']);
@@ -39,7 +39,7 @@ class WebProfilerExtension extends Extension
*/
public function load(array $configs, ContainerBuilder $container)
{
- $configuration = new Configuration();
+ $configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
@@ -49,6 +49,16 @@ public function __construct($name, NodeInterface $parent = null)
$this->allowNewKeys = true;
$this->performDeepMerging = true;
}
+
+ /**
+ * Retrieves the children of this node.
+ *
+ * @return array The children
+ */
+ public function getChildren()
+ {
+ return $this->children;
+ }
/**
* Sets the xml remappings that should be performed.
@@ -29,6 +29,8 @@
protected $allowOverwrite;
protected $required;
protected $equivalentValues;
+ protected $info;
+ protected $example;
/**
* Constructor.
@@ -51,6 +53,46 @@ public function __construct($name, NodeInterface $parent = null)
$this->required = false;
$this->equivalentValues = array();
}
+
+ /**
+ * Sets info message
+ *
+ * @param string $info The info text
+ */
+ public function setInfo($info)
+ {
+ $this->info = $info;
+ }
+
+ /**
+ * Returns info message
+ *
+ * @return string The info text
+ */
+ public function getInfo()
+ {
+ return $this->info;
+ }
+
+ /**
+ * Sets the example configuration for this node.
+ *
+ * @param array $example
+ */
+ public function setExample($example)
+ {
+ $this->example = $example;
+ }
+
+ /**
+ * Retrieves the example configuration for this node.
+ *
+ * @return mixed The example
+ */
+ public function getExample()
+ {
+ return $this->example;
+ }
/**
* Adds an equivalent value.
@@ -32,6 +32,8 @@
protected $trueEquivalent;
protected $falseEquivalent;
protected $parent;
+ protected $info;
+ protected $example;
/**
* Constructor
@@ -60,6 +62,34 @@ public function setParent(NodeParentInterface $parent)
return $this;
}
+
+ /**
+ * Sets info message
+ *
+ * @param string $info The info text
+ *
+ * @return NodeDefinition
+ */
+ public function setInfo($info)
+ {
+ $this->info = $info;
+
+ return $this;
+ }
+
+ /**
+ * Sets example configuration
+ *
+ * @param example $example
+ *
+ * @return NodeDefinition
+ */
+ public function setExample($example)
+ {
+ $this->example = $example;
+
+ return $this;
+ }
/**
* Returns the parent node.
@@ -91,8 +121,13 @@ public function getNode($forceRootNode = false)
if (null !== $this->validation) {
$this->validation->rules = ExprBuilder::buildExpressions($this->validation->rules);
}
+
+ $node = $this->createNode();
+
+ $node->setInfo($this->info);
+ $node->setExample($this->example);
- return $this->createNode();
+ return $node;
}
/**
@@ -79,6 +79,16 @@ public function setKeyAttribute($attribute, $remove = true)
}
/**
+ * Retrieves the name of the attribute which value should be used as key.
+ *
+ * @return string The name of the attribute
+ */
+ public function getKeyAttribute()
+ {
+ return $this->keyAttribute;
+ }
+
+ /**
* Sets the default value of this node.
*
* @param string $value
@@ -122,6 +132,16 @@ public function setPrototype(PrototypeNodeInterface $node)
{
$this->prototype = $node;
}
+
+ /**
+ * Retrieves the prototype
+ *
+ * @return PrototypeNodeInterface The prototype
+ */
+ public function getPrototype()
+ {
+ return $this->prototype;
+ }
/**
* Disable adding concrete children for prototyped nodes.
@@ -0,0 +1,32 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection\Extension;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * ConfigurationExtensionInterface is the interface implemented by container extension classes.
+ *
+ * @author Kevin Bond <kevinbond@gmail.com>
+ */
+interface ConfigurationExtensionInterface
stof
stof Nov 22, 2011 Member

this interface has nothing to do with the DI extension (it could be implemented by other code using the Config\Definition component) so it should be placed in the Config component and renamed (maybe ConfigurableInterface ?)

stof
stof Nov 22, 2011 Member

hmm, in fact, it is linked to the DI component because of the signature. Do we really need to pass a ContainerBuilder to the method ?

kbond
kbond Nov 22, 2011 Contributor

I originally didn't have the ContainerBuilder passed but if you look at how the configuration is retrieved in the various core bundle extensions, it is needed.

+{
+ /**
+ * Returns extension configuration
+ *
+ * @param array $config $config An array of configuration values
+ * @param ContainerBuilder $container A ContainerBuilder instance
+ *
+ * @return ConfigurationInterface|null The configuration or null
+ */
+ function getConfiguration(array $config, ContainerBuilder $container);
+}
@@ -5,6 +5,9 @@
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
+use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Container;
/*
@@ -21,7 +24,7 @@
*
* @author Fabien Potencier <fabien@symfony.com>
*/
-abstract class Extension implements ExtensionInterface
+abstract class Extension implements ExtensionInterface, ConfigurationExtensionInterface
stof
stof Nov 22, 2011 Member

now that it is a separate interface, I would find it more logical to implement it only when we really have the Configuration class instead of implementing the interface and returning null.

kbond
kbond Nov 22, 2011 Contributor

I like it as is because if your bundle's configuration is just a basic Configurationclass with no special constructor it automatically will be able to be retrieved by a future documentation generator.

Having users add implements ConfigurationExtensionInterface to their bundle's Extension class seems a little verbose, no? This way many bundles be able to have their configuration documentation generated with no additions on their end.

stof
stof Nov 22, 2011 Member

as the DI extension is generated by SensioGeneratorBundle when creating a bundle, this is not really an issue. We simply need to update the bundle too.

But currently, the command needs to do 2 checks: does it implement the interface ? And if yes, does it return null or a Configuration instance ?

kbond
kbond Nov 22, 2011 Contributor

You are right, the command would need both checks.

I suppose I was trying to make it as BC as possible. Most 3rd party bundles would work out of the box currently.

stof
stof Nov 22, 2011 Member

If you implement the interface here, it will break any third party bundle passing extra parameters.

If you implement the interface in the actual extension class, there will be no issue for third party bundles. They will simply have to update their code to be able to use the doc generator.

kbond
kbond Nov 22, 2011 Contributor

I don't see how it will break the 3rd party bundle. The default getConfiguration will just return null if extra parameters are passed (the __constructor check). It is documented in the interface that the return can be null or ConfigurationInterface.

I currently check for that in the command and give an error if null (kbond@a647540#L0R105)

I am not trying to be a stick in the mud about this I just would like to avoid having to rely on the third party bundles to update their code for this to work.

stof
stof Nov 22, 2011 Member

ah, I forgot the constructor check.

{
private $classes = array();
@@ -100,4 +103,24 @@ public function getAlias()
return $processor->processConfiguration($configuration, $configs);
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getConfiguration(array $config, ContainerBuilder $container)
+ {
+ $reflected = new \ReflectionClass($this);
+ $namespace = $reflected->getNamespaceName();
+
+ $class = $namespace . '\\Configuration';
+ if (class_exists($class)) {
+ if (!method_exists($class, '__construct')) {
+ $configuration = new $class();
+
+ return $configuration;
+ }
+ }
+
+ return null;
+ }
}
Oops, something went wrong.