Issue #2028511 by damiankloip, dawehner: Allow plugin derivative classes to use services from the container.

8.0.x
Alex Pott 2013-07-19 10:08:06 +01:00
parent 535ed4185b
commit bd51e51a90
7 changed files with 248 additions and 5 deletions

View File

@ -8,7 +8,7 @@
namespace Drupal\Core\Plugin;
use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
use Drupal\Component\Plugin\PluginManagerBase;
use Drupal\Component\Plugin\PluginManagerInterface;
use Drupal\Component\Utility\NestedArray;
@ -98,7 +98,7 @@ class DefaultPluginManager extends PluginManagerBase implements PluginManagerInt
public function __construct($subdir, \Traversable $namespaces, $annotation_namespaces = array(), $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin') {
$this->subdir = $subdir;
$this->discovery = new AnnotatedClassDiscovery($subdir, $namespaces, $annotation_namespaces, $plugin_definition_annotation_name);
$this->discovery = new DerivativeDiscoveryDecorator($this->discovery);
$this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
$this->factory = new ContainerFactory($this);
}

View File

@ -0,0 +1,35 @@
<?php
/**
* @file
* Contains \Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator.
*/
namespace Drupal\Core\Plugin\Discovery;
use Drupal\Component\Plugin\Discovery\DerivativeDiscoveryDecorator;
class ContainerDerivativeDiscoveryDecorator extends DerivativeDiscoveryDecorator {
/**
* {@inheritdoc}
*/
protected function getDerivativeFetcher($base_plugin_id, array $base_definition) {
if (!isset($this->derivativeFetchers[$base_plugin_id])) {
$this->derivativeFetchers[$base_plugin_id] = FALSE;
if (isset($base_definition['derivative'])) {
$class = $base_definition['derivative'];
// If the derivative class provides a factory method, pass the container
// to it.
if (is_subclass_of($class, 'Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface')) {
$this->derivativeFetchers[$base_plugin_id] = $class::create(\Drupal::getContainer(), $base_plugin_id);
}
else {
$this->derivativeFetchers[$base_plugin_id] = new $class($base_plugin_id);
}
}
}
return $this->derivativeFetchers[$base_plugin_id] ?: NULL;
}
}

View File

@ -0,0 +1,30 @@
<?php
/**
* @file
* Contains \Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface.
*/
namespace Drupal\Core\Plugin\Discovery;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Derivative fetcher interface to pass the container to static create method.
*/
interface ContainerDerivativeInterface {
/**
* Creates an instance of the derivative fetcher.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The container to pull out services used in the fetcher.
* @param string $plugin_id
* The base plugin ID for the plugin ID.
*
* @return static
* Returns an instance of this fetcher.
*/
public static function create(ContainerInterface $container, $base_plugin_id);
}

View File

@ -7,14 +7,16 @@
namespace Drupal\views\Plugin\Derivative;
use Drupal\Component\Plugin\Derivative\DerivativeInterface;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides block plugin definitions for all Views block displays.
*
* @see \Drupal\views\Plugin\block\block\ViewsBlock
*/
class ViewsBlock implements DerivativeInterface {
class ViewsBlock implements ContainerDerivativeInterface {
/**
* List of derivative definitions.
@ -23,6 +25,43 @@ class ViewsBlock implements DerivativeInterface {
*/
protected $derivatives = array();
/**
* The base plugin ID.
*
* @var string
*/
protected $base_plugin_id;
/**
* The view storage controller.
*
* @var \Drupal\Core\Entity\EntityStorageControllerInterface
*/
protected $viewStorageController;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static(
$base_plugin_id,
$container->get('plugin.manager.entity')->getStorageController('view')
);
}
/**
* Constructs a ViewsBlock object.
*
* @param string $base_plugin_id
* The base plugin ID.
* @param \Drupal\Core\Entity\EntityStorageControllerInterface $view_storage_controller
* The entity storage controller to load views.
*/
public function __construct($base_plugin_id, EntityStorageControllerInterface $view_storage_controller) {
$this->basePluginId = $base_plugin_id;
$this->viewStorageController = $view_storage_controller;
}
/**
* Implements \Drupal\Component\Plugin\Derivative\DerivativeInterface::getDerivativeDefinition().
*/
@ -39,7 +78,7 @@ class ViewsBlock implements DerivativeInterface {
*/
public function getDerivativeDefinitions(array $base_plugin_definition) {
// Check all Views for block displays.
foreach (views_get_all_views() as $view) {
foreach ($this->viewStorageController->loadMultiple() as $view) {
// Do not return results for disabled views.
if (!$view->status()) {
continue;

View File

@ -0,0 +1,68 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecoratorTest.
*/
namespace Drupal\Tests\Core\Plugin\Discovery;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
use Drupal\Tests\UnitTestCase;
/**
* Tests the container aware derivative discovery decorator.
*/
class ContainerDerivativeDiscoveryDecoratorTest extends UnitTestCase {
/**
* {@inheritdoc}
*/
public static function getInfo() {
return array(
'name' => 'Container aware derivative discovery decorator.',
'description' => 'Tests the container aware derivative discovery decorator.',
'group' => 'Plugin',
);
}
/**
* Tests the getDerivativeFetcher method.
*
* @see \Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator::getDerivativeFetcher().
*/
public function testGetDerivativeFetcher() {
$example_service = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$example_container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')
->setMethods(array('get'))
->getMock();
$example_container->expects($this->once())
->method('get')
->with($this->equalTo('example_service'))
->will($this->returnValue($example_service));
\Drupal::setContainer($example_container);
$definitions = array();
$definitions['container_aware_discovery'] = array(
'id' => 'container_aware_discovery',
'derivative' => '\Drupal\Tests\Core\Plugin\Discovery\TestContainerDerivativeDiscovery',
);
$definitions['non_container_aware_discovery'] = array(
'id' => 'non_container_aware_discovery',
'derivative' => '\Drupal\Tests\Core\Plugin\Discovery\TestDerivativeDiscovery',
);
$discovery_main = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
$discovery_main->expects($this->any())
->method('getDefinitions')
->will($this->returnValue($definitions));
$discovery = new ContainerDerivativeDiscoveryDecorator($discovery_main);
$definitions = $discovery->getDefinitions();
// Ensure that both the instances from container and non-container test derivatives got added.
$this->assertEquals(4, count($definitions));
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Plugin\Discovery\TestContainerDerivativeDiscovery.
*/
namespace Drupal\Tests\Core\Plugin\Discovery;
use Drupal\Core\Plugin\Discovery\ContainerDerivativeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Defines container test derivative discovery.
*/
class TestContainerDerivativeDiscovery extends TestDerivativeDiscovery implements ContainerDerivativeInterface {
/**
* Constructs a TestContainerDerivativeDiscovery object.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $example_service
* Some service.
*/
public function __construct(EventDispatcherInterface $example_service) {
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static($container->get('example_service'));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Plugin\Discovery\TestDiscovery.
*/
namespace Drupal\Tests\Core\Plugin\Discovery;
use Drupal\Component\Plugin\Derivative\DerivativeInterface;
/**
* Defines test derivative discovery.
*/
class TestDerivativeDiscovery implements DerivativeInterface {
/**
* {@inheritdoc}
*/
public function getDerivativeDefinition($derivative_id, array $base_plugin_definition) {
$definitions = $this->getDerivativeDefinitions($base_plugin_definition);
return $definitions[$derivative_id];
}
/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions(array $base_plugin_definition) {
$plugins = array();
for ($i = 0; $i < 2; $i++) {
$plugins['test_discovery_' . $i] = $base_plugin_definition;
}
return $plugins;
}
}