Issue #2616814 by dpi, Xano, geek-merlin, Hardik_Patel_12, jofitz, alexpott, Fabianx, catch, joachim, andypost, dawehner, daffie, cweagans, neclimdul: Delegate all hook invocations to ModuleHandler
parent
fb3dc749ac
commit
7e81e515da
|
@ -312,10 +312,9 @@ class AssetResolver implements AssetResolverInterface {
|
|||
if ($settings_required && $settings_have_changed) {
|
||||
$settings = $this->getJsSettingsAssets($assets);
|
||||
// Allow modules to add cached JavaScript settings.
|
||||
foreach ($this->moduleHandler->getImplementations('js_settings_build') as $module) {
|
||||
$function = $module . '_js_settings_build';
|
||||
$function($settings, $assets);
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith('js_settings_build', function (callable $hook, string $module) use (&$settings, $assets) {
|
||||
$hook($settings, $assets);
|
||||
});
|
||||
}
|
||||
$settings_in_header = in_array('core/drupalSettings', $header_js_libraries);
|
||||
$this->cache->set($cid, [$js_assets_header, $js_assets_footer, $settings, $settings_in_header], CacheBackendInterface::CACHE_PERMANENT, ['library_info']);
|
||||
|
|
|
@ -358,7 +358,7 @@ class LibraryDiscoveryParser {
|
|||
|
||||
// Allow modules to add dynamic library definitions.
|
||||
$hook = 'library_info_build';
|
||||
if ($this->moduleHandler->implementsHook($extension, $hook)) {
|
||||
if ($this->moduleHandler->hasImplementations($hook, $extension)) {
|
||||
$libraries = NestedArray::mergeDeep($libraries, $this->moduleHandler->invoke($extension, $hook));
|
||||
}
|
||||
|
||||
|
|
|
@ -229,8 +229,7 @@ class Cron implements CronInterface {
|
|||
$logger = $time_logging_enabled ? $this->logger : new NullLogger();
|
||||
|
||||
// Iterate through the modules calling their cron handlers (if any):
|
||||
foreach ($this->moduleHandler->getImplementations('cron') as $module) {
|
||||
|
||||
$this->moduleHandler->invokeAllWith('cron', function (callable $hook, string $module) use (&$module_previous, $logger) {
|
||||
if (!$module_previous) {
|
||||
$logger->info('Starting execution of @module_cron().', [
|
||||
'@module' => $module,
|
||||
|
@ -247,7 +246,7 @@ class Cron implements CronInterface {
|
|||
|
||||
// Do not let an exception thrown by one module disturb another.
|
||||
try {
|
||||
$this->moduleHandler->invoke($module, 'cron');
|
||||
$hook();
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
watchdog_exception('cron', $e);
|
||||
|
@ -255,7 +254,7 @@ class Cron implements CronInterface {
|
|||
|
||||
Timer::stop('cron_' . $module);
|
||||
$module_previous = $module;
|
||||
}
|
||||
});
|
||||
if ($module_previous) {
|
||||
$logger->info('Execution of @module_previous_cron() took @time.', [
|
||||
'@module_previous' => $module_previous,
|
||||
|
|
|
@ -862,15 +862,19 @@ abstract class ContentEntityStorageBase extends EntityStorageBase implements Con
|
|||
protected function invokeStorageLoadHook(array &$entities) {
|
||||
if (!empty($entities)) {
|
||||
// Call hook_entity_storage_load().
|
||||
foreach ($this->moduleHandler()->getImplementations('entity_storage_load') as $module) {
|
||||
$function = $module . '_entity_storage_load';
|
||||
$function($entities, $this->entityTypeId);
|
||||
}
|
||||
$this->moduleHandler()->invokeAllWith(
|
||||
'entity_storage_load',
|
||||
function (callable $hook, string $module) use (&$entities) {
|
||||
$hook($entities, $this->entityTypeId);
|
||||
}
|
||||
);
|
||||
// Call hook_TYPE_storage_load().
|
||||
foreach ($this->moduleHandler()->getImplementations($this->entityTypeId . '_storage_load') as $module) {
|
||||
$function = $module . '_' . $this->entityTypeId . '_storage_load';
|
||||
$function($entities);
|
||||
}
|
||||
$this->moduleHandler()->invokeAllWith(
|
||||
$this->entityTypeId . '_storage_load',
|
||||
function (callable $hook, string $module) use (&$entities) {
|
||||
$hook($entities);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -342,10 +342,12 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
|
|||
// Invoke hook and collect grants/denies for field access from other
|
||||
// modules.
|
||||
$grants = [];
|
||||
$hook_implementations = $this->moduleHandler()->getImplementations('entity_field_access');
|
||||
foreach ($hook_implementations as $module) {
|
||||
$grants[] = [$module => $this->moduleHandler()->invoke($module, 'entity_field_access', [$operation, $field_definition, $account, $items])];
|
||||
}
|
||||
$this->moduleHandler()->invokeAllWith(
|
||||
'entity_field_access',
|
||||
function (callable $hook, string $module) use ($operation, $field_definition, $account, $items, &$grants) {
|
||||
$grants[] = [$module => $hook($operation, $field_definition, $account, $items)];
|
||||
}
|
||||
);
|
||||
// Our default access flag is masked under the ':default' key.
|
||||
$grants = array_merge([':default' => $default], ...$grants);
|
||||
|
||||
|
|
|
@ -282,9 +282,10 @@ class EntityFieldManager implements EntityFieldManagerInterface {
|
|||
}
|
||||
|
||||
// Retrieve base field definitions from modules.
|
||||
foreach ($this->moduleHandler->getImplementations('entity_base_field_info') as $module) {
|
||||
$module_definitions = $this->moduleHandler->invoke($module, 'entity_base_field_info', [$entity_type]);
|
||||
if (!empty($module_definitions)) {
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'entity_base_field_info',
|
||||
function (callable $hook, string $module) use (&$base_field_definitions, $entity_type) {
|
||||
$module_definitions = $hook($entity_type) ?? [];
|
||||
// Ensure the provider key actually matches the name of the provider
|
||||
// defining the field.
|
||||
foreach ($module_definitions as $field_name => $definition) {
|
||||
|
@ -296,7 +297,7 @@ class EntityFieldManager implements EntityFieldManagerInterface {
|
|||
$base_field_definitions[$field_name] = $definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Automatically set the field name, target entity type and bundle
|
||||
// for non-configurable fields.
|
||||
|
@ -404,9 +405,10 @@ class EntityFieldManager implements EntityFieldManagerInterface {
|
|||
}
|
||||
|
||||
// Retrieve base field definitions from modules.
|
||||
foreach ($this->moduleHandler->getImplementations('entity_bundle_field_info') as $module) {
|
||||
$module_definitions = $this->moduleHandler->invoke($module, 'entity_bundle_field_info', [$entity_type, $bundle, $base_field_definitions]);
|
||||
if (!empty($module_definitions)) {
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'entity_bundle_field_info',
|
||||
function (callable $hook, string $module) use (&$bundle_field_definitions, $entity_type, $bundle, $base_field_definitions) {
|
||||
$module_definitions = $hook($entity_type, $bundle, $base_field_definitions) ?? [];
|
||||
// Ensure the provider key actually matches the name of the provider
|
||||
// defining the field.
|
||||
foreach ($module_definitions as $field_name => $definition) {
|
||||
|
@ -418,7 +420,7 @@ class EntityFieldManager implements EntityFieldManagerInterface {
|
|||
$bundle_field_definitions[$field_name] = $definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Automatically set the field name, target entity type and bundle
|
||||
// for non-configurable fields.
|
||||
|
@ -580,9 +582,10 @@ class EntityFieldManager implements EntityFieldManagerInterface {
|
|||
$field_definitions = [];
|
||||
|
||||
// Retrieve base field definitions from modules.
|
||||
foreach ($this->moduleHandler->getImplementations('entity_field_storage_info') as $module) {
|
||||
$module_definitions = $this->moduleHandler->invoke($module, 'entity_field_storage_info', [$entity_type]);
|
||||
if (!empty($module_definitions)) {
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'entity_field_storage_info',
|
||||
function (callable $hook, string $module) use (&$field_definitions, $entity_type, $entity_type_id) {
|
||||
$module_definitions = $hook($entity_type) ?? [];
|
||||
// Ensure the provider key actually matches the name of the provider
|
||||
// defining the field.
|
||||
foreach ($module_definitions as $field_name => $definition) {
|
||||
|
@ -596,7 +599,7 @@ class EntityFieldManager implements EntityFieldManagerInterface {
|
|||
$field_definitions[$field_name] = $definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Invoke alter hook.
|
||||
$this->moduleHandler->alter('entity_field_storage_info', $field_definitions, $entity_type);
|
||||
|
|
|
@ -387,16 +387,11 @@ class EntityForm extends FormBase implements EntityFormInterface {
|
|||
* The current state of the form.
|
||||
*/
|
||||
protected function prepareInvokeAll($hook, FormStateInterface $form_state) {
|
||||
$implementations = $this->moduleHandler->getImplementations($hook);
|
||||
foreach ($implementations as $module) {
|
||||
$function = $module . '_' . $hook;
|
||||
if (function_exists($function)) {
|
||||
// Ensure we pass an updated translation object and form display at
|
||||
// each invocation, since they depend on form state which is alterable.
|
||||
$args = [$this->entity, $this->operation, &$form_state];
|
||||
call_user_func_array($function, $args);
|
||||
}
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith($hook, function (callable $hook, string $module) use ($form_state) {
|
||||
// Ensure we pass an updated translation object and form display at
|
||||
// each invocation, since they depend on form state which is alterable.
|
||||
$hook($this->entity, $this->operation, $form_state);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -393,16 +393,12 @@ abstract class EntityStorageBase extends EntityHandlerBase implements EntityStor
|
|||
$entity_class::postLoad($this, $items);
|
||||
}
|
||||
}
|
||||
// Call hook_entity_load().
|
||||
foreach ($this->moduleHandler()->getImplementations('entity_load') as $module) {
|
||||
$function = $module . '_entity_load';
|
||||
$function($entities, $this->entityTypeId);
|
||||
}
|
||||
// Call hook_TYPE_load().
|
||||
foreach ($this->moduleHandler()->getImplementations($this->entityTypeId . '_load') as $module) {
|
||||
$function = $module . '_' . $this->entityTypeId . '_load';
|
||||
$function($entities);
|
||||
}
|
||||
$this->moduleHandler()->invokeAllWith('entity_load', function (callable $hook, string $module) use (&$entities) {
|
||||
$hook($entities, $this->entityTypeId);
|
||||
});
|
||||
$this->moduleHandler()->invokeAllWith($this->entityTypeId . '_load', function (callable $hook, string $module) use (&$entities) {
|
||||
$hook($entities);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -114,13 +114,9 @@ class EntityTypeManager extends DefaultPluginManager implements EntityTypeManage
|
|||
*/
|
||||
protected function findDefinitions() {
|
||||
$definitions = $this->getDiscovery()->getDefinitions();
|
||||
|
||||
// Directly call the hook implementations to pass the definitions to them
|
||||
// by reference, so new entity types can be added.
|
||||
foreach ($this->moduleHandler->getImplementations('entity_type_build') as $module) {
|
||||
$function = $module . '_entity_type_build';
|
||||
$function($definitions);
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith('entity_type_build', function (callable $hook, string $module) use (&$definitions) {
|
||||
$hook($definitions);
|
||||
});
|
||||
foreach ($definitions as $plugin_id => $definition) {
|
||||
$this->processDefinition($definition, $plugin_id);
|
||||
}
|
||||
|
|
|
@ -325,6 +325,7 @@ class ModuleHandler implements ModuleHandlerInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function getImplementations($hook) {
|
||||
@trigger_error('ModuleHandlerInterface::getImplementations() is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Instead you should use ModuleHandlerInterface::invokeAllWith() for hook invocations, or you should use ModuleHandlerInterface::hasImplementations() to determine if hooks implementations exist. See https://www.drupal.org/node/3000490', E_USER_DEPRECATED);
|
||||
$implementations = $this->getImplementationInfo($hook);
|
||||
return array_keys($implementations);
|
||||
}
|
||||
|
@ -355,8 +356,8 @@ class ModuleHandler implements ModuleHandlerInterface {
|
|||
// when non-database caching backends are used, so there will be more
|
||||
// significant gains when a large number of modules are installed or hooks
|
||||
// invoked, since this can quickly lead to
|
||||
// \Drupal::moduleHandler()->implementsHook() being called several thousand
|
||||
// times per request.
|
||||
// \Drupal::moduleHandler()->hasImplementations() being called several
|
||||
// thousand times per request.
|
||||
$this->cacheBackend->set('module_implements', []);
|
||||
$this->cacheBackend->delete('hook_info');
|
||||
}
|
||||
|
@ -364,32 +365,56 @@ class ModuleHandler implements ModuleHandlerInterface {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function implementsHook($module, $hook) {
|
||||
$function = $module . '_' . $hook;
|
||||
if (function_exists($function)) {
|
||||
return TRUE;
|
||||
}
|
||||
// If the hook implementation does not exist, check whether it lives in an
|
||||
// optional include file registered via hook_hook_info().
|
||||
$hook_info = $this->getHookInfo();
|
||||
if (isset($hook_info[$hook]['group'])) {
|
||||
$this->loadInclude($module, 'inc', $module . '.' . $hook_info[$hook]['group']);
|
||||
if (function_exists($function)) {
|
||||
return TRUE;
|
||||
public function hasImplementations(string $hook, $modules = NULL): bool {
|
||||
if ($modules !== NULL) {
|
||||
foreach ((array) $modules as $module) {
|
||||
// Hook implementations usually found in a module's .install file are
|
||||
// not stored in the implementation info cache. In order to invoke hooks
|
||||
// like hook_schema() and hook_requirements() the module's .install file
|
||||
// must be included by the calling code. Additionally, this check avoids
|
||||
// unnecessary work when a hook implementation is present in a module's
|
||||
// .module file.
|
||||
if (function_exists($module . '_' . $hook)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
$implementations = $this->getImplementationInfo($hook);
|
||||
if ($modules === NULL && !empty($implementations)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return !empty(array_intersect((array) $modules, array_keys($implementations)));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function implementsHook($module, $hook) {
|
||||
@trigger_error('ModuleHandlerInterface::implementsHook() is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Instead you should use ModuleHandlerInterface::hasImplementations() with the $modules argument. See https://www.drupal.org/node/3000490', E_USER_DEPRECATED);
|
||||
return $this->hasImplementations($hook, $module);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function invokeAllWith(string $hook, callable $callback): void {
|
||||
foreach (array_keys($this->getImplementationInfo($hook)) as $module) {
|
||||
$hookInvoker = \Closure::fromCallable($module . '_' . $hook);
|
||||
$callback($hookInvoker, $module);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function invoke($module, $hook, array $args = []) {
|
||||
if (!$this->implementsHook($module, $hook)) {
|
||||
if (!$this->hasImplementations($hook, $module)) {
|
||||
return;
|
||||
}
|
||||
$function = $module . '_' . $hook;
|
||||
return call_user_func_array($function, $args);
|
||||
$hookInvoker = \Closure::fromCallable($module . '_' . $hook);
|
||||
return call_user_func_array($hookInvoker, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -397,18 +422,15 @@ class ModuleHandler implements ModuleHandlerInterface {
|
|||
*/
|
||||
public function invokeAll($hook, array $args = []) {
|
||||
$return = [];
|
||||
$implementations = $this->getImplementations($hook);
|
||||
foreach ($implementations as $module) {
|
||||
$function = $module . '_' . $hook;
|
||||
$result = call_user_func_array($function, $args);
|
||||
$this->invokeAllWith($hook, function (callable $hook, string $module) use ($args, &$return) {
|
||||
$result = call_user_func_array($hook, $args);
|
||||
if (isset($result) && is_array($result)) {
|
||||
$return = NestedArray::mergeDeep($return, $result);
|
||||
}
|
||||
elseif (isset($result)) {
|
||||
$return[] = $result;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
@ -478,10 +500,10 @@ class ModuleHandler implements ModuleHandlerInterface {
|
|||
if (!isset($this->alterFunctions[$cid])) {
|
||||
$this->alterFunctions[$cid] = [];
|
||||
$hook = $type . '_alter';
|
||||
$modules = $this->getImplementations($hook);
|
||||
$modules = array_keys($this->getImplementationInfo($hook));
|
||||
if (!isset($extra_types)) {
|
||||
// For the more common case of a single hook, we do not need to call
|
||||
// function_exists(), since $this->getImplementations() returns only
|
||||
// function_exists(), since $this->getImplementationInfo() returns only
|
||||
// modules with implementations.
|
||||
foreach ($modules as $module) {
|
||||
$this->alterFunctions[$cid][] = $module . '_' . $hook;
|
||||
|
@ -492,21 +514,21 @@ class ModuleHandler implements ModuleHandlerInterface {
|
|||
// implements at least one of them.
|
||||
$extra_modules = [];
|
||||
foreach ($extra_types as $extra_type) {
|
||||
$extra_modules[] = $this->getImplementations($extra_type . '_alter');
|
||||
$extra_modules[] = array_keys($this->getImplementationInfo($extra_type . '_alter'));
|
||||
}
|
||||
$extra_modules = array_merge([], ...$extra_modules);
|
||||
// If any modules implement one of the extra hooks that do not implement
|
||||
// the primary hook, we need to add them to the $modules array in their
|
||||
// appropriate order. $this->getImplementations() can only return
|
||||
// appropriate order. $this->getImplementationInfo() can only return
|
||||
// ordered implementations of a single hook. To get the ordered
|
||||
// implementations of multiple hooks, we mimic the
|
||||
// $this->getImplementations() logic of first ordering by
|
||||
// $this->getImplementationInfo() logic of first ordering by
|
||||
// $this->getModuleList(), and then calling
|
||||
// $this->alter('module_implements').
|
||||
if (array_diff($extra_modules, $modules)) {
|
||||
// Merge the arrays and order by getModuleList().
|
||||
$modules = array_intersect(array_keys($this->moduleList), array_merge($modules, $extra_modules));
|
||||
// Since $this->getImplementations() already took care of loading the
|
||||
// Since $this->getImplementationInfo() already took care of loading the
|
||||
// necessary include files, we can safely pass FALSE for the array
|
||||
// values.
|
||||
$implementations = array_fill_keys($modules, FALSE);
|
||||
|
|
|
@ -180,6 +180,13 @@ interface ModuleHandlerInterface {
|
|||
*
|
||||
* @return array
|
||||
* An array with the names of the modules which are implementing this hook.
|
||||
*
|
||||
* @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Instead you
|
||||
* should use ModuleHandlerInterface::invokeAllWith() for hook invocations
|
||||
* or you should use ModuleHandlerInterface::hasImplementations() to
|
||||
* determine if hooks implementations exist.
|
||||
*
|
||||
* @see https://www.drupal.org/node/3000490
|
||||
*/
|
||||
public function getImplementations($hook);
|
||||
|
||||
|
@ -193,6 +200,23 @@ interface ModuleHandlerInterface {
|
|||
*/
|
||||
public function resetImplementations();
|
||||
|
||||
/**
|
||||
* Determines whether there are implementations of a hook.
|
||||
*
|
||||
* @param string $hook
|
||||
* The name of the hook (e.g. "help" or "menu").
|
||||
* @param string|string[]|null $modules
|
||||
* (optional) A single module or multiple modules to check if they have any
|
||||
* implementations of a hook. Use NULL to check if any enabled module has
|
||||
* implementations.
|
||||
*
|
||||
* @return bool
|
||||
* If $modules is provided, then TRUE if there are any implementations by
|
||||
* the module(s) provided. Or if $modules if NULL, then TRUE if there are
|
||||
* any implementations. Otherwise FALSE.
|
||||
*/
|
||||
public function hasImplementations(string $hook, $modules = NULL): bool;
|
||||
|
||||
/**
|
||||
* Returns whether a given module implements a given hook.
|
||||
*
|
||||
|
@ -204,9 +228,31 @@ interface ModuleHandlerInterface {
|
|||
* @return bool
|
||||
* TRUE if the module is both installed and enabled, and the hook is
|
||||
* implemented in that module.
|
||||
*
|
||||
* @deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Use the
|
||||
* hasImplementations() methods instead with the $modules argument.
|
||||
*
|
||||
* @see https://www.drupal.org/node/3000490
|
||||
*/
|
||||
public function implementsHook($module, $hook);
|
||||
|
||||
/**
|
||||
* Executes a callback for each implementation of a hook.
|
||||
*
|
||||
* The callback is passed two arguments, a closure which executes a hook
|
||||
* implementation. And the module name.
|
||||
*
|
||||
* @param string $hook
|
||||
* The name of the hook to invoke.
|
||||
* @param callable $callback
|
||||
* A callable that invokes a hook implementation. Such that
|
||||
* $callback is callable(callable, string): mixed.
|
||||
* Arguments:
|
||||
* - Closure to a hook implementation.
|
||||
* - Implementation module machine name.
|
||||
*/
|
||||
public function invokeAllWith(string $hook, callable $callback): void;
|
||||
|
||||
/**
|
||||
* Invokes a hook in a particular module.
|
||||
*
|
||||
|
|
|
@ -94,7 +94,7 @@ function hook_hook_info() {
|
|||
/**
|
||||
* Alter the registry of modules implementing a hook.
|
||||
*
|
||||
* This hook is invoked during \Drupal::moduleHandler()->getImplementations().
|
||||
* This hook is invoked in \Drupal::moduleHandler()->getImplementationInfo().
|
||||
* A module may implement this hook in order to reorder the implementing
|
||||
* modules, which are otherwise ordered by the module's system weight.
|
||||
*
|
||||
|
@ -117,7 +117,7 @@ function hook_hook_info() {
|
|||
function hook_module_implements_alter(&$implementations, $hook) {
|
||||
if ($hook == 'form_alter') {
|
||||
// Move my_module_form_alter() to the end of the list.
|
||||
// \Drupal::moduleHandler()->getImplementations()
|
||||
// \Drupal::moduleHandler()->getImplementationInfo()
|
||||
// iterates through $implementations with a foreach loop which PHP iterates
|
||||
// in the order that the items were added, so to move an item to the end of
|
||||
// the array, we remove it and then add it.
|
||||
|
|
|
@ -268,12 +268,8 @@ class MailManager extends DefaultPluginManager implements MailManagerInterface {
|
|||
$message['headers'] = $headers;
|
||||
|
||||
// Build the email (get subject and body, allow additional headers) by
|
||||
// invoking hook_mail() on this module. We cannot use
|
||||
// moduleHandler()->invoke() as we need to have $message by reference in
|
||||
// hook_mail().
|
||||
if (function_exists($function = $module . '_mail')) {
|
||||
$function($key, $message, $params);
|
||||
}
|
||||
// invoking hook_mail() on this module.
|
||||
$this->moduleHandler->invoke($module, 'mail', [$key, &$message, $params]);
|
||||
|
||||
// Invoke hook_mail_alter() to allow all modules to alter the resulting
|
||||
// email.
|
||||
|
|
|
@ -46,13 +46,13 @@ class HookDiscovery implements DiscoveryInterface {
|
|||
*/
|
||||
public function getDefinitions() {
|
||||
$definitions = [];
|
||||
foreach ($this->moduleHandler->getImplementations($this->hook) as $module) {
|
||||
$result = $this->moduleHandler->invoke($module, $this->hook);
|
||||
foreach ($result as $plugin_id => $definition) {
|
||||
$this->moduleHandler->invokeAllWith($this->hook, function (callable $hook, string $module) use (&$definitions) {
|
||||
$module_definitions = $hook();
|
||||
foreach ($module_definitions as $plugin_id => $definition) {
|
||||
$definition['provider'] = $module;
|
||||
$definitions[$plugin_id] = $definition;
|
||||
}
|
||||
}
|
||||
});
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,10 +44,12 @@ class InfoHookDecorator implements DiscoveryInterface {
|
|||
*/
|
||||
public function getDefinitions() {
|
||||
$definitions = $this->decorated->getDefinitions();
|
||||
foreach (\Drupal::moduleHandler()->getImplementations($this->hook) as $module) {
|
||||
$function = $module . '_' . $this->hook;
|
||||
$function($definitions);
|
||||
}
|
||||
\Drupal::moduleHandler()->invokeAllWith(
|
||||
$this->hook,
|
||||
function (callable $hook, string $module) use (&$definitions) {
|
||||
$hook($definitions);
|
||||
}
|
||||
);
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
|
|
|
@ -307,10 +307,12 @@ class HtmlRenderer implements MainContentRendererInterface {
|
|||
public function invokePageAttachmentHooks(array &$page) {
|
||||
// Modules can add attachments.
|
||||
$attachments = [];
|
||||
foreach ($this->moduleHandler->getImplementations('page_attachments') as $module) {
|
||||
$function = $module . '_page_attachments';
|
||||
$function($attachments);
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'page_attachments',
|
||||
function (callable $hook, string $module) use (&$attachments) {
|
||||
$hook($attachments);
|
||||
}
|
||||
);
|
||||
if (array_diff(array_keys($attachments), ['#attached', '#cache']) !== []) {
|
||||
throw new \LogicException('Only #attached and #cache may be set in hook_page_attachments().');
|
||||
}
|
||||
|
@ -346,14 +348,18 @@ class HtmlRenderer implements MainContentRendererInterface {
|
|||
// Modules can add render arrays to the top and bottom of the page.
|
||||
$page_top = [];
|
||||
$page_bottom = [];
|
||||
foreach ($this->moduleHandler->getImplementations('page_top') as $module) {
|
||||
$function = $module . '_page_top';
|
||||
$function($page_top);
|
||||
}
|
||||
foreach ($this->moduleHandler->getImplementations('page_bottom') as $module) {
|
||||
$function = $module . '_page_bottom';
|
||||
$function($page_bottom);
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'page_top',
|
||||
function (callable $hook, string $module) use (&$page_top) {
|
||||
$hook($page_top);
|
||||
}
|
||||
);
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'page_bottom',
|
||||
function (callable $hook, string $module) use (&$page_bottom) {
|
||||
$hook($page_bottom);
|
||||
}
|
||||
);
|
||||
if (!empty($page_top)) {
|
||||
$html['page_top'] = $page_top;
|
||||
}
|
||||
|
|
|
@ -348,9 +348,9 @@ class Registry implements DestructableInterface {
|
|||
$cache = $cached->data;
|
||||
}
|
||||
else {
|
||||
foreach ($this->moduleHandler->getImplementations('theme') as $module) {
|
||||
$this->moduleHandler->invokeAllWith('theme', function (callable $callback, string $module) use (&$cache) {
|
||||
$this->processExtension($cache, $module, 'module', $module, $this->moduleList->getPath($module));
|
||||
}
|
||||
});
|
||||
// Only cache this registry if all modules are loaded.
|
||||
if ($this->moduleHandler->isLoaded()) {
|
||||
$this->cache->set("theme_registry:build:modules", $cache, Cache::PERMANENT, ['theme_registry']);
|
||||
|
|
|
@ -86,7 +86,7 @@ class CommentSelection extends DefaultSelection {
|
|||
// Passing the query to node_query_node_access_alter() is sadly
|
||||
// insufficient for nodes.
|
||||
// @see \Drupal\node\Plugin\EntityReferenceSelection\NodeSelection::buildEntityQuery()
|
||||
if (!$this->currentUser->hasPermission('bypass node access') && !count($this->moduleHandler->getImplementations('node_grants'))) {
|
||||
if (!$this->currentUser->hasPermission('bypass node access') && !$this->moduleHandler->hasImplementations('node_grants')) {
|
||||
$query->condition($node_alias . '.status', 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,10 +44,16 @@ class DbLogTest extends KernelTestBase {
|
|||
$this->assertGreaterThan($row_limit, $count, new FormattableMarkup('Dblog row count of @count exceeds row limit of @limit', ['@count' => $count, '@limit' => $row_limit]));
|
||||
|
||||
// Get the number of enabled modules. Cron adds a log entry for each module.
|
||||
$list = $this->container->get('module_handler')->getImplementations('cron');
|
||||
$module_count = count($list);
|
||||
$implementation_count = 0;
|
||||
\Drupal::moduleHandler()->invokeAllWith(
|
||||
'cron',
|
||||
function (callable $hook, string $module) use (&$implementation_count) {
|
||||
$implementation_count++;
|
||||
}
|
||||
);
|
||||
|
||||
$cron_detailed_count = $this->runCron();
|
||||
$this->assertEquals($module_count + 2, $cron_detailed_count, new FormattableMarkup('Cron added @count of @expected new log entries', ['@count' => $cron_detailed_count, '@expected' => $module_count + 2]));
|
||||
$this->assertEquals($implementation_count + 2, $cron_detailed_count, new FormattableMarkup('Cron added @count of @expected new log entries', ['@count' => $cron_detailed_count, '@expected' => $implementation_count + 2]));
|
||||
|
||||
// Test disabling of detailed cron logging.
|
||||
$this->config('system.cron')->set('logging', 0)->save();
|
||||
|
|
|
@ -112,7 +112,7 @@ function field_help($route_name, RouteMatchInterface $route_match) {
|
|||
// hook_help().
|
||||
if (isset($modules[$provider])) {
|
||||
$display = \Drupal::moduleHandler()->getName($provider);
|
||||
if (\Drupal::moduleHandler()->implementsHook($provider, 'help')) {
|
||||
if (\Drupal::moduleHandler()->hasImplementations('help', $provider)) {
|
||||
$items[] = Link::fromTextAndUrl($display, Url::fromRoute('help.page', ['name' => $provider]))->toRenderable();
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -107,10 +107,6 @@ class FieldStorageConfigAccessControlHandlerTest extends UnitTestCase {
|
|||
->willReturn('node');
|
||||
|
||||
$this->moduleHandler = $this->createMock(ModuleHandlerInterface::class);
|
||||
$this->moduleHandler
|
||||
->expects($this->any())
|
||||
->method('getImplementations')
|
||||
->will($this->returnValue([]));
|
||||
$this->moduleHandler
|
||||
->expects($this->any())
|
||||
->method('invokeAll')
|
||||
|
|
|
@ -120,15 +120,18 @@ class EntityFormDisplayEditForm extends EntityDisplayFormBase {
|
|||
$settings_form = [];
|
||||
// Invoke hook_field_widget_third_party_settings_form(), keying resulting
|
||||
// subforms by module name.
|
||||
foreach ($this->moduleHandler->getImplementations('field_widget_third_party_settings_form') as $module) {
|
||||
$settings_form[$module] = $this->moduleHandler->invoke($module, 'field_widget_third_party_settings_form', [
|
||||
$plugin,
|
||||
$field_definition,
|
||||
$this->entity->getMode(),
|
||||
$form,
|
||||
$form_state,
|
||||
]);
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'field_widget_third_party_settings_form',
|
||||
function (callable $hook, string $module) use (&$settings_form, $plugin, $field_definition, &$form, $form_state) {
|
||||
$settings_form[$module] = $hook(
|
||||
$plugin,
|
||||
$field_definition,
|
||||
$this->entity->getMode(),
|
||||
$form,
|
||||
$form_state
|
||||
);
|
||||
}
|
||||
);
|
||||
return $settings_form;
|
||||
}
|
||||
|
||||
|
|
|
@ -169,15 +169,18 @@ class EntityViewDisplayEditForm extends EntityDisplayFormBase {
|
|||
$settings_form = [];
|
||||
// Invoke hook_field_formatter_third_party_settings_form(), keying resulting
|
||||
// subforms by module name.
|
||||
foreach ($this->moduleHandler->getImplementations('field_formatter_third_party_settings_form') as $module) {
|
||||
$settings_form[$module] = $this->moduleHandler->invoke($module, 'field_formatter_third_party_settings_form', [
|
||||
$plugin,
|
||||
$field_definition,
|
||||
$this->entity->getMode(),
|
||||
$form,
|
||||
$form_state,
|
||||
]);
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'field_formatter_third_party_settings_form',
|
||||
function (callable $hook, string $module) use (&$settings_form, &$plugin, &$field_definition, &$form, &$form_state) {
|
||||
$settings_form[$module] = $hook(
|
||||
$plugin,
|
||||
$field_definition,
|
||||
$this->entity->getMode(),
|
||||
$form,
|
||||
$form_state,
|
||||
);
|
||||
}
|
||||
);
|
||||
return $settings_form;
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ class HelpController extends ControllerBase {
|
|||
*/
|
||||
public function helpPage($name) {
|
||||
$build = [];
|
||||
if ($this->moduleHandler()->implementsHook($name, 'help')) {
|
||||
if ($this->moduleHandler()->hasImplementations('help', $name)) {
|
||||
$module_name = $this->moduleHandler()->getName($name);
|
||||
$build['#title'] = $module_name;
|
||||
|
||||
|
|
|
@ -91,20 +91,15 @@ class HelpBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
|||
return [];
|
||||
}
|
||||
|
||||
$implementations = $this->moduleHandler->getImplementations('help');
|
||||
$build = [];
|
||||
$args = [
|
||||
$this->routeMatch->getRouteName(),
|
||||
$this->routeMatch,
|
||||
];
|
||||
foreach ($implementations as $module) {
|
||||
$this->moduleHandler->invokeAllWith('help', function (callable $hook, string $module) use (&$build) {
|
||||
// Don't add empty strings to $build array.
|
||||
if ($help = $this->moduleHandler->invoke($module, 'help', $args)) {
|
||||
if ($help = $hook($this->routeMatch->getRouteName(), $this->routeMatch)) {
|
||||
// Convert strings to #markup render arrays so that they will XSS admin
|
||||
// filtered.
|
||||
$build[] = is_array($help) ? $help : ['#markup' => $help];
|
||||
}
|
||||
}
|
||||
});
|
||||
return $build;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,10 +59,13 @@ class HookHelpSection extends HelpSectionPluginBase implements ContainerFactoryP
|
|||
*/
|
||||
public function listTopics() {
|
||||
$topics = [];
|
||||
foreach ($this->moduleHandler->getImplementations('help') as $module) {
|
||||
$title = $this->moduleHandler->getName($module);
|
||||
$topics[$title] = Link::createFromRoute($title, 'help.page', ['name' => $module]);
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'help',
|
||||
function (callable $hook, string $module) use (&$topics) {
|
||||
$title = $this->moduleHandler->getName($module);
|
||||
$topics[$title] = Link::createFromRoute($title, 'help.page', ['name' => $module]);
|
||||
}
|
||||
);
|
||||
|
||||
// Sort topics by title, which is the array key above.
|
||||
ksort($topics);
|
||||
|
|
|
@ -164,9 +164,12 @@ class HelpTest extends BrowserTestBase {
|
|||
protected function getModuleList() {
|
||||
$modules = [];
|
||||
$module_data = $this->container->get('extension.list.module')->getList();
|
||||
foreach (\Drupal::moduleHandler()->getImplementations('help') as $module) {
|
||||
$modules[$module] = $module_data[$module]->info['name'];
|
||||
}
|
||||
\Drupal::moduleHandler()->invokeAllWith(
|
||||
'help',
|
||||
function (callable $hook, string $module) use (&$modules, $module_data) {
|
||||
$modules[$module] = $module_data[$module]->info['name'];
|
||||
}
|
||||
);
|
||||
return $modules;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ class NoHelpTest extends BrowserTestBase {
|
|||
$this->drupalGet('admin/help');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains('Module overviews are provided by modules');
|
||||
$this->assertFalse(\Drupal::moduleHandler()->implementsHook('menu_test', 'help'), 'The menu_test module does not implement hook_help');
|
||||
$this->assertFalse(\Drupal::moduleHandler()->hasImplementations('help', 'menu_test'), 'The menu_test module does not implement hook_help');
|
||||
// Make sure the test module menu_test does not display a help link on
|
||||
// admin/help.
|
||||
$this->assertSession()->pageTextNotContains(\Drupal::moduleHandler()->getName('menu_test'));
|
||||
|
|
|
@ -442,14 +442,17 @@ class TemporaryQueryGuard {
|
|||
// hook_jsonapi_ENTITY_TYPE_filter_access() for each module and merge its
|
||||
// results with the combined results.
|
||||
foreach (['jsonapi_entity_filter_access', 'jsonapi_' . $entity_type->id() . '_filter_access'] as $hook) {
|
||||
foreach (static::$moduleHandler->getImplementations($hook) as $module) {
|
||||
$module_access_results = static::$moduleHandler->invoke($module, $hook, [$entity_type, $account]);
|
||||
if ($module_access_results) {
|
||||
foreach ($module_access_results as $subset => $access_result) {
|
||||
$combined_access_results[$subset] = $combined_access_results[$subset]->orIf($access_result);
|
||||
static::$moduleHandler->invokeAllWith(
|
||||
$hook,
|
||||
function (callable $hook, string $module) use (&$combined_access_results, $entity_type, $account) {
|
||||
$module_access_results = $hook($entity_type, $account);
|
||||
if ($module_access_results) {
|
||||
foreach ($module_access_results as $subset => $access_result) {
|
||||
$combined_access_results[$subset] = $combined_access_results[$subset]->orIf($access_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return $combined_access_results;
|
||||
|
|
|
@ -311,15 +311,18 @@ class FieldBlock extends BlockBase implements ContextAwarePluginInterface, Conta
|
|||
$settings_form = [];
|
||||
// Invoke hook_field_formatter_third_party_settings_form(), keying resulting
|
||||
// subforms by module name.
|
||||
foreach ($this->moduleHandler->getImplementations('field_formatter_third_party_settings_form') as $module) {
|
||||
$settings_form[$module] = $this->moduleHandler->invoke($module, 'field_formatter_third_party_settings_form', [
|
||||
$plugin,
|
||||
$field_definition,
|
||||
EntityDisplayBase::CUSTOM_MODE,
|
||||
$form,
|
||||
$form_state,
|
||||
]);
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'field_formatter_third_party_settings_form',
|
||||
function (callable $hook, string $module) use (&$settings_form, $plugin, $field_definition, $form, $form_state) {
|
||||
$settings_form[$module] = $hook(
|
||||
$plugin,
|
||||
$field_definition,
|
||||
EntityDisplayBase::CUSTOM_MODE,
|
||||
$form,
|
||||
$form_state,
|
||||
);
|
||||
}
|
||||
);
|
||||
return $settings_form;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ function node_requirements($phase) {
|
|||
// in the {node_access} table, or if there are modules that
|
||||
// implement hook_node_grants().
|
||||
$grant_count = \Drupal::entityTypeManager()->getAccessControlHandler('node')->countGrants();
|
||||
if ($grant_count != 1 || count(\Drupal::moduleHandler()->getImplementations('node_grants')) > 0) {
|
||||
if ($grant_count != 1 || \Drupal::moduleHandler()->hasImplementations('node_grants')) {
|
||||
$value = \Drupal::translation()->formatPlural($grant_count, 'One permission in use', '@count permissions in use', ['@count' => $grant_count]);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -913,7 +913,7 @@ function node_access_view_all_nodes($account = NULL) {
|
|||
}
|
||||
|
||||
// If no modules implement the node access system, access is always TRUE.
|
||||
if (!\Drupal::moduleHandler()->getImplementations('node_grants')) {
|
||||
if (!\Drupal::moduleHandler()->hasImplementations('node_grants')) {
|
||||
$access[$account->id()] = TRUE;
|
||||
}
|
||||
else {
|
||||
|
@ -954,7 +954,7 @@ function node_query_node_access_alter(AlterableInterface $query) {
|
|||
if ($account->hasPermission('bypass node access')) {
|
||||
return;
|
||||
}
|
||||
if (!count(\Drupal::moduleHandler()->getImplementations('node_grants'))) {
|
||||
if (!\Drupal::moduleHandler()->hasImplementations('node_grants')) {
|
||||
return;
|
||||
}
|
||||
if ($op == 'view' && node_access_view_all_nodes($account)) {
|
||||
|
@ -1066,7 +1066,7 @@ function node_access_rebuild($batch_mode = FALSE) {
|
|||
$access_control_handler = \Drupal::entityTypeManager()->getAccessControlHandler('node');
|
||||
$access_control_handler->deleteGrants();
|
||||
// Only recalculate if the site is using a node_access module.
|
||||
if (count(\Drupal::moduleHandler()->getImplementations('node_grants'))) {
|
||||
if (\Drupal::moduleHandler()->hasImplementations('node_grants')) {
|
||||
if ($batch_mode) {
|
||||
$batch_builder = (new BatchBuilder())
|
||||
->setTitle(t('Rebuilding content access permissions'))
|
||||
|
@ -1194,10 +1194,10 @@ function _node_access_rebuild_batch_finished($success, $results, $operations) {
|
|||
/**
|
||||
* Implements hook_modules_installed().
|
||||
*/
|
||||
function node_modules_installed($modules) {
|
||||
function node_modules_installed(array $modules) {
|
||||
// Check if any of the newly enabled modules require the node_access table to
|
||||
// be rebuilt.
|
||||
if (!node_access_needs_rebuild() && array_intersect($modules, \Drupal::moduleHandler()->getImplementations('node_grants'))) {
|
||||
if (!node_access_needs_rebuild() && \Drupal::moduleHandler()->hasImplementations('node_grants', $modules)) {
|
||||
node_access_needs_rebuild(TRUE);
|
||||
}
|
||||
}
|
||||
|
@ -1214,14 +1214,14 @@ function node_modules_uninstalled($modules) {
|
|||
// check whether a hook implementation function exists and do not invoke it.
|
||||
// Node access also needs to be rebuilt if language module is disabled to
|
||||
// remove any language-specific grants.
|
||||
if (!node_access_needs_rebuild() && (\Drupal::moduleHandler()->implementsHook($module, 'node_grants') || $module == 'language')) {
|
||||
if (!node_access_needs_rebuild() && (\Drupal::moduleHandler()->hasImplementations('node_grants', $module) || $module == 'language')) {
|
||||
node_access_needs_rebuild(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// If there remains no more node_access module, rebuilding will be
|
||||
// straightforward, we can do it right now.
|
||||
if (node_access_needs_rebuild() && count(\Drupal::moduleHandler()->getImplementations('node_grants')) == 0) {
|
||||
if (node_access_needs_rebuild() && !\Drupal::moduleHandler()->hasImplementations('node_grants')) {
|
||||
node_access_rebuild();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ class NodeAccessGrantsCacheContext extends UserCacheContextBase implements Calcu
|
|||
public function getCacheableMetadata($operation = NULL) {
|
||||
$cacheable_metadata = new CacheableMetadata();
|
||||
|
||||
if (!\Drupal::moduleHandler()->getImplementations('node_grants')) {
|
||||
if (!\Drupal::moduleHandler()->hasImplementations('node_grants')) {
|
||||
return $cacheable_metadata;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ class NodeGrantDatabaseStorage implements NodeGrantDatabaseStorageInterface {
|
|||
|
||||
// If no module implements the hook or the node does not have an id there is
|
||||
// no point in querying the database for access grants.
|
||||
if (!$this->moduleHandler->getImplementations('node_grants') || !$node->id()) {
|
||||
if (!$this->moduleHandler->hasImplementations('node_grants') || !$node->id()) {
|
||||
// Return the equivalent of the default grant, defined by
|
||||
// self::writeDefault().
|
||||
if ($operation === 'view') {
|
||||
|
@ -208,7 +208,7 @@ class NodeGrantDatabaseStorage implements NodeGrantDatabaseStorageInterface {
|
|||
$query->execute();
|
||||
}
|
||||
// Only perform work when node_access modules are active.
|
||||
if (!empty($grants) && count($this->moduleHandler->getImplementations('node_grants'))) {
|
||||
if (!empty($grants) && $this->moduleHandler->hasImplementations('node_grants')) {
|
||||
$query = $this->database->insert('node_access')->fields(['nid', 'langcode', 'fallback', 'realm', 'gid', 'grant_view', 'grant_update', 'grant_delete']);
|
||||
// If we have defined a granted langcode, use it. But if not, add a grant
|
||||
// for every language this node is translated to.
|
||||
|
|
|
@ -28,7 +28,7 @@ class NodeSelection extends DefaultSelection {
|
|||
// 'unpublished'. We need to do that as long as there are no access control
|
||||
// modules in use on the site. As long as one access control module is there,
|
||||
// it is supposed to handle this check.
|
||||
if (!$this->currentUser->hasPermission('bypass node access') && !count($this->moduleHandler->getImplementations('node_grants'))) {
|
||||
if (!$this->currentUser->hasPermission('bypass node access') && !$this->moduleHandler->hasImplementations('node_grants')) {
|
||||
$query->condition('status', NodeInterface::PUBLISHED);
|
||||
}
|
||||
return $query;
|
||||
|
@ -53,7 +53,7 @@ class NodeSelection extends DefaultSelection {
|
|||
public function validateReferenceableNewEntities(array $entities) {
|
||||
$entities = parent::validateReferenceableNewEntities($entities);
|
||||
// Mirror the conditions checked in buildEntityQuery().
|
||||
if (!$this->currentUser->hasPermission('bypass node access') && !count($this->moduleHandler->getImplementations('node_grants'))) {
|
||||
if (!$this->currentUser->hasPermission('bypass node access') && !$this->moduleHandler->hasImplementations('node_grants')) {
|
||||
$entities = array_filter($entities, function ($node) {
|
||||
/** @var \Drupal\node\NodeInterface $node */
|
||||
return $node->isPublished();
|
||||
|
|
|
@ -43,8 +43,7 @@ class NodeAccessCacheabilityWithNodeGrants extends BrowserTestBase {
|
|||
// Check that at least one module implements hook_node_grants() as this test
|
||||
// only tests this case.
|
||||
// @see \node_test_node_grants()
|
||||
$node_grants_implementations = \Drupal::moduleHandler()->getImplementations('node_grants');
|
||||
$this->assertNotEmpty($node_grants_implementations);
|
||||
$this->assertTrue(\Drupal::moduleHandler()->hasImplementations('node_grants'));
|
||||
|
||||
// Create an unpublished node.
|
||||
$referenced = $this->createNode(['status' => FALSE]);
|
||||
|
|
|
@ -113,17 +113,20 @@ function rdf_get_namespaces() {
|
|||
$namespaces = [];
|
||||
// In order to resolve duplicate namespaces by using the earliest defined
|
||||
// namespace, do not use \Drupal::moduleHandler()->invokeAll().
|
||||
foreach (\Drupal::moduleHandler()->getImplementations('rdf_namespaces') as $module) {
|
||||
$function = $module . '_rdf_namespaces';
|
||||
foreach ($function() as $prefix => $namespace) {
|
||||
if (array_key_exists($prefix, $namespaces) && $namespace !== $namespaces[$prefix]) {
|
||||
throw new Exception("Tried to map '$prefix' to '$namespace', but '$prefix' is already mapped to '{$namespaces[$prefix]}'.");
|
||||
}
|
||||
else {
|
||||
$namespaces[$prefix] = $namespace;
|
||||
\Drupal::moduleHandler()->invokeAllWith(
|
||||
'rdf_namespaces',
|
||||
function (callable $hook, string $module) use (&$namespaces) {
|
||||
$namespacesFromHook = $hook();
|
||||
foreach ($namespacesFromHook as $prefix => $namespace) {
|
||||
if (array_key_exists($prefix, $namespaces) && $namespace !== $namespaces[$prefix]) {
|
||||
throw new Exception("Tried to map '$prefix' to '$namespace', but '$prefix' is already mapped to '{$namespaces[$prefix]}'.");
|
||||
}
|
||||
else {
|
||||
$namespaces[$prefix] = $namespace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return $namespaces;
|
||||
}
|
||||
|
||||
|
|
|
@ -117,9 +117,12 @@ class SearchTextProcessor implements SearchTextProcessorInterface {
|
|||
* Language code for the language of $text, if known.
|
||||
*/
|
||||
protected function invokePreprocess(string &$text, ?string $langcode = NULL): void {
|
||||
foreach ($this->moduleHandler->getImplementations('search_preprocess') as $module) {
|
||||
$text = $this->moduleHandler->invoke($module, 'search_preprocess', [$text, $langcode]);
|
||||
}
|
||||
$this->moduleHandler->invokeAllWith(
|
||||
'search_preprocess',
|
||||
function (callable $hook, string $module) use (&$text, &$langcode) {
|
||||
$text = $hook($text, $langcode);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -63,7 +63,7 @@ class ShortcutSetDeleteForm extends EntityDeleteForm {
|
|||
|
||||
// Also, if a module implements hook_shortcut_default_set(), it's possible
|
||||
// that this set is being used as a default set. Add a message about that too.
|
||||
if ($this->moduleHandler->getImplementations('shortcut_default_set')) {
|
||||
if ($this->moduleHandler->hasImplementations('shortcut_default_set')) {
|
||||
$info .= '<p>' . $this->t('If you have chosen this shortcut set as the default for some or all users, they may also be affected by deleting it.') . '</p>';
|
||||
}
|
||||
|
||||
|
|
|
@ -278,7 +278,7 @@ class ModulesListForm extends FormBase {
|
|||
// Generate link for module's help page. Assume that if a hook_help()
|
||||
// implementation exists then the module provides an overview page, rather
|
||||
// than checking to see if the page exists, which is costly.
|
||||
if ($this->moduleHandler->moduleExists('help') && $module->status && in_array($module->getName(), $this->moduleHandler->getImplementations('help'))) {
|
||||
if ($this->moduleHandler->moduleExists('help') && $module->status && $this->moduleHandler->hasImplementations('help', $module->getName())) {
|
||||
$row['links']['help'] = [
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Help <span class="visually-hidden">for @module</span>', ['@module' => $module->info['name']]),
|
||||
|
|
|
@ -1346,19 +1346,22 @@ function system_requirements($phase) {
|
|||
/** @var \Drupal\Core\Update\UpdateHookRegistry $update_registry */
|
||||
$update_registry = \Drupal::service('update.update_hook_registry');
|
||||
$module_list = [];
|
||||
foreach ($module_handler->getImplementations('update_last_removed') as $module) {
|
||||
$last_removed = $module_handler->invoke($module, 'update_last_removed');
|
||||
if ($last_removed && $last_removed > $update_registry->getInstalledVersion($module)) {
|
||||
$module_handler->invokeAllWith(
|
||||
'update_last_removed',
|
||||
function (callable $hook, string $module) use (&$module_list, $update_registry, $module_extension_list) {
|
||||
$last_removed = $hook();
|
||||
if ($last_removed && $last_removed > $update_registry->getInstalledVersion($module)) {
|
||||
|
||||
/** @var \Drupal\Core\Extension\Extension $module_info */
|
||||
$module_info = $module_extension_list->get($module);
|
||||
$module_list[$module] = [
|
||||
'name' => $module_info->info['name'],
|
||||
'last_removed' => $last_removed,
|
||||
'installed_version' => $update_registry->getInstalledVersion($module),
|
||||
];
|
||||
/** @var \Drupal\Core\Extension\Extension $module_info */
|
||||
$module_info = $module_extension_list->get($module);
|
||||
$module_list[$module] = [
|
||||
'name' => $module_info->info['name'],
|
||||
'last_removed' => $last_removed,
|
||||
'installed_version' => $update_registry->getInstalledVersion($module),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// If system or workspaces is in the list then only show a specific message
|
||||
// for Drupal core.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* A file to test \Drupal::moduleHandler()->getImplementations() loading includes.
|
||||
* A file to test \Drupal::moduleHandler()->getImplementationInfo() loading includes.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,6 +5,20 @@
|
|||
* Helper module for the plugin tests.
|
||||
*/
|
||||
|
||||
use Drupal\plugin_test\Plugin\plugin_test\fruit\Apple;
|
||||
|
||||
/**
|
||||
* Implements hook_test_plugin_info().
|
||||
*/
|
||||
function plugin_test_test_plugin_info() {
|
||||
return [
|
||||
'apple' => [
|
||||
'id' => 'apple',
|
||||
'class' => Apple::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_plugin_test_alter().
|
||||
*/
|
||||
|
|
|
@ -125,10 +125,6 @@ EOF
|
|||
EOF
|
||||
);
|
||||
$modules = ['module_a', 'module_b', 'module_c'];
|
||||
$this->moduleHandler->expects($this->any())
|
||||
->method('getImplementations')
|
||||
->with('permission')
|
||||
->willReturn([]);
|
||||
|
||||
$this->moduleHandler->expects($this->any())
|
||||
->method('getModuleList')
|
||||
|
@ -248,11 +244,6 @@ EOF
|
|||
|
||||
$modules = ['module_a', 'module_b', 'module_c'];
|
||||
|
||||
$this->moduleHandler->expects($this->any())
|
||||
->method('getImplementations')
|
||||
->with('permission')
|
||||
->willReturn([]);
|
||||
|
||||
$this->moduleHandler->expects($this->any())
|
||||
->method('getModuleList')
|
||||
->willReturn(array_flip($modules));
|
||||
|
@ -300,11 +291,6 @@ EOF
|
|||
|
||||
$modules = ['module_a'];
|
||||
|
||||
$this->moduleHandler->expects($this->any())
|
||||
->method('getImplementations')
|
||||
->with('permission')
|
||||
->willReturn([]);
|
||||
|
||||
$this->moduleHandler->expects($this->any())
|
||||
->method('getModuleList')
|
||||
->willReturn(array_flip($modules));
|
||||
|
|
|
@ -119,9 +119,6 @@ class UserAccessControlHandlerTest extends UnitTestCase {
|
|||
|
||||
$this->accessControlHandler = new UserAccessControlHandler($entity_type);
|
||||
$module_handler = $this->createMock('Drupal\Core\Extension\ModuleHandlerInterface');
|
||||
$module_handler->expects($this->any())
|
||||
->method('getImplementations')
|
||||
->will($this->returnValue([]));
|
||||
$this->accessControlHandler->setModuleHandler($module_handler);
|
||||
|
||||
$this->items = $this->getMockBuilder('Drupal\Core\Field\FieldItemList')
|
||||
|
|
|
@ -231,10 +231,9 @@ class ViewsData {
|
|||
return $data->data;
|
||||
}
|
||||
else {
|
||||
$modules = $this->moduleHandler->getImplementations('views_data');
|
||||
$data = [];
|
||||
foreach ($modules as $module) {
|
||||
$views_data = $this->moduleHandler->invoke($module, 'views_data');
|
||||
$this->moduleHandler->invokeAllWith('views_data', function (callable $hook, string $module) use (&$data) {
|
||||
$views_data = $hook();
|
||||
// Set the provider key for each base table.
|
||||
foreach ($views_data as &$table) {
|
||||
if (isset($table['table']) && !isset($table['table']['provider'])) {
|
||||
|
@ -242,7 +241,7 @@ class ViewsData {
|
|||
}
|
||||
}
|
||||
$data = NestedArray::mergeDeep($data, $views_data);
|
||||
}
|
||||
});
|
||||
$this->moduleHandler->alter('views_data', $data);
|
||||
|
||||
$this->processEntityTypes($data);
|
||||
|
|
|
@ -29,8 +29,9 @@ function views_test_data_views_data() {
|
|||
/**
|
||||
* Implements hook_views_data_alter().
|
||||
*/
|
||||
function views_test_data_views_data_alter() {
|
||||
function views_test_data_views_data_alter(array &$data) {
|
||||
\Drupal::state()->set('views_hook_test_views_data_alter', TRUE);
|
||||
\Drupal::state()->set('views_hook_test_views_data_alter_data', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -67,7 +67,7 @@ class ViewsHooksTest extends ViewsKernelTestBase {
|
|||
|
||||
// Test each hook is found in the implementations array and is invoked.
|
||||
foreach (static::$hooks as $hook => $type) {
|
||||
$this->assertTrue($this->moduleHandler->implementsHook('views_test_data', $hook), new FormattableMarkup('The hook @hook was registered.', ['@hook' => $hook]));
|
||||
$this->assertTrue($this->moduleHandler->hasImplementations($hook, 'views_test_data'), new FormattableMarkup('The hook @hook was registered.', ['@hook' => $hook]));
|
||||
|
||||
if ($hook == 'views_post_render') {
|
||||
$this->moduleHandler->invoke('views_test_data', $hook, [$view, &$view->display_handler->output, $view->display_handler->getPlugin('cache')]);
|
||||
|
@ -81,7 +81,7 @@ class ViewsHooksTest extends ViewsKernelTestBase {
|
|||
|
||||
case 'alter':
|
||||
$data = [];
|
||||
$this->moduleHandler->invoke('views_test_data', $hook, [$data]);
|
||||
$this->moduleHandler->alter($hook, $data);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -131,16 +131,13 @@ class ViewsDataTest extends UnitTestCase {
|
|||
*
|
||||
* @return \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
|
||||
*/
|
||||
protected function setupMockedModuleHandler() {
|
||||
$views_data = $this->viewsData();
|
||||
$this->moduleHandler->expects($this->once())
|
||||
->method('getImplementations')
|
||||
protected function setupMockedModuleHandler(): void {
|
||||
$this->moduleHandler->expects($this->atLeastOnce())
|
||||
->method('invokeAllWith')
|
||||
->with('views_data')
|
||||
->willReturn(['views_test_data']);
|
||||
$this->moduleHandler->expects($this->once())
|
||||
->method('invoke')
|
||||
->with('views_test_data', 'views_data')
|
||||
->willReturn($views_data);
|
||||
->willReturnCallback(function (string $hook, callable $callback) {
|
||||
$callback(\Closure::fromCallable([$this, 'viewsData']), 'views_test_data');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,13 +210,11 @@ class ViewsDataTest extends UnitTestCase {
|
|||
|
||||
// Views data should be invoked twice due to the clear call.
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('getImplementations')
|
||||
->method('invokeAllWith')
|
||||
->with('views_data')
|
||||
->willReturn(['views_test_data']);
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('invoke')
|
||||
->with('views_test_data', 'views_data')
|
||||
->willReturn($this->viewsData());
|
||||
->willReturnCallback(function ($hook, $callback) {
|
||||
$callback(\Closure::fromCallable([$this, 'viewsData']), 'views_test_data');
|
||||
});
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('alter')
|
||||
->with('views_data', $expected_views_data);
|
||||
|
@ -403,7 +398,7 @@ class ViewsDataTest extends UnitTestCase {
|
|||
public function testCacheCallsWithSameTableMultipleTimesAndWarmCache() {
|
||||
$expected_views_data = $this->viewsDataWithProvider();
|
||||
$this->moduleHandler->expects($this->never())
|
||||
->method('getImplementations');
|
||||
->method('invokeAllWith');
|
||||
|
||||
// Setup a warm cache backend for a single table.
|
||||
$this->cacheBackend->expects($this->once())
|
||||
|
@ -433,7 +428,7 @@ class ViewsDataTest extends UnitTestCase {
|
|||
public function testCacheCallsWithWarmCacheAndDifferentTable() {
|
||||
$expected_views_data = $this->viewsDataWithProvider();
|
||||
$this->moduleHandler->expects($this->never())
|
||||
->method('getImplementations');
|
||||
->method('invokeAllWith');
|
||||
|
||||
// Setup a warm cache backend for a single table.
|
||||
$this->cacheBackend->expects($this->exactly(2))
|
||||
|
@ -472,7 +467,7 @@ class ViewsDataTest extends UnitTestCase {
|
|||
$expected_views_data = $this->viewsDataWithProvider();
|
||||
$non_existing_table = $this->randomMachineName();
|
||||
$this->moduleHandler->expects($this->never())
|
||||
->method('getImplementations');
|
||||
->method('invokeAllWith');
|
||||
|
||||
// Setup a warm cache backend for a single table.
|
||||
$this->cacheBackend->expects($this->exactly(2))
|
||||
|
@ -511,7 +506,7 @@ class ViewsDataTest extends UnitTestCase {
|
|||
public function testCacheCallsWithWarmCacheForInvalidTable() {
|
||||
$non_existing_table = $this->randomMachineName();
|
||||
$this->moduleHandler->expects($this->never())
|
||||
->method('getImplementations');
|
||||
->method('invokeAllWith');
|
||||
|
||||
// Setup a warm cache backend for a single table.
|
||||
$this->cacheBackend->expects($this->once())
|
||||
|
@ -564,7 +559,7 @@ class ViewsDataTest extends UnitTestCase {
|
|||
public function testCacheCallsWithWarmCacheAndGetAllTables() {
|
||||
$expected_views_data = $this->viewsDataWithProvider();
|
||||
$this->moduleHandler->expects($this->never())
|
||||
->method('getImplementations');
|
||||
->method('invokeAllWith');
|
||||
|
||||
// Setup a warm cache backend for a single table.
|
||||
$this->cacheBackend->expects($this->once())
|
||||
|
|
|
@ -42,10 +42,10 @@ class ModuleImplementsAlterTest extends KernelTestBase {
|
|||
|
||||
$this->assertArrayHasKey('module_test', \Drupal::moduleHandler()->getModuleList());
|
||||
|
||||
$this->assertContains('module_test', \Drupal::moduleHandler()->getImplementations('modules_installed'),
|
||||
$this->assertTrue(\Drupal::moduleHandler()->hasImplementations('modules_installed', 'module_test'),
|
||||
'module_test implements hook_modules_installed().');
|
||||
|
||||
$this->assertContains('module_test', \Drupal::moduleHandler()->getImplementations('module_implements_alter'),
|
||||
$this->assertTrue(\Drupal::moduleHandler()->hasImplementations('module_implements_alter', 'module_test'),
|
||||
'module_test implements hook_module_implements_alter().');
|
||||
|
||||
// Assert that module_test.implementations.inc is not included yet.
|
||||
|
@ -55,7 +55,7 @@ class ModuleImplementsAlterTest extends KernelTestBase {
|
|||
// Trigger hook discovery for hook_altered_test_hook().
|
||||
// Assert that module_test_module_implements_alter(*, 'altered_test_hook')
|
||||
// has added an implementation.
|
||||
$this->assertContains('module_test', \Drupal::moduleHandler()->getImplementations('altered_test_hook'),
|
||||
$this->assertTrue(\Drupal::moduleHandler()->hasImplementations('altered_test_hook', 'module_test'),
|
||||
'module_test implements hook_altered_test_hook().');
|
||||
|
||||
// Assert that module_test.implementations.inc was included as part of the process.
|
||||
|
@ -78,7 +78,7 @@ class ModuleImplementsAlterTest extends KernelTestBase {
|
|||
// Trigger hook discovery.
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessage('An invalid implementation module_test_unimplemented_test_hook was added by hook_module_implements_alter()');
|
||||
\Drupal::moduleHandler()->getImplementations('unimplemented_test_hook');
|
||||
\Drupal::moduleHandler()->hasImplementations('unimplemented_test_hook');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -526,9 +526,6 @@ class ConfigEntityStorageTest extends UnitTestCase {
|
|||
->willReturn($config_object->reveal());
|
||||
$this->configFactory->rename(Argument::cetera())->shouldNotBeCalled();
|
||||
|
||||
$this->moduleHandler->getImplementations('entity_load')->willReturn([]);
|
||||
$this->moduleHandler->getImplementations('test_entity_type_load')->willReturn([]);
|
||||
|
||||
$this->entityQuery->condition('uuid', 'baz')->willReturn($this->entityQuery);
|
||||
$this->entityQuery->execute()->willReturn(['foo']);
|
||||
|
||||
|
@ -558,9 +555,6 @@ class ConfigEntityStorageTest extends UnitTestCase {
|
|||
$this->configFactory->loadMultiple(['the_provider.the_config_prefix.foo'])
|
||||
->willReturn([$config_object->reveal()]);
|
||||
|
||||
$this->moduleHandler->getImplementations('entity_load')->willReturn([]);
|
||||
$this->moduleHandler->getImplementations('test_entity_type_load')->willReturn([]);
|
||||
|
||||
$entity = $this->entityStorage->load('foo');
|
||||
$this->assertInstanceOf(EntityInterface::class, $entity);
|
||||
$this->assertSame('foo', $entity->id());
|
||||
|
@ -598,9 +592,6 @@ class ConfigEntityStorageTest extends UnitTestCase {
|
|||
$this->configFactory->loadMultiple(['the_provider.the_config_prefix.foo', 'the_provider.the_config_prefix.bar'])
|
||||
->willReturn([$foo_config_object->reveal(), $bar_config_object->reveal()]);
|
||||
|
||||
$this->moduleHandler->getImplementations('entity_load')->willReturn([]);
|
||||
$this->moduleHandler->getImplementations('test_entity_type_load')->willReturn([]);
|
||||
|
||||
$entities = $this->entityStorage->loadMultiple();
|
||||
$expected['foo'] = 'foo';
|
||||
$expected['bar'] = 'bar';
|
||||
|
@ -629,9 +620,6 @@ class ConfigEntityStorageTest extends UnitTestCase {
|
|||
$this->configFactory->loadMultiple(['the_provider.the_config_prefix.foo'])
|
||||
->willReturn([$config_object->reveal()]);
|
||||
|
||||
$this->moduleHandler->getImplementations('entity_load')->willReturn([]);
|
||||
$this->moduleHandler->getImplementations('test_entity_type_load')->willReturn([]);
|
||||
|
||||
$entities = $this->entityStorage->loadMultiple(['foo']);
|
||||
$this->assertContainsOnlyInstancesOf(EntityInterface::class, $entities);
|
||||
foreach ($entities as $id => $entity) {
|
||||
|
@ -703,7 +691,6 @@ class ConfigEntityStorageTest extends UnitTestCase {
|
|||
* @covers ::doDelete
|
||||
*/
|
||||
public function testDeleteNothing() {
|
||||
$this->moduleHandler->getImplementations(Argument::cetera())->shouldNotBeCalled();
|
||||
$this->moduleHandler->invokeAll(Argument::cetera())->shouldNotBeCalled();
|
||||
|
||||
$this->configFactory->get(Argument::cetera())->shouldNotBeCalled();
|
||||
|
|
|
@ -139,7 +139,7 @@ class EntityFormDisplayAccessControlHandlerTest extends UnitTestCase {
|
|||
$this->moduleHandler = $this->createMock(ModuleHandlerInterface::class);
|
||||
$this->moduleHandler
|
||||
->expects($this->any())
|
||||
->method('getImplementations')
|
||||
->method('invokeAllWith')
|
||||
->will($this->returnValue([]));
|
||||
$this->moduleHandler
|
||||
->expects($this->any())
|
||||
|
|
|
@ -272,9 +272,17 @@ class EntityFieldManagerTest extends UnitTestCase {
|
|||
'field_storage' => $field_storage_definition->reveal(),
|
||||
];
|
||||
|
||||
$this->moduleHandler->getImplementations('entity_base_field_info')->willReturn([]);
|
||||
$this->moduleHandler->getImplementations('entity_field_storage_info')->willReturn(['example_module']);
|
||||
$this->moduleHandler->invoke('example_module', 'entity_field_storage_info', [$this->entityType])->willReturn($definitions);
|
||||
$this->moduleHandler->invokeAllWith('entity_base_field_info', Argument::any());
|
||||
$this->moduleHandler->invokeAllWith('entity_field_storage_info', Argument::any())
|
||||
->will(function ($arguments) use ($definitions) {
|
||||
[$hook, $callback] = $arguments;
|
||||
$callback(
|
||||
function () use ($definitions) {
|
||||
return $definitions;
|
||||
},
|
||||
'example_module',
|
||||
);
|
||||
});
|
||||
$this->moduleHandler->alter('entity_field_storage_info', $definitions, $this->entityType)->willReturn(NULL);
|
||||
|
||||
$expected = [
|
||||
|
@ -436,8 +444,16 @@ class EntityFieldManagerTest extends UnitTestCase {
|
|||
|
||||
$definitions = ['field_storage' => $field_storage_definition->reveal()];
|
||||
|
||||
$this->moduleHandler->getImplementations('entity_field_storage_info')->willReturn(['example_module']);
|
||||
$this->moduleHandler->invoke('example_module', 'entity_field_storage_info', [$this->entityType])->willReturn($definitions);
|
||||
$this->moduleHandler->invokeAllWith('entity_field_storage_info', Argument::any())
|
||||
->will(function ($arguments) use ($definitions) {
|
||||
[$hook, $callback] = $arguments;
|
||||
$callback(
|
||||
function () use ($definitions) {
|
||||
return $definitions;
|
||||
},
|
||||
'example_module',
|
||||
);
|
||||
});
|
||||
$this->moduleHandler->alter('entity_field_storage_info', $definitions, $this->entityType)->willReturn(NULL);
|
||||
|
||||
$expected = [
|
||||
|
@ -503,9 +519,16 @@ class EntityFieldManagerTest extends UnitTestCase {
|
|||
$field_definition->setTargetBundle(NULL)->shouldBeCalled();
|
||||
$field_definition->setTargetBundle('test_bundle')->shouldBeCalled();
|
||||
|
||||
$this->moduleHandler->getImplementations(Argument::type('string'))->willReturn([$module]);
|
||||
$this->moduleHandler->invoke($module, 'entity_base_field_info', [$this->entityType])->willReturn([$field_definition->reveal()]);
|
||||
$this->moduleHandler->invoke($module, 'entity_bundle_field_info', Argument::type('array'))->willReturn([$field_definition->reveal()]);
|
||||
$this->moduleHandler->invokeAllWith(Argument::type('string'), Argument::any())
|
||||
->will(function ($arguments) use ($field_definition, $module) {
|
||||
[$hook, $callback] = $arguments;
|
||||
$callback(
|
||||
function () use ($field_definition) {
|
||||
return [$field_definition->reveal()];
|
||||
},
|
||||
$module,
|
||||
);
|
||||
});
|
||||
|
||||
$this->entityFieldManager->getFieldDefinitions('test_entity_type', 'test_bundle');
|
||||
}
|
||||
|
@ -543,7 +566,7 @@ class EntityFieldManagerTest extends UnitTestCase {
|
|||
$entity_class::$bundleFieldDefinitions = [];
|
||||
|
||||
if (!$custom_invoke_all) {
|
||||
$this->moduleHandler->getImplementations(Argument::cetera())->willReturn([]);
|
||||
$this->moduleHandler->invokeAllWith(Argument::cetera(), Argument::cetera());
|
||||
}
|
||||
|
||||
// Mock the base field definition override.
|
||||
|
@ -683,7 +706,7 @@ class EntityFieldManagerTest extends UnitTestCase {
|
|||
'first_bundle' => 'first_bundle',
|
||||
'second_bundle' => 'second_bundle',
|
||||
])->shouldBeCalled();
|
||||
$this->moduleHandler->getImplementations('entity_base_field_info')->willReturn([]);
|
||||
$this->moduleHandler->invokeAllWith('entity_base_field_info', Argument::any());
|
||||
|
||||
$expected = [
|
||||
'test_entity_type' => [
|
||||
|
@ -738,7 +761,7 @@ class EntityFieldManagerTest extends UnitTestCase {
|
|||
'first_bundle' => 'first_bundle',
|
||||
'second_bundle' => 'second_bundle',
|
||||
])->shouldBeCalled();
|
||||
$this->moduleHandler->getImplementations('entity_base_field_info')->willReturn([])->shouldBeCalled();
|
||||
$this->moduleHandler->invokeAllWith('entity_base_field_info', Argument::any())->shouldBeCalled();
|
||||
|
||||
// Define an ID field definition as a base field.
|
||||
$id_definition = $this->prophesize(FieldDefinitionInterface::class);
|
||||
|
|
|
@ -80,7 +80,6 @@ class EntityTypeBundleInfoTest extends UnitTestCase {
|
|||
parent::setUp();
|
||||
|
||||
$this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
$this->moduleHandler->getImplementations('entity_type_build')->willReturn([]);
|
||||
$this->moduleHandler->alter('entity_type', Argument::type('array'))->willReturn(NULL);
|
||||
|
||||
$this->cacheBackend = $this->prophesize(CacheBackendInterface::class);
|
||||
|
|
|
@ -80,8 +80,6 @@ class EntityTypeManagerTest extends UnitTestCase {
|
|||
parent::setUp();
|
||||
|
||||
$this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
|
||||
$this->moduleHandler->getImplementations('entity_type_build')->willReturn([]);
|
||||
$this->moduleHandler->alter('entity_type', Argument::type('array'))->willReturn(NULL);
|
||||
|
||||
$this->cacheBackend = $this->prophesize(CacheBackendInterface::class);
|
||||
$this->translationManager = $this->prophesize(TranslationInterface::class);
|
||||
|
|
|
@ -289,11 +289,6 @@ class KeyValueEntityStorageTest extends UnitTestCase {
|
|||
->will($this->returnValue([['id' => 'foo']]));
|
||||
$this->keyValueStore->expects($this->never())
|
||||
->method('delete');
|
||||
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('getImplementations')
|
||||
->withConsecutive(['entity_load'], ['test_entity_type_load'])
|
||||
->will($this->returnValue([]));
|
||||
$this->moduleHandler->expects($this->exactly(4))
|
||||
->method('invokeAll')
|
||||
->withConsecutive(
|
||||
|
@ -357,10 +352,6 @@ class KeyValueEntityStorageTest extends UnitTestCase {
|
|||
->will($this->returnValue(get_class($entity)));
|
||||
$this->setUpKeyValueEntityStorage();
|
||||
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('getImplementations')
|
||||
->withConsecutive(['entity_load'], ['test_entity_type_load'])
|
||||
->will($this->returnValue([]));
|
||||
$expected = ['id' => 'foo'];
|
||||
$entity->expects($this->once())
|
||||
->method('toArray')
|
||||
|
@ -480,10 +471,6 @@ class KeyValueEntityStorageTest extends UnitTestCase {
|
|||
->method('getMultiple')
|
||||
->with(['foo'])
|
||||
->will($this->returnValue([['id' => 'foo']]));
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('getImplementations')
|
||||
->withConsecutive(['entity_load'], ['test_entity_type_load'])
|
||||
->will($this->returnValue([]));
|
||||
$entity = $this->entityStorage->load('foo');
|
||||
$this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
|
||||
$this->assertSame('foo', $entity->id());
|
||||
|
@ -499,8 +486,6 @@ class KeyValueEntityStorageTest extends UnitTestCase {
|
|||
->method('getMultiple')
|
||||
->with(['foo'])
|
||||
->will($this->returnValue([]));
|
||||
$this->moduleHandler->expects($this->never())
|
||||
->method('getImplementations');
|
||||
$entity = $this->entityStorage->load('foo');
|
||||
$this->assertNull($entity);
|
||||
}
|
||||
|
@ -522,10 +507,6 @@ class KeyValueEntityStorageTest extends UnitTestCase {
|
|||
$this->keyValueStore->expects($this->once())
|
||||
->method('getAll')
|
||||
->will($this->returnValue([['id' => 'foo'], ['id' => 'bar']]));
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('getImplementations')
|
||||
->withConsecutive(['entity_load'], ['test_entity_type_load'])
|
||||
->will($this->returnValue([]));
|
||||
$entities = $this->entityStorage->loadMultiple();
|
||||
foreach ($entities as $id => $entity) {
|
||||
$this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
|
||||
|
@ -552,10 +533,6 @@ class KeyValueEntityStorageTest extends UnitTestCase {
|
|||
->method('getMultiple')
|
||||
->with(['foo'])
|
||||
->will($this->returnValue([['id' => 'foo']]));
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('getImplementations')
|
||||
->withConsecutive(['entity_load'], ['test_entity_type_load'])
|
||||
->will($this->returnValue([]));
|
||||
$entities = $this->entityStorage->loadMultiple(['foo']);
|
||||
foreach ($entities as $id => $entity) {
|
||||
$this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
|
||||
|
|
|
@ -1444,7 +1444,7 @@ class SqlContentEntityStorageTest extends UnitTestCase {
|
|||
*/
|
||||
protected function setUpModuleHandlerNoImplementations() {
|
||||
$this->moduleHandler->expects($this->any())
|
||||
->method('getImplementations')
|
||||
->method('invokeAllWith')
|
||||
->willReturnMap([
|
||||
['entity_load', []],
|
||||
[$this->entityTypeId . '_load', []],
|
||||
|
|
|
@ -306,36 +306,78 @@ class ModuleHandlerTest extends UnitTestCase {
|
|||
/**
|
||||
* Tests implementations methods when module is enabled.
|
||||
*
|
||||
* @covers ::implementsHook
|
||||
* @covers ::hasImplementations
|
||||
* @covers ::loadAllIncludes
|
||||
*/
|
||||
public function testImplementsHookModuleEnabled() {
|
||||
$module_handler = $this->getModuleHandler();
|
||||
$this->assertTrue($module_handler->implementsHook('module_handler_test', 'hook'), 'Installed module implementation found.');
|
||||
$this->assertTrue($module_handler->hasImplementations('hook', 'module_handler_test'), 'Installed module implementation found.');
|
||||
|
||||
$module_handler->addModule('module_handler_test_added', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_added');
|
||||
$this->assertTrue($module_handler->implementsHook('module_handler_test_added', 'hook'), 'Runtime added module with implementation in include found.');
|
||||
$this->assertTrue($module_handler->hasImplementations('hook', 'module_handler_test_added'), 'Runtime added module with implementation in include found.');
|
||||
|
||||
$module_handler->addModule('module_handler_test_no_hook', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_no_hook');
|
||||
$this->assertFalse($module_handler->implementsHook('module_handler_test_no_hook', 'hook', [TRUE]), 'Missing implementation not found.');
|
||||
$this->assertFalse($module_handler->hasImplementations('hook', 'module_handler_test_no_hook'), 'Missing implementation not found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getImplementations.
|
||||
* Tests deprecation of the ::getImplementations method.
|
||||
*
|
||||
* @covers ::getImplementations
|
||||
* @covers ::getImplementationInfo
|
||||
* @covers ::buildImplementationInfo
|
||||
*
|
||||
* @group legacy
|
||||
*/
|
||||
public function testGetImplementations() {
|
||||
$this->expectDeprecation('ModuleHandlerInterface::getImplementations() is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Instead you should use ModuleHandlerInterface::invokeAllWith() for hook invocations, or you should use ModuleHandlerInterface::hasImplementations() to determine if hooks implementations exist. See https://www.drupal.org/node/3000490');
|
||||
$this->assertEquals(['module_handler_test'], $this->getModuleHandler()->getImplementations('hook'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests deprecation of the ::implementsHook method.
|
||||
*
|
||||
* @covers ::implementsHook
|
||||
*
|
||||
* @group legacy
|
||||
*/
|
||||
public function testImplementsHook() {
|
||||
$this->expectDeprecation('ModuleHandlerInterface::implementsHook() is deprecated in drupal:9.4.0 and is removed from drupal:10.0.0. Instead you should use ModuleHandlerInterface::hasImplementations() with the $modules argument. See https://www.drupal.org/node/3000490');
|
||||
$this->assertTrue($this->getModuleHandler()->implementsHook('module_handler_test', 'hook'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hasImplementations.
|
||||
*
|
||||
* @covers ::hasImplementations
|
||||
*/
|
||||
public function testHasImplementations() {
|
||||
$module_handler = $this->getMockBuilder(ModuleHandler::class)
|
||||
->setConstructorArgs([$this->root, [], $this->cacheBackend])
|
||||
->onlyMethods(['buildImplementationInfo'])
|
||||
->getMock();
|
||||
$module_handler->expects($this->exactly(2))
|
||||
->method('buildImplementationInfo')
|
||||
->with('hook')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
[],
|
||||
['mymodule' => FALSE],
|
||||
);
|
||||
|
||||
// ModuleHandler::buildImplementationInfo mock returns no implementations.
|
||||
$this->assertFalse($module_handler->hasImplementations('hook'));
|
||||
|
||||
// Reset static caches.
|
||||
$module_handler->resetImplementations();
|
||||
|
||||
// ModuleHandler::buildImplementationInfo mock returns an implementation.
|
||||
$this->assertTrue($module_handler->hasImplementations('hook'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getImplementations.
|
||||
*
|
||||
* @covers ::getImplementations
|
||||
* @covers ::getImplementationInfo
|
||||
* @covers ::invokeAllWith
|
||||
*/
|
||||
public function testCachedGetImplementations() {
|
||||
$this->cacheBackend->expects($this->exactly(1))
|
||||
|
@ -361,14 +403,20 @@ class ModuleHandlerTest extends UnitTestCase {
|
|||
|
||||
$module_handler->expects($this->never())->method('buildImplementationInfo');
|
||||
$module_handler->expects($this->once())->method('loadInclude');
|
||||
$this->assertEquals(['module_handler_test'], $module_handler->getImplementations('hook'));
|
||||
$implementors = [];
|
||||
$module_handler->invokeAllWith(
|
||||
'hook',
|
||||
function (callable $hook, string $module) use (&$implementors) {
|
||||
$implementors[] = $module;
|
||||
}
|
||||
);
|
||||
$this->assertEquals(['module_handler_test'], $implementors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getImplementations.
|
||||
*
|
||||
* @covers ::getImplementations
|
||||
* @covers ::getImplementationInfo
|
||||
* @covers ::invokeAllWith
|
||||
*/
|
||||
public function testCachedGetImplementationsMissingMethod() {
|
||||
$this->cacheBackend->expects($this->exactly(1))
|
||||
|
@ -398,7 +446,14 @@ class ModuleHandlerTest extends UnitTestCase {
|
|||
$module_handler->load('module_handler_test');
|
||||
|
||||
$module_handler->expects($this->never())->method('buildImplementationInfo');
|
||||
$this->assertEquals(['module_handler_test'], $module_handler->getImplementations('hook'));
|
||||
$implementors = [];
|
||||
$module_handler->invokeAllWith(
|
||||
'hook',
|
||||
function (callable $hook, string $module) use (&$implementors) {
|
||||
$implementors[] = $module;
|
||||
}
|
||||
);
|
||||
$this->assertEquals(['module_handler_test'], $implementors);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -428,7 +483,7 @@ class ModuleHandlerTest extends UnitTestCase {
|
|||
->expects($this->exactly(2))
|
||||
->method('set')
|
||||
->with($this->logicalOr('module_implements', 'hook_info'));
|
||||
$module_handler->getImplementations('hook');
|
||||
$module_handler->invokeAllWith('hook', function (callable $hook, string $module) {});
|
||||
$module_handler->writeCache();
|
||||
}
|
||||
|
||||
|
@ -469,7 +524,7 @@ class ModuleHandlerTest extends UnitTestCase {
|
|||
public function testResetImplementations() {
|
||||
$module_handler = $this->getModuleHandler();
|
||||
// Prime caches
|
||||
$module_handler->getImplementations('hook');
|
||||
$module_handler->invokeAllWith('hook', function (callable $hook, string $module) {});
|
||||
$module_handler->getHookInfo();
|
||||
|
||||
// Reset all caches internal and external.
|
||||
|
@ -491,7 +546,7 @@ class ModuleHandlerTest extends UnitTestCase {
|
|||
->expects($this->exactly(2))
|
||||
->method('get')
|
||||
->with($this->logicalOr('module_implements', 'hook_info'));
|
||||
$module_handler->getImplementations('hook');
|
||||
$module_handler->invokeAllWith('hook', function (callable $hook, string $module) {});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,7 +41,7 @@ class HookDiscoveryTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetDefinitionsWithoutPlugins() {
|
||||
$this->moduleHandler->expects($this->once())
|
||||
->method('getImplementations')
|
||||
->method('invokeAllWith')
|
||||
->with('test_plugin')
|
||||
->will($this->returnValue([]));
|
||||
|
||||
|
@ -54,17 +54,15 @@ class HookDiscoveryTest extends UnitTestCase {
|
|||
* @see \Drupal\Core\Plugin\Discovery::getDefinitions()
|
||||
*/
|
||||
public function testGetDefinitions() {
|
||||
$this->moduleHandler->expects($this->once())
|
||||
->method('getImplementations')
|
||||
$this->moduleHandler->expects($this->atLeastOnce())
|
||||
->method('invokeAllWith')
|
||||
->with('test_plugin')
|
||||
->will($this->returnValue(['hook_discovery_test', 'hook_discovery_test2']));
|
||||
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('invoke')
|
||||
->willReturnMap([
|
||||
['hook_discovery_test', 'test_plugin', [], $this->hookDiscoveryTestTestPlugin()],
|
||||
['hook_discovery_test2', 'test_plugin', [], $this->hookDiscoveryTest2TestPlugin()],
|
||||
]);
|
||||
->willReturnCallback(function (string $hook, callable $callback) {
|
||||
$callback(\Closure::fromCallable([$this, 'hookDiscoveryTestTestPlugin']), 'hook_discovery_test');
|
||||
$callback(\Closure::fromCallable([$this, 'hookDiscoveryTest2TestPlugin']), 'hook_discovery_test2');
|
||||
});
|
||||
$this->moduleHandler->expects($this->never())
|
||||
->method('invoke');
|
||||
|
||||
$definitions = $this->hookDiscovery->getDefinitions();
|
||||
|
||||
|
@ -86,26 +84,12 @@ class HookDiscoveryTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetDefinition() {
|
||||
$this->moduleHandler->expects($this->exactly(4))
|
||||
->method('getImplementations')
|
||||
->method('invokeAllWith')
|
||||
->with('test_plugin')
|
||||
->will($this->returnValue(['hook_discovery_test', 'hook_discovery_test2']));
|
||||
|
||||
$this->moduleHandler->expects($this->any())
|
||||
->method('invoke')
|
||||
->willReturnMap([
|
||||
[
|
||||
'hook_discovery_test',
|
||||
'test_plugin',
|
||||
[],
|
||||
$this->hookDiscoveryTestTestPlugin(),
|
||||
],
|
||||
[
|
||||
'hook_discovery_test2',
|
||||
'test_plugin',
|
||||
[],
|
||||
$this->hookDiscoveryTest2TestPlugin(),
|
||||
],
|
||||
]);
|
||||
->willReturnCallback(function (string $hook, callable $callback) {
|
||||
$callback(\Closure::fromCallable([$this, 'hookDiscoveryTestTestPlugin']), 'hook_discovery_test');
|
||||
$callback(\Closure::fromCallable([$this, 'hookDiscoveryTest2TestPlugin']), 'hook_discovery_test2');
|
||||
});
|
||||
|
||||
$this->assertNull($this->hookDiscovery->getDefinition('test_non_existent', FALSE));
|
||||
|
||||
|
@ -129,7 +113,7 @@ class HookDiscoveryTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetDefinitionWithUnknownID() {
|
||||
$this->moduleHandler->expects($this->once())
|
||||
->method('getImplementations')
|
||||
->method('invokeAllWith')
|
||||
->will($this->returnValue([]));
|
||||
|
||||
$this->expectException(PluginNotFoundException::class);
|
||||
|
|
|
@ -137,10 +137,12 @@ class RegistryTest extends UnitTestCase {
|
|||
// Include the module and theme files so that hook_theme can be called.
|
||||
include_once $this->root . '/core/modules/system/tests/modules/theme_test/theme_test.module';
|
||||
include_once $this->root . '/core/tests/fixtures/test_stable/test_stable.theme';
|
||||
$this->moduleHandler->expects($this->exactly(2))
|
||||
->method('getImplementations')
|
||||
$this->moduleHandler->expects($this->atLeastOnce())
|
||||
->method('invokeAllWith')
|
||||
->with('theme')
|
||||
->will($this->returnValue(['theme_test']));
|
||||
->willReturnCallback(function (string $hook, callable $callback) {
|
||||
$callback(function () {}, 'theme_test');
|
||||
});
|
||||
$this->moduleHandler->expects($this->atLeastOnce())
|
||||
->method('getModuleList')
|
||||
->willReturn([]);
|
||||
|
|
Loading…
Reference in New Issue