Basically you can use the DIC by writing some services "tagged" with a special name.
For this you need to define your services into a file (following DIC specification) and tagging them in a particular way (Code will be took by Sonata Admin Bundle in this case, for explaination)
# MyBundle/Resources/config/admin.yml
services:
sonata.admin.tag:
class: YourNS\AdminBundle\Admin\BlogAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: posts, label: "Blog" }
arguments:
- ~
- YourNS\AdminBundle\Entity\Course
- 'SonataAdminBundle:CRUD'
calls:
- [ setTranslationDomain, [YourNSAdminBundle]]
In this case i'm defining a service called sonata.admin.tag that is tagged with sonata.admin tag.
I can define dozen of those, all with sonata.admin.tag tag name.
Once I've done this, I have to create a "special" file (that I'll place into bundle's DependencyInjection folder [for convention]) that is a CompilerPass file.
What is a CompilerPass file?
Compiler passes give you an opportunity to manipulate other service
definitions that have been registered with the service container.[...]
One of the most common use-cases of compiler passes is to work with
tagged services (read more about tags in the components section
"Working with Tagged Services").
and this is exactly what you need!
Now you have to search (into this file) for services tagged with (in this specific example) sonata.admin
class AddDependencyCallsCompilerPass implements CompilerPassInterface
{
/**
* {@inheritDoc}
*/
public function process(ContainerBuilder $container)
{
$groupDefaults = $admins = $classes = array();
$pool = $container->getDefinition('sonata.admin.pool');
foreach ($container->findTaggedServiceIds('sonata.admin') as $id => $tags) {
foreach ($tags as $attributes) {
$definition = $container->getDefinition($id);
$arguments = $definition->getArguments();
if (strlen($arguments[0]) == 0) {
$definition->replaceArgument(0, $id);
}
if (strlen($arguments[2]) == 0) {
$definition->replaceArgument(2, 'SonataAdminBundle:CRUD');
}
$this->applyConfigurationFromAttribute($definition, $attributes);
$this->applyDefaults($container, $id, $attributes);
$arguments = $definition->getArguments();
$admins[] = $id;
//other logic here
$pool->addMethodCall('setAdminClasses', array($classes));
As you can see here, we are searching for services tagged with sonata.admin ($container->findTaggedServiceIds('sonata.admin')) and we add those (in this case, that is specific for sonata admin bundle) to a $pool that is a ContainerBuilder
Now, we have to register a CompilerPass into our bundle file (the one you create before register bundle into application)
class SonataAdminBundle extends Bundle
{
/**
* {@inheritDoc}
*/
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new AddDependencyCallsCompilerPass());
}
}
Now, you have registered some kind of services only for this bundle. A service factory is more oriented for
Symfony2's Service Container provides a powerful way of controlling
the creation of objects, allowing you to specify arguments passed to
the constructor as well as calling methods and setting parameters.
Sometimes, however, this will not provide you with everything you need
to construct your objects.
or view it more like to an "entry point" for services instantiation.