whitebear whitebear -4 years ago 209
PHP Question

Override DependencyInjection or unload XML/YML

I have mybundle to override SonataMediaBundle,

So,this is my bundle

Application\Sonata\MediaBundle\DependencyInjection\ApplicationSonataMediaExtension

class ApplicationSonataMediaExtension extends Extension
{
/**
* {@inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('myservice.xml');
}


and this is original DependancyInjection.
Sonata\MediaBundle\DependencyInjection\SonataMediaExtension

class SonataMediaExtension extends Extension
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$processor = new Processor();
$configuration = new Configuration();
$config = $processor->processConfiguration($configuration, $configs);

$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('provider.xml');
$loader->load('media.xml');
$loader->load('twig.xml');
$loader->load('security.xml');
$loader->load('extra.xml');
$loader->load('form.xml');
$loader->load('gaufrette.xml');

// NEXT_MAJOR: Remove Following lines
$amazonS3Definition = $container->getDefinition('sonata.media.adapter.service.s3');
if (method_exists($amazonS3Definition, 'setFactory')) {
$amazonS3Definition->setFactory(array('Aws\S3\S3Client', 'factory'));
} else {
$amazonS3Definition->setFactoryClass('Aws\S3\S3Client');
$amazonS3Definition->setFactoryMethod('factory');
}

// NEXT_MAJOR: Remove Following lines
$openCloudDefinition = $container->getDefinition('sonata.media.adapter.filesystem.opencloud.objectstore');
if (method_exists($openCloudDefinition, 'setFactory')) {
$openCloudDefinition->setFactory(array(new Reference('sonata.media.adapter.filesystem.opencloud.connection'), 'ObjectStore'));
} else {
$openCloudDefinition->setFactoryService('sonata.media.adapter.filesystem.opencloud.connection');
$openCloudDefinition->setFactoryMethod('ObjectStore');
}

$loader->load('validators.xml');
$loader->load('serializer.xml');

if (!in_array(strtolower($config['db_driver']), array('doctrine_orm', 'doctrine_mongodb', 'doctrine_phpcr'))) {
throw new \InvalidArgumentException(sprintf('SonataMediaBundle - Invalid db driver "%s".', $config['db_driver']));
}

$bundles = $container->getParameter('kernel.bundles');

if (isset($bundles['FOSRestBundle']) && isset($bundles['NelmioApiDocBundle'])) {
$loader->load(sprintf('api_form_%s.xml', $config['db_driver']));

if ('doctrine_orm' == $config['db_driver']) {
$loader->load('api_controllers.xml');
}
}

if (isset($bundles['SonataNotificationBundle'])) {
$loader->load('consumer.xml');
}

if (isset($bundles['SonataFormatterBundle'])) {
$loader->load('formatter.xml');
}

if (isset($bundles['SonataBlockBundle'])) {
$loader->load('block.xml');
}

if (isset($bundles['SonataSeoBundle'])) {
$loader->load('seo_block.xml');
}

if (!isset($bundles['LiipImagineBundle'])) {
$container->removeDefinition('sonata.media.thumbnail.liip_imagine');
}

if (!array_key_exists($config['default_context'], $config['contexts'])) {
throw new \InvalidArgumentException(sprintf('SonataMediaBundle - Invalid default context : %s, available : %s', $config['default_context'], json_encode(array_keys($config['contexts']))));
}

$loader->load(sprintf('%s.xml', $config['db_driver']));

if (isset($bundles['SonataAdminBundle'])) {
$loader->load(sprintf('%s_admin.xml', $config['db_driver']));
}

$this->configureFilesystemAdapter($container, $config);
$this->configureCdnAdapter($container, $config);

$pool = $container->getDefinition('sonata.media.pool');
$pool->replaceArgument(0, $config['default_context']);

// this shameless hack is done in order to have one clean configuration
// for adding formats ....
$pool->addMethodCall('__hack__', $config);

$strategies = array();

foreach ($config['contexts'] as $name => $settings) {
$formats = array();

foreach ($settings['formats'] as $format => $value) {
$formats[$name.'_'.$format] = $value;
}

$strategies[] = $settings['download']['strategy'];
$pool->addMethodCall('addContext', array($name, $settings['providers'], $formats, $settings['download']));
}

$container->setParameter('sonata.media.admin_format', $config['admin_format']);

$strategies = array_unique($strategies);

foreach ($strategies as $strategyId) {
$pool->addMethodCall('addDownloadStrategy', array($strategyId, new Reference($strategyId)));
}

if ('doctrine_orm' == $config['db_driver']) {
$this->registerDoctrineMapping($config);
}

$container->setParameter('sonata.media.resizer.simple.adapter.mode', $config['resizer']['simple']['mode']);
$container->setParameter('sonata.media.resizer.square.adapter.mode', $config['resizer']['square']['mode']);

$this->configureParameterClass($container, $config);
$this->configureExtra($container, $config);
$this->configureBuzz($container, $config);
$this->configureProviders($container, $config);
$this->configureAdapters($container, $config);
$this->configureResizers($container, $config);
$this->configureClassesToCompile();
}


Normally this way is enough to my service, but in my case.

I would like to unload some xml loaded in original DependancyInjection.

for example

$loader->load('media.xml');
is loaded in original one.

However I don't want to let this loaded.

I have two ideas


  1. unload in my bundle

  2. override(copy all script) original bundle and comment out.,but how can I override???



How can I do this ???




I want to remove yml for admin.
Sonata\MediaBundle\DependencyInjection\SonataMediaExtension

if (isset($bundles['SonataAdminBundle'])) {
$loader->load(sprintf('%s_admin.xml', $config['db_driver']));
}


This quesion is related with
How to override xml under config directory to hide SonataMediaBundle and Classification setting from dashboard




Thanks to @dbrumann comment, I decided to use CompilerPass.

I implemented

in Acme\AdminBundle\AcmeAdminBundle

namespace Acme\AdminBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Acme\AdminBundle\DependencyInjection\Compiler\CustomPass;
//use \Symfony\Component\DependencyInjection\Compiler\PassConfig;

class AcmeAdminBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);

$container->addCompilerPass(new CustomPass());
}


in CustomPass

namespace Acme\AdminBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class CustomPass implements CompilerPassInterface {
public function process(ContainerBuilder $container)
{
var_dump($container->getDefinitions());
if ($container->hasDefinition('sonata.admin.arobject')) //I have arobject entity on dashboard
{
$container->removeDefinition('sonata.admin.arobject');
}
}
}


It looks like I have step forward. however this error happens.

[2/2] FileLoaderLoadException: You have requested a non-existent service "sonata.admin.arobject". Did you mean one of these: "sonata.admin.armarket", "sonata.admin.artracker", "sonata.admin.exporter", "sonata.admin.helper", "sonata.admin.placecat", "sonata.admin.pool", "sonata.admin.user"? in . (which is being imported from "/Users/whitebear/CodingWorks/httproot/arserver/app/config/routing.yml").


mysteriously
$container->hasDefinition('sonata.admin.arobject')
returns true, but,
$container->removeDefinition('sonata.admin.arobject')
returns the error above.

This is my var_dump($container->getDefinitions()) log




Finally I found out there is two way to slove this problem.

1) Use CompilerPass

2) Load new service.xml

If you have trouble in removing mediabundle and classificationbundle from admin dashboard.

please check here

Answer Source

What you are attempting to do sounds very dangerous. I'm not very familiar with SonataAdminBundle, but when the bundle is working with the provided services you will break it. Maybe you can extend the question with an explanation as to why you want to unload those services.

In the meantime you might want to checkout CompilerPasses. They run before the container is built and can alter it. You could call removeDefinition() on the ContainerBuilder to get rid of the services. Instead of unloading the service you specifically remove the definitions you want to remove. Alternatively you could replace them with other services or alter them to your needs.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download