Backwards compatible bundle releases

Posted by Unknown on Saturday, September 27, 2014

The problem


With a new bundle release you may want to rename services or parameters, make a service private, change some constructor arguments, change the structure of the bundle configuration, etc. Some of these changes may acually be backwards incompatible changes for the users of that bundle. Luckily, the Symfony DependenyInjection component and Config component both provide you with some options to prevent such backwards compatibility (BC) breaks. If you want to know more about backwards compatibility and bundle versioning, please read my previous article on this subject.


This article gives you an overview of the things you can do to prevent BC breaks between releases of your bundles.


Renaming things


The bundle itself


You can't, without introducing a BC break.



// don't change the name
class MyOldBundle extends Bundle
{
}


The container extension alias


You can't, without introducing a BC break.



use Symfony\Component\HttpKernel\DependencyInjection\Extension;

class MyBundleExtension extends Extension
{
...

public function getAlias()
{
// don't do this
return 'new_name';
}
}


Parameters


If you want to change the name of a parameter, just copy the parameter instead of actually renaming it:



parameters:
old_parameter: same_value
new_parameter: same_value



class MyBundleExtension extends Extension
{
public function load(array $config, ContainerBuilder $container)
{
$container->setParameter('old_parameter', 'same_value');
$container->setParameter('new_parameter', 'same_value');
}
}


Config keys


The container extension alias can not be changed without causing a BC break, but it is possible to rename config keys. Just make sure you fix the structure of any existing user configuration values before processing the configuration:



class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('my');

$rootNode
->beforeNormalization()
->always(function(array $v) {
if (isset($v['old_name'])) {
// move existing values to the right key
$v['new_name'] = $v['old_name'];

// remove invalid key
unset($v['old_name']);
}

return $v;
})
->end()
->children()
->scalarNode('new_name')->end()
->end()
;
}
}


Service definitions


If you want to rename a service definition, add an alias with the name of the old service:



services:
new_service_name:
...

old_service_name:
alias: new_service_name


This may cause a problem in user code, because during the container build phase they may call $container->getDefinition('old_service_name') which will cause an error if old_service_name is not an actual service definition, but an alias. This is why user code should always use $container->findDefintion($id), which resolves aliases to their actual service definitions.


Method names for setter injection



services:
subject_service:
calls:
# we want to change the name of the method: addListener
- [addListener, [@listener1]]
- [addListener, [@listener2]]


This one is actually in the grey area between the bundle and the library. You can only change the method names used for setter injection if users aren't supposed to call those methods themselves. This should actually never be the case. You should just offer an extension point that takes away the need for users to call those methods. The best option is to create a compiler pass for that:



namespace MyBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;

class InjectListenersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$subjectDefinition = $container->findDefintion('subject');

foreach ($container->findTaggedServiceIds('listener') as $serviceId => $tags) {
$subjectDefinition->addMethodCall(
'addListener',
array(new Reference($serviceId))
);
}
}
}


Truncated by Planet PHP, read more at the original (another 4278 bytes)




more

{ 0 comments... » Backwards compatible bundle releases read them below or add one }

Post a Comment

Popular Posts