How can I find out which module is providing a particular entity type? I'm implementing hook_entity_type_alter() in a custom module, and I want to identify the entities that are provided by core. Is there a way to get information about the module that implements an entity type, so that I can gets its origin (set in core/lib/Drupal/Core/Extension/ExtensionDiscovery.php) or its package (set in module.info.yml)?
3 Answers
There is no definitive way to derive this. Here is why.
- A decent, but not perfect solution is to maintain a static list of core entity type plugin IDs. However this will change and has changed every minor release due to experimental modules.
- Checking the "package" of a module will not work because some core modules are in packages that may be re-used by contrib, and there is nothing stopping a contrib or custom module from re-using a package name.
- If following best practice, then definitively, any module within the
core/modules
directory is in core. This breaks down when someone hacks core and places their modules incore/modules
for some reason.
I would implement #3 because it is the closest to a definitive, unchanging list for the majority of Drupal sites. However doing #1 is also pretty easy and could easily create a hash of core modules based on core version. Here's an untested approach for #3:
Edit 2016.11.23
See @Peacog's answer to their own question for an implementation that takes into account @Berdir's correction about provider not being equivalent to module, and that it is necessary to take into account entity types provided by core, but not core modules.
$moduleHandler = \Drupal::service('module_handler');
$entityTypeManager = \Drupal::service('entity_type.manager');
$coreModules = [];
/** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
foreach ($entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
$module_name = $entity_type->getProvider();
if (!in_array($module_name, $coreModules)) {
/** @var \Drupal\Core\Extension\ExtensionInterface $module */
$module = $moduleHandler->getModule($module_name);
// Test the module's relative path against core. I think this should work using ^ RegExp operator.
if (preg_match('/^core/', $module->getPath()) {
// A core module implements an entity.
$coreModules[$entity_type_id] = $module_name;
}
}
}
-
4there are some core entity type not provided by core but they actually live in Drupal\Core. your logic won't work there, because then provider is "core" and there is no such module (That's why it is called provider, not module, as it must not be a module)– BerdirCommented Nov 22, 2016 at 19:42
-
You can make use of module handler to get path to extension info file.
/**
* Implements hook_entity_type_alter().
*/
function example_entity_type_alter(array &$entity_types) {
$module_handler = \Drupal::moduleHandler();
foreach ($entity_types as $entity_type => $entity_type_info) {
$provider = $entity_types['block']->getProvider();
$module = $module_handler->getModule($provider);
$info_file = $module->getPathname();
drupal_set_message("$entity_type ---> $provider ($info_file)");
}
}
-
Nice. We posted nearly the same time with the same idea. :-) Commented Nov 22, 2016 at 16:20
Thanks for all the great answers. Here's what I ended up with:
foreach ($entity_types as $entity_type_id => $entity_type) {
$core_entity = FALSE;
$module_name = $entity_type->getProvider();
if ($module_name != 'core') {
// Identify core entity types that are provided by modules.
$module = $module_handler->getModule($module_name);
if (preg_match('/^core/', $module->getPath())){
$core_entity = TRUE;
}
}
else {
// Some core entity types are not provided by a module.
$core_entity = TRUE;
}
}