diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php index c27f2bc..ddfe285 100644 --- a/core/lib/Drupal/Core/Extension/ModuleHandler.php +++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Extension; use Drupal\Component\Graph\Graph; +use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Symfony\Component\Yaml\Parser; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\CacheBackendInterface; @@ -42,6 +43,13 @@ class ModuleHandler implements ModuleHandlerInterface { protected $loaded = FALSE; /** + * Array of initialized module Hook objects. + * + * @var \Drupal\Core\DependencyInjection\ContainerInjectionInterface[] + */ + protected $hookObjects = array(); + + /** * List of hook implementations keyed by hook name. * * @var array @@ -246,7 +254,21 @@ public function getHookInfo() { foreach ($this->moduleList as $module => $filename) { $function = $this->moduleList[$module]->hookPrefix . 'hook_info'; if (is_callable($function)) { - $result = $function(); + if (strpos($function, '::') !== FALSE) { + list($class, $method) = explode('::', $function); + if (in_array('Drupal\Core\DependencyInjection\ContainerInjectionInterface', class_implements($class))) { + if (!isset($this->hookObjects[$class])) { + $this->hookObjects[$class] = $class::create(\Drupal::getContainer()); + } + $result = $this->hookObjects[$class]->{$method}(); + } + else { + $result = $function(); + } + } + else { + $result = $function(); + } if (isset($result) && is_array($result)) { $this->hookInfo = NestedArray::mergeDeep($this->hookInfo, $result); } @@ -281,6 +303,15 @@ public function implementsHook($module, $hook) { } $function = $this->moduleList[$module]->hookPrefix . $hook; if (is_callable($function)) { + if (strpos($function, '::') !== FALSE) { + list($class, $method) = explode('::', $function); + if (in_array('Drupal\Core\DependencyInjection\ContainerInjectionInterface', class_implements($class))) { + if (!isset($this->hookObjects[$class])) { + $this->hookObjects[$class] = $class::create(\Drupal::getContainer()); + } + return array($this->hookObjects[$class], $method); + } + } return $function; } // @todo Remove this legacy fallback. diff --git a/core/modules/system/lib/Drupal/system/Tests/Extension/ModuleHookTest.php b/core/modules/system/lib/Drupal/system/Tests/Extension/ModuleHookTest.php index 1972ea2..1fd8895 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Extension/ModuleHookTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Extension/ModuleHookTest.php @@ -14,7 +14,7 @@ */ class ModuleHookTest extends DrupalUnitTestBase { - public static $modules = array('module_test'); + public static $modules = array('module_test', 'requirements1_test'); /** * {@inheritdoc} @@ -50,6 +50,17 @@ public function testHookFunction() { } /** + * Tests object-oriented Hook class invocations with container-injection. + */ + public function testHookContainerInjection() { + $result = $this->moduleHandler()->invoke('requirements1_test', 'test_hook_container_injection'); + $this->assertIdentical($result, 'Foobar'); + + $result = $this->moduleHandler()->invokeAll('test_hook_container_injection'); + $this->assertIdentical($result, array('Foobar')); + } + + /** * Returns the module handler service. * * @return \Drupal\Core\Extension\ModulerHandlerInterface diff --git a/core/modules/system/tests/modules/requirements1_test/lib/Drupal/requirements1_test/Hook.php b/core/modules/system/tests/modules/requirements1_test/lib/Drupal/requirements1_test/Hook.php new file mode 100644 index 0000000..b3723c0 --- /dev/null +++ b/core/modules/system/tests/modules/requirements1_test/lib/Drupal/requirements1_test/Hook.php @@ -0,0 +1,56 @@ +get('cache.default')); + } + + /** + * Constructs a new \Drupal\requirements1_test\Hook object. + */ + public function __construct(CacheBackendInterface $cache) { + $this->cache = $cache; + if ($cache->get('requirements1_test_cid')) { + // If the value is already set, then we change the value - this will catch + // that the Hook object is only created once per request. + $cache->set('requirements1_test_cid', 'Barfoo'); + } + else { + $cache->set('requirements1_test_cid', 'Foobar'); + } + } + + /** + * Implements hook_test_hook_container_injection(). + */ + public function test_hook_container_injection() { + $value = $this->cache->get('requirements1_test_cid'); + if ($value) { + return $value->data; + } + return FALSE; + } + +}