diff --git a/core/core.services.yml b/core/core.services.yml index afccb3177d0..66a534a46e6 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1256,7 +1256,7 @@ services: - { name: plugin_manager_cache_clear } image.toolkit.operation.manager: class: Drupal\Core\ImageToolkit\ImageToolkitOperationManager - arguments: ['@logger.channel.image'] + arguments: ['@logger.channel.image', '@image.toolkit.manager'] parent: default_plugin_manager tags: - { name: plugin_manager_cache_clear } diff --git a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php index 1bc09996e00..b6d3d7ee9ba 100644 --- a/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php +++ b/core/lib/Drupal/Core/ImageToolkit/ImageToolkitOperationManager.php @@ -32,6 +32,13 @@ class ImageToolkitOperationManager extends DefaultPluginManager implements Image */ protected $logger; + /** + * The image toolkit manager. + * + * @var \Drupal\Core\ImageToolkit\ImageToolkitManager + */ + protected $toolkitManager; + /** * Constructs the ImageToolkitOperationManager object. * @@ -44,20 +51,23 @@ class ImageToolkitOperationManager extends DefaultPluginManager implements Image * The module handler to invoke the alter hook with. * @param \Psr\Log\LoggerInterface $logger * A logger instance. + * @param \Drupal\Core\ImageToolkit\ImageToolkitManager $toolkit_manager + * The image toolkit manager. */ - public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, LoggerInterface $logger) { + public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, LoggerInterface $logger, ImageToolkitManager $toolkit_manager) { parent::__construct('Plugin/ImageToolkit/Operation', $namespaces, $module_handler, 'Drupal\Core\ImageToolkit\ImageToolkitOperationInterface', 'Drupal\Core\ImageToolkit\Annotation\ImageToolkitOperation'); $this->alterInfo('image_toolkit_operation'); $this->setCacheBackend($cache_backend, 'image_toolkit_operation_plugins'); $this->logger = $logger; + $this->toolkitManager = $toolkit_manager; } /** * Returns the plugin ID for a given toolkit and operation. * - * @param string $toolkit_id - * The toolkit plugin ID. + * @param \Drupal\Core\ImageToolkit\ImageToolkitInterface $toolkit + * The toolkit instance. * @param string $operation * The operation (e.g. "crop"). * @@ -67,7 +77,8 @@ class ImageToolkitOperationManager extends DefaultPluginManager implements Image * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException * When no plugin is available. */ - protected function getToolkitOperationPluginId($toolkit_id, $operation) { + protected function getToolkitOperationPluginId(ImageToolkitInterface $toolkit, $operation) { + $toolkit_id = $toolkit->getPluginId(); $definitions = $this->getDefinitions(); $definitions = array_filter($definitions, @@ -77,6 +88,14 @@ class ImageToolkitOperationManager extends DefaultPluginManager implements Image ); if (!$definitions) { + // If this image toolkit plugin is a derivative and returns no operation, + // try once again with its base plugin. + $base_toolkit_id = $toolkit->getBaseId(); + if (($toolkit_id != $base_toolkit_id) && !empty($base_toolkit_id)) { + $base_toolkit = $this->toolkitManager->createInstance($base_toolkit_id); + return $this->getToolkitOperationPluginId($base_toolkit, $operation); + } + $message = SafeMarkup::format("No image operation plugin for '@toolkit' toolkit and '@operation' operation.", array('@toolkit' => $toolkit_id, '@operation' => $operation)); throw new PluginNotFoundException($toolkit_id . '.' . $operation, $message); } @@ -102,7 +121,7 @@ class ImageToolkitOperationManager extends DefaultPluginManager implements Image * {@inheritdoc} */ public function getToolkitOperation(ImageToolkitInterface $toolkit, $operation) { - $plugin_id = $this->getToolkitOperationPluginId($toolkit->getPluginId(), $operation); + $plugin_id = $this->getToolkitOperationPluginId($toolkit, $operation); return $this->createInstance($plugin_id, array(), $toolkit); } diff --git a/core/modules/system/src/Tests/Image/ToolkitTest.php b/core/modules/system/src/Tests/Image/ToolkitTest.php index ea5bd5f661f..363fe08c81f 100644 --- a/core/modules/system/src/Tests/Image/ToolkitTest.php +++ b/core/modules/system/src/Tests/Image/ToolkitTest.php @@ -21,6 +21,7 @@ class ToolkitTest extends ToolkitTestBase { $manager = $this->container->get('image.toolkit.manager'); $toolkits = $manager->getAvailableToolkits(); $this->assertTrue(isset($toolkits['test']), 'The working toolkit was returned.'); + $this->assertTrue(isset($toolkits['test:derived_toolkit']), 'The derived toolkit was returned.'); $this->assertFalse(isset($toolkits['broken']), 'The toolkit marked unavailable was not returned'); $this->assertToolkitOperationsCalled(array()); } @@ -71,4 +72,22 @@ class ToolkitTest extends ToolkitTestBase { $this->assertEqual($calls['apply'][0][0], 'my_operation', "'my_operation' was passed correctly as operation"); $this->assertEqual($calls['apply'][0][1], array(), 'passing no parameters was handled correctly'); } + + /** + * Tests image toolkit operations inheritance by derivative toolkits. + */ + public function testDerivative() { + $toolkit_manager = $this->container->get('image.toolkit.manager'); + $operation_manager = $this->container->get('image.toolkit.operation.manager'); + + $toolkit = $toolkit_manager->createInstance('test:derived_toolkit'); + + // Load an overwritten and an inherited operation. + $blur = $operation_manager->getToolkitOperation($toolkit, 'blur'); + $invert = $operation_manager->getToolkitOperation($toolkit, 'invert'); + + $this->assertIdentical('foo_derived', $blur->getPluginId(), "'Blur' operation overwritten by derivative."); + $this->assertIdentical('bar', $invert->getPluginId(), '"Invert" operation inherited from base plugin.'); + } + } diff --git a/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/DerivedToolkit.php b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/DerivedToolkit.php new file mode 100644 index 00000000000..2df5c2b56a3 --- /dev/null +++ b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/DerivedToolkit.php @@ -0,0 +1,18 @@ +