summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2018-01-03 17:42:51 (GMT)
committerNathaniel Catchpole2018-01-03 17:42:51 (GMT)
commit5485720ee8b53acb7b666433667a6f83b192a80e (patch)
treede6afc974b042d45ad3c31750dc350132ea73c2c
parentc5fba61258904541e78a1eefdb9b2f9b344edc84 (diff)
Issue #2866779 by Mile23, dawehner: Add a way to trigger_error() for deprecated hooks
-rw-r--r--core/lib/Drupal/Core/Extension/ModuleHandler.php60
-rw-r--r--core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php89
-rw-r--r--core/modules/system/tests/modules/deprecation_test/deprecation_test.module14
-rw-r--r--core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerDeprecatedHookTest.php61
-rw-r--r--core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerDeprecatedHookUnimplementedTest.php33
5 files changed, 257 insertions, 0 deletions
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php
index d8d3608..ad539fd7 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php
@@ -414,6 +414,44 @@ class ModuleHandler implements ModuleHandlerInterface {
/**
* {@inheritdoc}
*/
+ public function invokeDeprecated($description, $module, $hook, array $args = array()) {
+ $result = $this->invoke($module, $hook, $args);
+ $this->triggerDeprecationError($description, $hook);
+ return $result;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function invokeAllDeprecated($description, $hook, array $args = array()) {
+ $result = $this->invokeAll($hook, $args);
+ $this->triggerDeprecationError($description, $hook);
+ return $result;
+ }
+
+
+ /**
+ * Triggers an E_USER_DEPRECATED error if any module implements the hook.
+ *
+ * @param string $description
+ * Helpful text describing what to do instead of implementing this hook.
+ * @param string $hook
+ * The name of the hook.
+ */
+ private function triggerDeprecationError($description, $hook) {
+ $modules = array_keys($this->getImplementationInfo($hook));
+ if (!empty($modules)) {
+ $message = 'The deprecated hook hook_' . $hook . '() is implemented in these functions: ';
+ $implementations = array_map(function ($module) use ($hook) {
+ return $module . '_' . $hook . '()';
+ }, $modules);
+ @trigger_error($message . implode(', ', $implementations) . '. ' . $description, E_USER_DEPRECATED);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
// Most of the time, $type is passed as a string, so for performance,
// normalize it to that. When passed as an array, usually the first item in
@@ -503,6 +541,28 @@ class ModuleHandler implements ModuleHandlerInterface {
}
/**
+ * {@inheritdoc}
+ */
+ public function alterDeprecated($description, $type, &$data, &$context1 = NULL, &$context2 = NULL) {
+ // Invoke the alter hook. This has the side effect of populating
+ // $this->alterFunctions.
+ $this->alter($type, $data, $context1, $context2);
+ // The $type parameter can be an array. alter() will deal with this
+ // internally, but we have to extract the proper $cid in order to discover
+ // implementations.
+ $cid = $type;
+ if (is_array($type)) {
+ $cid = implode(',', $type);
+ $extra_types = $type;
+ $type = array_shift($extra_types);
+ }
+ if (!empty($this->alterFunctions[$cid])) {
+ $message = 'The deprecated alter hook hook_' . $type . '_alter() is implemented in these functions: ' . implode(', ', $this->alterFunctions[$cid]) . '.';
+ @trigger_error($message . ' ' . $description, E_USER_DEPRECATED);
+ }
+ }
+
+ /**
* Provides information about modules' implementations of a hook.
*
* @param string $hook
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php b/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php
index 03d3f66..f1097e3 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php
@@ -239,6 +239,59 @@ interface ModuleHandlerInterface {
public function invokeAll($hook, array $args = []);
/**
+ * Invokes a deprecated hook in a particular module.
+ *
+ * Invoking a deprecated hook adds the behavior of triggering an
+ * E_USER_DEPRECATED error if any implementations are found.
+ *
+ * API maintainers should use this method instead of invoke() when their hook
+ * is deprecated. This method does not detect when a hook is deprecated.
+ *
+ * @param string $description
+ * Helpful text describing what to do instead of implementing this hook.
+ * @param string $module
+ * The name of the module (without the .module extension).
+ * @param string $hook
+ * The name of the hook to invoke.
+ * @param array $args
+ * Arguments to pass to the hook implementation.
+ *
+ * @return mixed
+ * The return value of the hook implementation.
+ *
+ * @see \Drupal\Core\Extension\ModuleHandlerInterface::invoke()
+ * @see https://www.drupal.org/core/deprecation#how-hook
+ */
+ public function invokeDeprecated($description, $module, $hook, array $args = []);
+
+ /**
+ * Invokes a deprecated hook in all enabled modules that implement it.
+ *
+ * Invoking a deprecated hook adds the behavior of triggering an
+ * E_USER_DEPRECATED error if any implementations are found.
+ *
+ * API maintainers should use this method instead of invokeAll() when their
+ * hook is deprecated. This method does not detect when a hook is deprecated.
+ *
+ * @param string $description
+ * Helpful text describing what to do instead of implementing this hook.
+ * @param string $hook
+ * The name of the hook to invoke.
+ * @param array $args
+ * Arguments to pass to the hook.
+ *
+ * @return array
+ * An array of return values of the hook implementations. If modules return
+ * arrays from their implementations, those are merged into one array
+ * recursively. Note: integer keys in arrays will be lost, as the merge is
+ * done using array_merge_recursive().
+ *
+ * @see \Drupal\Core\Extension\ModuleHandlerInterface::invokeAll()
+ * @see https://www.drupal.org/core/deprecation#how-hook
+ */
+ public function invokeAllDeprecated($description, $hook, array $args = []);
+
+ /**
* Passes alterable variables to specific hook_TYPE_alter() implementations.
*
* This dispatch function hands off the passed-in variables to type-specific
@@ -290,6 +343,42 @@ interface ModuleHandlerInterface {
public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL);
/**
+ * Passes alterable variables to deprecated hook_TYPE_alter() implementations.
+ *
+ * This method triggers an E_USER_DEPRECATED error if any implementations of
+ * the alter hook are found. It is otherwise identical to alter().
+ *
+ * See the documentation for alter() for more details.
+ *
+ * @param string $description
+ * Helpful text describing what to do instead of implementing this alter
+ * hook.
+ * @param string|array $type
+ * A string describing the type of the alterable $data. 'form', 'links',
+ * 'node_content', and so on are several examples. Alternatively can be an
+ * array, in which case hook_TYPE_alter() is invoked for each value in the
+ * array, ordered first by module, and then for each module, in the order of
+ * values in $type. For example, when Form API is using $this->alter() to
+ * execute both hook_form_alter() and hook_form_FORM_ID_alter()
+ * implementations, it passes array('form', 'form_' . $form_id) for $type.
+ * @param mixed $data
+ * The variable that will be passed to hook_TYPE_alter() implementations to be
+ * altered. The type of this variable depends on the value of the $type
+ * argument. For example, when altering a 'form', $data will be a structured
+ * array. When altering a 'profile', $data will be an object.
+ * @param mixed $context1
+ * (optional) An additional variable that is passed by reference.
+ * @param mixed $context2
+ * (optional) An additional variable that is passed by reference. If more
+ * context needs to be provided to implementations, then this should be an
+ * associative array as described above.
+ *
+ * @see \Drupal\Core\Extension\ModuleHandlerInterface::alter()
+ * @see https://www.drupal.org/core/deprecation#how-hook
+ */
+ public function alterDeprecated($description, $type, &$data, &$context1 = NULL, &$context2 = NULL);
+
+ /**
* Returns an array of directories for all enabled modules. Useful for
* tasks such as finding a file that exists in all module directories.
*
diff --git a/core/modules/system/tests/modules/deprecation_test/deprecation_test.module b/core/modules/system/tests/modules/deprecation_test/deprecation_test.module
index e255021..69217db 100644
--- a/core/modules/system/tests/modules/deprecation_test/deprecation_test.module
+++ b/core/modules/system/tests/modules/deprecation_test/deprecation_test.module
@@ -18,3 +18,17 @@ function deprecation_test_function() {
@trigger_error('This is the deprecation message for deprecation_test_function().', E_USER_DEPRECATED);
return 'known_return_value';
}
+
+/**
+ * Implements hook_deprecated_hook().
+ */
+function deprecation_test_deprecated_hook($arg) {
+ return $arg;
+}
+
+/**
+ * Implements hook_deprecated_alter_alter().
+ */
+function deprecation_test_deprecated_alter_alter(&$data, $context1, $context2) {
+ $data = [$context1, $context2];
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerDeprecatedHookTest.php b/core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerDeprecatedHookTest.php
new file mode 100644
index 0000000..1824563
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerDeprecatedHookTest.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Extension;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Test whether deprecated hook invocations trigger errors.
+ *
+ * @group Extension
+ * @group legacy
+ *
+ * @coversDefaultClass Drupal\Core\Extension\ModuleHandler
+ */
+class ModuleHandlerDeprecatedHookTest extends KernelTestBase {
+
+ protected static $modules = ['deprecation_test'];
+
+ /**
+ * @covers ::invokeDeprecated
+ * @expectedDeprecation The deprecated hook hook_deprecated_hook() is implemented in these functions: deprecation_test_deprecated_hook(). Use something else.
+ */
+ public function testInvokeDeprecated() {
+ /* @var $module_handler \Drupal\Core\Extension\ModuleHandlerInterface */
+ $module_handler = $this->container->get('module_handler');
+ $arg = 'an_arg';
+ $this->assertEqual(
+ $arg,
+ $module_handler->invokeDeprecated('Use something else.', 'deprecation_test', 'deprecated_hook', [$arg])
+ );
+ }
+
+ /**
+ * @covers ::invokeAllDeprecated
+ * @expectedDeprecation The deprecated hook hook_deprecated_hook() is implemented in these functions: deprecation_test_deprecated_hook(). Use something else.
+ */
+ public function testInvokeAllDeprecated() {
+ /* @var $module_handler \Drupal\Core\Extension\ModuleHandlerInterface */
+ $module_handler = $this->container->get('module_handler');
+ $arg = 'an_arg';
+ $this->assertEqual(
+ [$arg],
+ $module_handler->invokeAllDeprecated('Use something else.', 'deprecated_hook', [$arg])
+ );
+ }
+
+ /**
+ * @covers ::alterDeprecated
+ * @expectedDeprecation The deprecated alter hook hook_deprecated_alter_alter() is implemented in these functions: deprecation_test_deprecated_alter_alter. Alter something else.
+ */
+ public function testAlterDeprecated() {
+ /* @var $module_handler \Drupal\Core\Extension\ModuleHandlerInterface */
+ $module_handler = $this->container->get('module_handler');
+ $data = [];
+ $context1 = 'test1';
+ $context2 = 'test2';
+ $module_handler->alterDeprecated('Alter something else.', 'deprecated_alter', $data, $context1, $context2);
+ $this->assertEqual([$context1, $context2], $data);
+ }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerDeprecatedHookUnimplementedTest.php b/core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerDeprecatedHookUnimplementedTest.php
new file mode 100644
index 0000000..1d4e833
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Extension/ModuleHandlerDeprecatedHookUnimplementedTest.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Extension;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Test whether unimplemented deprecated hook invocations trigger errors.
+ *
+ * @group Extension
+ *
+ * @coversDefaultClass Drupal\Core\Extension\ModuleHandler
+ */
+class ModuleHandlerDeprecatedHookUnimplementedTest extends KernelTestBase {
+
+ /**
+ * @covers ::alterDeprecated
+ * @covers ::invokeAllDeprecated
+ * @covers ::invokeDeprecated
+ */
+ public function testUnimplementedHooks() {
+ $unimplemented_hook_name = 'unimplemented_hook_name';
+
+ /* @var $module_handler \Drupal\Core\Extension\ModuleHandlerInterface */
+ $module_handler = $this->container->get('module_handler');
+
+ $module_handler->invokeDeprecated('Use something else.', 'deprecation_test', $unimplemented_hook_name);
+ $module_handler->invokeAllDeprecated('Use something else.', $unimplemented_hook_name);
+ $data = [];
+ $module_handler->alterDeprecated('Alter something else.', $unimplemented_hook_name, $data);
+ }
+
+}