farm-2.x-dev/modules/core/entity/src/BundlePlugin/BundlePluginInstaller.php
modules/core/entity/src/BundlePlugin/BundlePluginInstaller.php
<?php
namespace Drupal\farm_entity\BundlePlugin;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\entity\BundlePlugin\BundlePluginInstaller as EntityBundlePluginInstaller;
/**
* Extends the entity BundlePluginInstaller service.
*
* Only removes field storage definitions when not in use by another module.
* This allows field names to be reused across bundles.
*
* @see https://www.drupal.org/project/farm/issues/3200219
*/
class BundlePluginInstaller extends EntityBundlePluginInstaller {
/**
* {@inheritdoc}
*/
public function uninstallBundles(EntityTypeInterface $entity_type, array $modules) {
$bundle_handler = $this->entityTypeManager->getHandler($entity_type->id(), 'bundle_plugin');
$bundles = array_filter($bundle_handler->getBundleInfo(), function ($bundle_info) use ($modules) {
return in_array($bundle_info['provider'], $modules, TRUE);
});
/**
* We need to uninstall the field storage definitions in a separate loop.
*
* This way we can allow a module to re-use the same field within multiple
* bundles, allowing e.g to subclass a bundle plugin.
*
* @var \Drupal\entity\BundleFieldDefinition[] $field_storage_definitions
*/
$field_storage_definitions = [];
// Field definitions that should persist after uninstalling these bundles.
$field_definitions_to_persist = $this->getFieldDefinitionsToPersist($entity_type, array_keys($bundles));
foreach (array_keys($bundles) as $bundle) {
$this->entityBundleListener->onBundleDelete($bundle, $entity_type->id());
foreach ($bundle_handler->getFieldDefinitions($bundle) as $definition) {
$field_name = $definition->getName();
$this->fieldDefinitionListener->onFieldDefinitionDelete($definition);
// Delete the field storage definition if it should not persist.
if (!in_array($field_name, array_keys($field_definitions_to_persist))) {
$field_storage_definitions[$field_name] = $definition;
}
}
}
foreach ($field_storage_definitions as $definition) {
$this->fieldStorageDefinitionListener->onFieldStorageDefinitionDelete($definition);
}
}
/**
* Get field definitions from all remaining bundles.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type to check.
* @param array $uninstalled_bundles
* The bundles that will be uninstalled.
*
* @return array
* Remaining field definitions.
*/
protected function getFieldDefinitionsToPersist(EntityTypeInterface $entity_type, array $uninstalled_bundles) {
$bundle_handler = $this->entityTypeManager->getHandler($entity_type->id(), 'bundle_plugin');
$remaining_bundles = array_filter($bundle_handler->getBundleInfo(), function ($bundle_name) use ($uninstalled_bundles) {
return !in_array($bundle_name, $uninstalled_bundles, TRUE);
}, ARRAY_FILTER_USE_KEY);
$fields_to_persist = [];
foreach (array_keys($remaining_bundles) as $bundle) {
foreach ($bundle_handler->getFieldDefinitions($bundle) as $definition) {
$field_name = $definition->getName();
if (!isset($fields_to_persist[$field_name])) {
$fields_to_persist[$field_name] = $definition;
}
}
}
return $fields_to_persist;
}
}
