Skip to content

Instantly share code, notes, and snippets.

@CodingNinja
Created March 6, 2012 11:36
Show Gist options
  • Save CodingNinja/1985816 to your computer and use it in GitHub Desktop.
Save CodingNinja/1985816 to your computer and use it in GitHub Desktop.
Extensible Bundle
<?php
namespace Ninja\BundleExtensionsBundle\Factory;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\NodeInterface;
/**
* Contract for an BundleExtension to implement
*
* @author CodingNinja
*/
interface BundleExtensionInterface
{
/**
* Build the Configuration
*
* @param NodeInterface $node
*/
public function buildConfiguration(NodeInterface $node);
/**
* Build the Container
*
* @param array $configs
* @param ConfigurationInterface $configuration
* @param ContainerBuilder $container
*/
public function buildContainer(array $configs, ConfigurationInterface $configuration, ContainerBuilder $container);
}
<?php
namespace Ninja\BundleExtensionsBundle;
use Ninja\BundleExtensionsBundle\Factory\BundleExtensionInterface;
use Ninja\BundleExtensionsBundle\DependencyInjection\ExtensibleExtension;
use Symfony\Component\HttpKernel\Bundle\Bundle;
/**
* Extensible Bundle
*
* Adds the ability to add extensions to the bundle with a simple helper method
*
* @author CodingNinja
*/
class ExtensibleBundle extends Bundle {
/**
* @throws \LogicException Thrown if the ContainerExtension is not extensible
*/
public function __construct() {
if(false === ($this->getContainerExtension() instanceof ExtensibleExtension)) {
throw new \LogicException('An extensible bundles container extension must implement "Ninja\BundleExtensionsBundle\Configuration\ExtensibleConfigurationInterface"');
}
}
/**
* Registers a factory
*
* Proxy method to {@see Ninja\BundleExtensionsBundle\DependencyInjection\ExtensibleExtension::registerFactory()}
*
* @param string $alias The factory alias
* @param mixed $factory Your factory interface
* @return \Ninja\BundleExtensionsBundle\ExtensibleBundle
*/
public function registerFactory($alias, BundleExtensionInterface $factory) {
$this->getContainerExtension()->registerFactory($alias, $factory);
return $this;
}
}
<?php
namespace Ninja\BundleExtensionsBundle\Configuration;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Ninja\BawsBundle\Build\Step\Factory\StepFactory;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* Extensible Configuration
*
* Allows a configuration to have factories to extend a bundle
*
* @author CodingNinja
*/
abstract class ExtensibleConfiguration implements ExtensibleConfigurationInterface {
/**
* @var array The factories for the Configuration
*/
private $factories = array();
/**
* {@inheritdoc}
* @see Ninja\BundleExtensionsBundle\Configuration.ExtensibleConfigurationInterface::setFactories()
*/
public function setFactories(array $factories) {
$this->factories = $factories;
return $this;
}
/**
* Generates the configuration tree builder.
*
* @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
*/
public final function getConfigTreeBuilder() {
$treeBuilder = $this->getCoreConfigTreeBuilder();
foreach($this->factories as $factory) {
$factory->buildConfiguration($this->getFactoryNode($factory, $treeBuilder));
}
return $treeBuilder;
}
/**
* Get the node for a factory
*
* Get the node that should be passed to the Factory class
*
* @param StepFactory $factory The factory
* @param TreeBuilder $treeBuilder The full TreeBuilder for this bundle
*/
protected function getFactoryNode(StepFactory $factory, TreeBuilder $treeBuilder) {
return $treeBuilder->buildTree();
}
}
<?php
namespace Ninja\BundleExtensionsBundle\Configuration;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* Contract for an ExtensibleConfiguration to implement
*
* @author CodingNinja
*/
interface ExtensibleConfigurationInterface extends ConfigurationInterface {
/**
* Get the real config tree builder
*
* @return TreeBuilder The Tree builder
*/
function getCoreConfigTreeBuilder();
/**
* Set the factories
*
* @param array $factories The factories
*/
function setFactories(array $factories);
}
<?php
namespace Ninja\BundleExtensionsBundle\DependencyInjection;
use Ninja\BundleExtensionsBundle\Factory\BundleExtensionInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Ninja\BundleExtensionsBundle\Configuration\ExtensibleConfigurationInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension as BaseExtension;
/**
* Extensible Extension
*
* Proxy class to automatically configure the Configuration for
* the bundle factories and then calls the real method
*
* @author CodingNinja
*/
abstract class ExtensibleExtension extends BaseExtension {
/**
* @var array The registered factories
*/
private $factories = array();
/**
* {@inheritDoc}
*
* Sets the Configuration up and calls the {@see ExtensibleExtension::doLoad() proper load} method with
* the {@see ExtensibleExtension::getConfiguration() configuration}. It then calls each of the factories
* to add any extra services / parameters.
*/
public final function load(array $configs, ContainerBuilder $container)
{
$configuration = $this->getConfiguration($configs, $container);
if(false === ($configuration instanceof ExtensibleConfigurationInterface)) {
throw new \LogicExcetption('Configuration must implement Ninja\BundleExtensionsBundle\Configuration\ExtensibleConfigurationInterface');
}
$configuration->setFactories($this->factories);
$this->doLoad($configuration, $configs, $container);
foreach($this->factories as $factory) {
$factory->buildContainer($configs, $configuration, $container);
}
}
/**
* @param string $alias The factory alias
* @param mixed $factory Put your factory interface here
* @return \Ninja\BundleExtensionsBundle\DependencyInjection\ExtensibleExtension
*/
public function registerFactory($alias, BundleExtensionInterface $factory) {
$this->factories[$alias] = $factory;
return $this;
}
/**
* Do the loading
*
* This method replaces the old load method and gives you a pre-setup
* configuration class, to modify the configuration before you get it
* in this method, look at the {@see BaseExtension::getConfiguration()}
*
* @param ExtensibleConfigurationInterface $config
* @param array $configs
* @param ContainerBuilder $builder
*/
protected abstract function doLoad(ExtensibleConfigurationInterface $config, array $configs, ContainerBuilder $builder);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment