entity_references_map-1.0.0-alpha2/src/Form/MapForm.php

src/Form/MapForm.php
<?php

namespace Drupal\entity_references_map\Form;

use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\FieldConfigInterface;
use Drupal\node\NodeTypeInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Entity Reference map configuration form.
 */
class MapForm extends ConfigFormBase {

  public const CONFIG_NAME = 'entity_references_map.config';

  /**
   * Drupal entity fields manager.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected EntityFieldManagerInterface $entityFieldManager;

  /**
   * Drupal entity type bundle info manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
   */
  protected EntityTypeBundleInfoInterface $entityTypeBundleInfoManager;

  /**
   * The EntityTypeManager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * Constructs MapForm instance.
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    EntityFieldManagerInterface $entityFieldManager,
    EntityTypeBundleInfoInterface $entityTypeBundleInfoManager,
    EntityTypeManagerInterface $entityTypeManager
  ) {
    parent::__construct($config_factory);
    $this->entityFieldManager = $entityFieldManager;
    $this->entityTypeBundleInfoManager = $entityTypeBundleInfoManager;
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory'),
      $container->get('entity_field.manager'),
      $container->get('entity_type.bundle.info'),
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [self::CONFIG_NAME];
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId(): string {
    return 'entity_references_map.map_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, NodeTypeInterface $node_type = NULL): array {

    if (is_null($node_type)) {
      $form['#markup'] = $this->t('Cannot find this node type.');
      return $form;
    }

    $form_state->set('node_type', $node_type);
    $config_data = $this->config(self::CONFIG_NAME)->get();

    $form['#tree'] = TRUE;
    $form['#attributes'] = [
      'id' => 'map_form',
    ];

    $form['enable_checkbox'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable Entity References Map for this node type'),
      '#default_value' => array_key_exists($node_type->id(), $config_data),
      '#attributes' => [
        'id' => 'map_enable_checkbox',
      ],
    ];

    $form['relationships'] = [
      '#type' => 'container',
      '#attributes' => [
        'id' => 'map_relationships_container',
      ],
      '#states' => [
        'visible' => [
          ':input[id="map_enable_checkbox"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $entity_bundle = $node_type->id();
    $forward_reference_fields = $this->getForwardReferenceFieldsData($entity_bundle);
    $backward_reference_fields = $this->getBackwardReferenceFields($entity_bundle);
    $form_state->set('forward_reference_fields', $forward_reference_fields);
    $form_state->set('backward_reference_fields', $backward_reference_fields);

    $forward_references = $this->buildForwardReferenceCheckboxes($forward_reference_fields, $entity_bundle);
    $backward_references = $this->buildBackWardReferenceCheckboxes($backward_reference_fields, $entity_bundle);

    $description = $this->t('There are no reference fields in this node type.');
    if (!empty($forward_references) || !empty($backward_references)) {
      $description = $this->t('Please configure entity type relationships.');
    }

    $form['relationships']['description'] = [
      '#markup' => $description,
    ];

    $form['relationships']['forward_reference']['fields'] = $forward_references;
    $form['relationships']['backward_reference']['fields'] = $backward_references;

    return parent::buildForm($form, $form_state);
  }

  /**
   * Builds render array of form checkboxes for forward_reference fields.
   */
  protected function buildForwardReferenceCheckboxes(array $forward_reference_fields, string $entity_bundle): array {
    $build = [];

    $config_data = $this->config(self::CONFIG_NAME)->get();

    $entity_types = $this->entityTypeManager->getDefinitions();
    // Allow to configure entity types available in the mapping.
    $content_entity_types = array_filter($entity_types, static function ($entity_type) {
      return $entity_type instanceof ContentEntityTypeInterface;
    });

    foreach ($forward_reference_fields as $field_id => $field_info) {
      [
        'label' => $field_label,
        'multiple' => $is_multiple,
        'machine_name' => $machine_name,
        'referenced_entity_type' => $referenced_entity_type,
        'referenced_entity_bundle' => $referenced_entity_bundle,
        'referenced_entity_label' => $referenced_entity_label,
      ] = $field_info;

      $build[$field_id] = [
        '#type' => 'fieldset',
        '#title' => "{$referenced_entity_label}: {$field_label} ({$machine_name})" . ($is_multiple ? ' [multiple]' : ''),
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
      ];

      $build[$field_id]['enabled'] = [
        '#type' => 'checkbox',
        '#title' => $this->t('Enable mapping'),
        '#default_value' => $this->getCheckboxDefaultValue($referenced_entity_bundle, 'forward_reference', $field_id),
      ];

      $input_id = sprintf(":input[id=\"edit-relationships-forward-reference-fields-%s-enabled\"]", str_replace([
        '.',
        '_',
      ], ['', '-'], $field_id));

      $build[$field_id]['header_color'] = [
        '#type' => 'color',
        '#title' => $this->t('Header background color'),
        '#states' => [
          'visible' => [
            $input_id => ['checked' => TRUE],
          ],
        ],
        '#default_value' => NestedArray::getValue($config_data, [
          'node',
          $entity_bundle,
          $machine_name,
          'header_color',
        ]) ?: '#cccccc',
      ];

      $build[$field_id]['content_color'] = [
        '#type' => 'color',
        '#title' => $this->t('Content background color'),
        '#states' => [
          'visible' => [
            $input_id => ['checked' => TRUE],
          ],
        ],
        '#default_value' => NestedArray::getValue($config_data, [
          'node',
          $entity_bundle,
          $machine_name,
          'content_color',
        ]) ?: '#ffffff',
      ];

      $build[$field_id]['nested_levels'] = [
        '#type' => 'select',
        '#title' => $this->t('Build nested levels'),
        '#states' => [
          'visible' => [
            $input_id => ['checked' => TRUE],
          ],
        ],
        '#options' => [
          'none' => $this->t('- None -'),
          'all' => $this->t('Build all nested levels'),
          // @todo implement manual settings for the referenced fields settings.
        ],
        '#default_value' => NestedArray::getValue($config_data, [
          'node',
          $entity_bundle,
          $machine_name,
          'nested_levels',
        ]) ?: 'none',
      ];

      $select_id = sprintf(":input[id=\"edit-relationships-forward-reference-fields-%s-nested-levels\"]", str_replace([
        '.',
        '_',
      ], ['', '-'], $field_id));

      // Form elements for all nested elements settings.
      $build[$field_id]['container_all'] = [
        '#type' => 'fieldset',
        '#title' => $this->t('All nested levels'),
        '#states' => [
          'visible' => [
            $select_id => ['value' => 'all'],
          ],
        ],
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
      ];

      $build[$field_id]['container_all']['entity_types'] = [
        '#type' => 'fieldset',
        '#title' => $this->t('Choose entity types that will be excluded from mapping'),
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
      ];

      /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $content_entity_type */
      foreach ($content_entity_types as $content_entity_type) {
        $entity_type_id = $content_entity_type->id();
        $excluded_entity_types = array_values(NestedArray::getValue($config_data, ['excluded_entity_types']) ?? []);
        if (!in_array($entity_type_id, $excluded_entity_types, TRUE)) {
          $build[$field_id]['container_all']['entity_types'][$entity_type_id] = [
            '#type' => 'checkbox',
            '#title' => $content_entity_type->getLabel(),
            '#default_value' => (bool) NestedArray::getValue($config_data, [
              'node',
              $entity_bundle,
              $machine_name,
              'all',
              'entity_types',
              $entity_type_id,
            ]),
          ];
        }
      }

      $build[$field_id]['container_all']['levels_depth'] = [
        '#type' => 'select',
        '#title' => $this->t('Number of nested levels shown'),
        '#options' => [
          'all' => $this->t('All'),
          1 => 1,
          2 => 2,
          3 => 3,
          4 => 4,
          5 => 5,
        ],
        '#default_value' => NestedArray::getValue($config_data, [
          'node',
          $entity_bundle,
          $machine_name,
          'all',
          'levels_depth',
        ]) ?: 'all',
      ];

      $build[$field_id]['container_all']['header_color'] = [
        '#type' => 'color',
        '#title' => $this->t('Headers background color'),
        '#default_value' => NestedArray::getValue($config_data, [
          'node',
          $entity_bundle,
          $machine_name,
          'all',
          'header_color',
        ]) ?: '#cccccc',
      ];

      $build[$field_id]['container_all']['content_color'] = [
        '#type' => 'color',
        '#title' => $this->t('Contents background color'),
        '#default_value' => NestedArray::getValue($config_data, [
          'node',
          $entity_bundle,
          $machine_name,
          'all',
          'content_color',
        ]) ?: '#ffffff',
      ];
    }

    return $build;
  }

  /**
   * Helper function to return array of backward-reference checkboxes.
   */
  protected function buildBackWardReferenceCheckboxes(array $backward_reference_fields, string $node_type): array {
    $build = [];

    foreach ($backward_reference_fields as $entity_type => $entity_bundle) {
      foreach ($entity_bundle as $field_item) {
        foreach ($field_item as $field_key => $field_info) {
          [
            'label' => $field_label,
            'multiple' => $is_multiple,
            'machine_name' => $machine_name,
            'referenced_entity_type' => $referenced_entity_type,
            'referenced_entity_bundle' => $referenced_entity_bundle,
            'referenced_entity_label' => $referenced_entity_label,
          ] = $field_info;
          $field_id = $referenced_entity_type . '.' . $referenced_entity_bundle . '.' . $machine_name;
          $build[$field_id] = [
            '#type' => 'checkbox',
            '#title' => "{$referenced_entity_label} : {$field_label} ({$machine_name})" . ($is_multiple ? ' [multiple]' : ''),
            '#default_value' => $this->getCheckboxDefaultValue($node_type, 'backward_reference', $field_id),
          ];
        }
      }
    }

    return $build;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getUserInput();
    $config = $this->config(self::CONFIG_NAME);
    $node_type = $form_state->get('node_type');
    $bundle_machine_name = $node_type->id();

    if (empty($values['enable_checkbox'])) {
      $config->clear($bundle_machine_name);
      $config->save();
      return;
    }

    foreach ($values['relationships'] as $relationship_type => $fields) {
      $entity_reference_fields = array_keys(array_filter($fields['fields']));
      $allowed_fields = [];
      $config->clear("$bundle_machine_name.$relationship_type");
      foreach ($entity_reference_fields as $allowed_field) {
        $allowed_field_data = $fields['fields'][$allowed_field];
        if ($allowed_field_data['enabled']) {
          $allowed_fields[] = $allowed_field;
        }
        $config->set("$allowed_field.header_color", $allowed_field_data['header_color']);
        $config->set("$allowed_field.content_color", $allowed_field_data['content_color']);
        $config->set("$allowed_field.nested_levels", $allowed_field_data['nested_levels']);
        if ($fields['fields'][$allowed_field]['nested_levels'] === 'all') {
          $nested_levels_all_data = $allowed_field_data['container_all'];
          $config->set("$allowed_field.all.header_color", $nested_levels_all_data['header_color']);
          $config->set("$allowed_field.all.content_color", $nested_levels_all_data['content_color']);
          if (is_numeric($nested_levels_all_data['levels_depth'])) {
            $config->set("$allowed_field.all.levels_depth", $nested_levels_all_data['levels_depth']);
          }
          else {
            $config->set("$allowed_field.all.levels_depth", NULL);
          }
          foreach ($nested_levels_all_data['entity_types'] as $entity_type => $enabled) {
            if (!empty($enabled)) {
              $config->set("$allowed_field.all.entity_types.$entity_type", $entity_type);
            }
            else {
              $config->clear("$allowed_field.all.entity_types.$entity_type");
            }
          }
        }
        else {
          $config->clear("$allowed_field.all");
        }
      }
      $config->set("$bundle_machine_name.$relationship_type", $allowed_fields);
    }

    $config->set("$bundle_machine_name.type", $node_type->getEntityType()
      ->getBundleOf());
    $config->save();
    parent::submitForm($form, $form_state);
  }

  /**
   * Get "Entity reference" FieldConfigInterface items list of given node type.
   *
   * @param string $bundle
   *   Node bundle name.
   * @param string $entity_type
   *   Entity type name.
   *
   * @return array
   *   Fields [field_config_id => FieldConfigInterface $item] associative array.
   */
  public function getForwardReferenceFieldsList(string $bundle, string $entity_type = 'node'): array {

    $fields = array_filter(
      $this->entityFieldManager->getFieldDefinitions($entity_type, $bundle), function ($field_definition) {
        return $field_definition instanceof FieldConfigInterface;
      }
    );

    $transformedFields = [];
    foreach ($fields as &$field) {
      /** @var \Drupal\field\Entity\FieldConfig $field */
      if ($field->getType() !== 'entity_reference') {
        continue;
      }
      $transformedFields[$field->id()] = $field;
    }

    return $transformedFields;
  }

  /**
   * Get given entity bundle type "entity_reference" fields array data.
   *
   * @param string $bundle
   *   Entity bundle name.
   * @param string $entity_type
   *   Entity type name.
   *
   * @return array
   *   [
   *     field_config_id => [
   *      'label' => $item->label(),
   *      'multiple' => $isMultiple,
   *      'machine_name' => $item->getName(),
   *      'referenced_entity_type' => $item->get('entity_type'),
   *      'referenced_entity_bundle' => $item->get('bundle'),
   *      'referenced_entity_label' => $label,
   *     ],
   *   ];
   */
  public function getForwardReferenceFieldsData(string $bundle, string $entity_type = 'node'): array {
    $entity_type_bundle_info_manager = $this->entityTypeBundleInfoManager;
    return array_map(static function ($item) use ($entity_type_bundle_info_manager) {
      /** @var \Drupal\field\Entity\FieldConfig $item */
      return [
        'label' => $item->label(),
        'machine_name' => $item->getName(),
        'multiple' => $item->getFieldStorageDefinition()->get('cardinality') !== 1,
        'referenced_entity_type' => $item->get('entity_type'),
        'referenced_entity_bundle' => $item->get('bundle'),
        'referenced_entity_label' => $entity_type_bundle_info_manager->getBundleInfo($item->get('entity_type'))[$item->get('bundle')]['label'] ?? t('Undefined'),
      ];
    }, $this->getForwardReferenceFieldsList($bundle, $entity_type));
  }

  /**
   * Get other nodes "entity_reference" fields that reference this node.
   *
   * @param string $bundle
   *   Entity bundle name.
   * @param string $entity_type
   *   Entity type name.
   *
   * @return array
   *   $childEntitiesFields = [
   *      entity_type_id => [
   *        entity_bundle => [
   *          'machine_name' => $field_machine_name,
   *          'label' => $field_label,
   *          'multiple' => $is_field_multiple,
   *        ]
   *      ]
   *   ]
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function getBackwardReferenceFields(string $bundle, string $entity_type = 'node'): array {

    $map = $this->entityFieldManager->getFieldMapByFieldType(
      'entity_reference'
    );
    $ids = [];
    foreach ($map as $type => $info) {
      foreach ($info as $name => $data) {
        foreach ($data['bundles'] as $bundle_name) {
          $ids[] = "$type.$bundle_name.$name";
        }
      }
    }

    $filtered_map = [];
    foreach (FieldConfig::loadMultiple($ids) as $field_config) {
      $field_name = $field_config->getName();
      $target_type = $field_config->getSetting('target_type');
      if (!empty($target_type) && $target_type === $entity_type) {
        $handler_settings = $field_config->getSetting('handler_settings');
        if (isset($handler_settings['target_bundles'][$bundle])) {
          $node_type = $this->entityTypeManager->getStorage('node_type')
            ->load($field_config->get('bundle'));
          $filtered_map[$entity_type][$field_config->get('bundle')][] = [
            'machine_name' => $field_name,
            'label' => $field_config->getLabel(),
            'multiple' => $field_config->getFieldStorageDefinition()->get('cardinality') !== 1,
            'referenced_entity_type' => $field_config->get('entity_type'),
            'referenced_entity_bundle' => $field_config->get('bundle'),
            'referenced_entity_label' => $node_type ? $node_type->label() : $this->t('Undefined node type label.'),
          ];
        }
      }
    }

    return $filtered_map;
  }

  /**
   * Helper method that returns true if ER field is already enabled in config.
   */
  public function getCheckboxDefaultValue(string $entity_bundle, string $reference_type, string $field_id): bool {
    $config_data = $this->config(self::CONFIG_NAME)->get();
    if (!empty($config_data[$entity_bundle][$reference_type])) {
      return in_array($field_id, $config_data[$entity_bundle][$reference_type], TRUE);
    }
    return FALSE;
  }

}

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

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