block_editor-1.0.x-dev/src/Service/EntityManager.php

src/Service/EntityManager.php
<?php

namespace Drupal\block_editor\Service;

use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\Yaml\Yaml;

/**
 * Manager for Block Editor content types.
 *
 * @package Drupal\block_editor
 */
class EntityManager {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;
  /**
   * The entity field manager.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $entityFieldManager;

  /**
   * The entity type bundle info service.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected $entityTypeBundleInfo;

  /**
   * The typed config manager.
   *
   * @var \Drupal\Core\Config\TypedConfigManagerInterface
   */
  protected $typedConfigManager;

  /**
   * The current route match.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface
   */
  protected $routeMatch;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * The logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  protected $loggerFactory;

  /**
   * Static cache for supported entity type mappings.
   *
   * @var array|null
   */
  protected static $supportedMappingsCache = NULL;

  /**
   * Constructs a new EntityManager.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
   *   The entity field manager.
   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
   *   The entity type bundle info service.
   * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
   *   The typed config manager.
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The current route match.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger factory.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    EntityFieldManagerInterface $entity_field_manager,
    EntityTypeBundleInfoInterface $entity_type_bundle_info,
    TypedConfigManagerInterface $typed_config_manager,
    RouteMatchInterface $route_match,
    ModuleHandlerInterface $module_handler,
    LoggerChannelFactoryInterface $logger_factory,
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->entityFieldManager = $entity_field_manager;
    $this->entityTypeBundleInfo = $entity_type_bundle_info;
    $this->typedConfigManager = $typed_config_manager;
    $this->routeMatch = $route_match;
    $this->moduleHandler = $module_handler;
    $this->loggerFactory = $logger_factory;
  }

  /**
   * Checks if a config entity supports Block Editor settings.
   *
   * This checks if the entity type has been explicitly configured to support
   * Block Editor by checking if it's in the supported mappings list.
   *
   * @param \Drupal\Core\Config\Entity\ConfigEntityInterface $entity
   *   The config entity to check.
   *
   * @return bool
   *   TRUE if the entity type supports Block Editor settings.
   */
  public function supportsBlockEditorSettings(ConfigEntityInterface $entity) {
    // Check if the entity supports third-party settings.
    // Config entities that extend ThirdPartySettingsInterface support this.
    if (!method_exists($entity, 'getThirdPartySetting')) {
      return FALSE;
    }

    // Check if this entity type is in our supported mappings.
    // This ensures we only support entity types with explicit schema
    // definitions.
    $entity_type_id = $entity->getEntityTypeId();
    $supported_mappings = $this->getSupportedEntityTypeMappings();

    return isset($supported_mappings[$entity_type_id]);
  }

  /**
   * Checks if an entity type supports Block Editor settings by entity type.
   *
   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
   *   The entity type.
   *
   * @return bool
   *   TRUE if the entity type supports Block Editor settings.
   */
  public function entityTypeSupportsBlockEditor($entity_type) {
    $entity_type_id = $entity_type->id();
    $bundle_of = $entity_type->getBundleOf();

    if (!$bundle_of) {
      return FALSE;
    }

    // Load a sample bundle to check if schema exists.
    $bundles = $this->entityTypeBundleInfo->getBundleInfo($bundle_of);
    if (empty($bundles)) {
      return FALSE;
    }

    // Get the first bundle to check schema.
    $bundle_id = key($bundles);
    $bundle = $this->entityTypeManager
      ->getStorage($entity_type_id)
      ->load($bundle_id);

    if (!$bundle instanceof ConfigEntityInterface) {
      return FALSE;
    }

    return $this->supportsBlockEditorSettings($bundle);
  }

  /**
   * Checks if Block Editor is enabled for an entity.
   *
   * @param \Drupal\Core\Config\Entity\ConfigEntityInterface $entity
   *   The config entity.
   *
   * @return bool
   *   TRUE if Block Editor is enabled for the entity.
   */
  public function isBlockEditorEnabledForEntity(ConfigEntityInterface $entity) {
    if (!$this->supportsBlockEditorSettings($entity)) {
      return FALSE;
    }

    return (bool) $entity->getThirdPartySetting('block_editor', 'enabled', FALSE);
  }

  /**
   * Checks if any bundles have Block Editor enabled for an entity type.
   *
   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
   *   The entity type.
   *
   * @return bool
   *   TRUE if any bundles have Block Editor enabled.
   */
  public function hasBlockEditorEnabledBundles($entity_type) {
    $entity_type_id = $entity_type->id();
    $bundle_entity_type = $entity_type->getBundleOf();

    if (!$bundle_entity_type) {
      return FALSE;
    }

    $bundles = $this->entityTypeBundleInfo->getBundleInfo($bundle_entity_type);

    foreach ($bundles as $bundle_id => $bundle_info) {
      $bundle_entity = $this->entityTypeManager
        ->getStorage($entity_type_id)
        ->load($bundle_id);

      if ($bundle_entity && $this->isBlockEditorEnabledForEntity($bundle_entity)) {
        return TRUE;
      }
    }

    return FALSE;
  }

  /**
   * Checks if Block Editor is enabled for a content entity's bundle.
   *
   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
   *   The content entity.
   *
   * @return bool
   *   TRUE if Block Editor is enabled for the bundle.
   */
  public function isBlockEditorEnabledForContentEntity(ContentEntityInterface $entity): bool {
    $entity_type = $entity->getEntityType();
    $bundle_entity_type_id = $entity_type->getBundleEntityType();

    if (!$bundle_entity_type_id) {
      return FALSE;
    }

    $bundle = $this->entityTypeManager
      ->getStorage($bundle_entity_type_id)
      ->load($entity->bundle());

    if (!$bundle instanceof ConfigEntityInterface) {
      return FALSE;
    }

    return $this->isBlockEditorEnabledForEntity($bundle);
  }

  /**
   * Gets all entity type mappings that support Block Editor.
   *
   * Returns an array mapping bundle entity types to their content entity types
   * (e.g., 'node_type' => 'node', 'comment_type' => 'comment').
   *
   * Discovers entity types from *.block_editor.yml configuration files in
   * enabled modules.
   *
   * @return array
   *   An associative array where keys are bundle entity type IDs and values
   *   are content entity type IDs.
   */
  public function getSupportedEntityTypeMappings(): array {
    // Return cached result if available.
    if (static::$supportedMappingsCache !== NULL) {
      return static::$supportedMappingsCache;
    }

    // Start with built-in supported entity types.
    static::$supportedMappingsCache = [
      'node_type' => 'node',
      'taxonomy_vocabulary' => 'taxonomy_term',
      'block_content_type' => 'block_content',
    ];

    // Discover additional entity types from *.block_editor.yml files.
    // @todo In the future, consider implementing schema-only detection to
    // reduce to a single file requirement. This would require a more
    // sophisticated schema introspection approach that doesn't rely on
    // hasConfigSchema() which returns true for generic third_party patterns.
    $this->discoverEntityTypesFromYamlFiles();

    return static::$supportedMappingsCache;
  }

  /**
   * Discovers entity types from *.block_editor.yml configuration files.
   *
   * Scans all enabled modules for files matching *.block_editor.yml pattern
   * and merges their entity type mappings.
   */
  protected function discoverEntityTypesFromYamlFiles(): void {
    $modules = $this->moduleHandler->getModuleList();

    foreach ($modules as $module_name => $module) {
      $config_file = $module->getPath() . '/' . $module_name . '.block_editor.yml';

      if (!file_exists($config_file)) {
        continue;
      }

      try {
        $config = Yaml::parseFile($config_file);

        if (isset($config['entity_types']) && is_array($config['entity_types'])) {
          foreach ($config['entity_types'] as $bundle_type => $content_type) {
            // Don't override built-in mappings.
            if (!isset(static::$supportedMappingsCache[$bundle_type])) {
              static::$supportedMappingsCache[$bundle_type] = $content_type;
            }
          }
        }
      }
      catch (\Exception $e) {
        // Log error but don't break - skip this file.
        $this->loggerFactory->get('block_editor')->error(
          'Error parsing @file: @message',
          ['@file' => $config_file, '@message' => $e->getMessage()]
        );
      }
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc