entity_value_inheritance-1.3.0/src/Plugin/EntityValueInheritanceUpdater/InheritanceOverridePlugin.php

src/Plugin/EntityValueInheritanceUpdater/InheritanceOverridePlugin.php
<?php

namespace Drupal\entity_value_inheritance\Plugin\EntityValueInheritanceUpdater;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Database\Connection;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\State\StateInterface;
use Drupal\entity_value_inheritance\EntityValueInheritanceUpdaterPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Allow content editor the ability to override form values.
 *
 * @EntityValueInheritanceUpdater(
 *   id = "override",
 *   title = @Translation("Override"),
 *   description = @Translation("Allow the end user to override the field value."),
 * )
 */
class InheritanceOverridePlugin extends EntityValueInheritanceUpdaterPluginBase {

  /**
   * State Service.
   */
  protected StateInterface $state;

  /**
   * Database Connection.
   */
  protected Connection $connection;

  /**
   * Module Handler Service.
   */
  protected ModuleHandler $moduleHandler;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $instance->state = $container->get('state');
    $instance->connection = $container->get('database');
    $instance->moduleHandler = $container->get('module_handler');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function alterForm(array $form, FormStateInterface $formState, EntityInterface $entity, FieldDefinitionInterface $fieldDefinition): array {
    $form = parent::alterForm($form, $formState, $entity, $fieldDefinition);

    array_unshift($form['#after_build'], [$this, 'afterBuildForm']);

    if (stripos($form['#prefix'] ?? '', 'evi-override') === FALSE) {
      $form['#prefix'] = ($form['#prefix'] ?? '') . '<div id="evi-override">';
      $form['#suffix'] = '</div>' . ($form['#suffix'] ?? '');

      $form[$this->inheritance->getDestinationReferenceField()]['widget'][0]['target_id']['#ajax'] = [
        'callback' => [$this, 'updateForm'],
        'wrapper' => 'evi-override',
        'event' => 'change',
        'progress' => [
          'type' => 'throbber',
          'message' => $this->t('Updating Form...'),
        ],
      ];

      $form['#validate'][] = [$this, 'validateForm'];
      array_unshift($form['actions']['submit']['#submit'], [$this, 'submitForm']);
    }

    return $form;
  }

  /**
   * Alter the build form.
   */
  public function afterBuildForm(array $form, FormStateInterface &$form_state) {
    // Remove the override for conditional fields setup if override_values is found.
    if (
      $this->moduleHandler->moduleExists('conditional_fields') &&
      isset($form['#conditional_fields']) &&
      isset($form['#conditional_fields']['override_values'])
    ) {
      unset($form['#conditional_fields']['override_values']);
    }

    return $form;
  }

  /**
   * Validation function used to remove errors for non overridden fields.
   */
  public function validateForm(array $form, FormStateInterface $formState) {
    // Get the override values.
    if (!empty($overrideValues = $formState->getValue('override_values', []))) {
      // Get all the previously defined errors.
      $errors = $formState->getErrors();
      // Clear the errors so that we can remove the fields that were overridden.
      $formState->clearErrors();
      // Get a list of all inheritances to loop through.
      $inheritances = $this->helper->getInheritanceItemsBySource($formState->getBuildInfo()['callback_object']->getEntity());
      // Filter out values that are not marked for being overridden.
      $overrideValues = array_filter($overrideValues, function ($item) {
        return $item === 0;
      });
      // Loop through values and remove errors from list.
      foreach ($overrideValues as $overrideValue => $override) {
        $inheritance = $inheritances[$overrideValue] ?? FALSE;
        if ($inheritance) {
          $keys = preg_grep('#^' . $inheritance->getDestinationField() . '#', array_keys($errors));
          foreach ($keys as $key) {
            unset($errors[$key]);
          }
        }
      }
      // Set the errors back to the form state.
      foreach ($errors as $field_name => $error) {
        $formState->setErrorByName($field_name, $error);
      }
    }
  }

  /**
   * Submit Form Functionality.
   */
  public function submitForm(array $form, FormStateInterface $formState) {
    if ($formState->getValue('override_values')) {
      $formState->getFormObject()->getEntity()->overrides = $formState->getValue('override_values', []);
    }
  }

  /**
   * Ajax Response.
   *
   * @param array $form
   *   Form Array.
   * @param \Drupal\Core\Form\FormStateInterface $formState
   *   Form State.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse
   *   Return Ajax Response.
   */
  public function updateForm(array $form, FormStateInterface $formState): AjaxResponse {
    $formState->setRebuild();
    $response = new AjaxResponse();
    $response->addCommand(new ReplaceCommand('#evi-override', $form));
    return $response;
  }

  /**
   * {@inheritdoc}
   */
  public function alterFormField(array $element, FormStateInterface $formState, EntityInterface $entity, FieldDefinitionInterface $fieldDefinition): array {
    $id = $this->inheritance->id();
    $element = parent::alterFormField($element, $formState, $entity, $fieldDefinition);

    $referenceField = $this->inheritance->getDestinationReferenceField();
    if (
      ($entity->isNew() && $formState->getValue($referenceField) !== NULL) ||
      (
        !$entity->isNew() &&
        (
          !empty($entity->get($referenceField)->getString()) ||
          $formState->getValue($referenceField) !== NULL
        )
      )
    ) {
      $element['#states'] = [
        'visible' => [
          ':input[name="override_values[' . $id . ']"]' => ['checked' => TRUE],
        ],
      ];

      $element = [
        'override_' . $id => [
          '#type' => 'checkbox',
          '#title' => $this->t('Override @field', ['@field' => $fieldDefinition->getLabel()]),
          '#parents' => ['override_values', $id],
          '#default_value' => $entity->overrides[$id]->override ?? 0,
          '#weight' => array_key_exists('#weight', $element) ? $element['#weight'] : 0,
        ],
        $fieldDefinition->getName() => $element,
      ];

      if ($this->moduleHandler->moduleExists('field_group') && function_exists('field_group_info_groups')) {
        // If the field_group module is used add the field to the current group.
        $group_fields = field_group_info_groups($entity->getEntityTypeId(), $entity->bundle(), 'form', 'default');
        foreach ($group_fields as $group_field) {
          if (in_array($fieldDefinition->getName(), $group_field->children)) {
            $element['override_' . $id]['#group'] = $group_field->group_name;
            $element[$fieldDefinition->getName()]['#group'] = $group_field->group_name;
          }
        }
      }
    }

    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function fieldGroupFormProcessAlter(array &$element, &$group, &$complete_form): void {
    $element['#show_empty_fields'] = TRUE;
  }

  /**
   * Set the Overrides.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   Entity to upsert the overrides.
   */
  protected function updateOverrides(EntityInterface $entity): void {
    if ($entity->overrides_processed ?? FALSE) {
      return;
    }
    $overrides = $entity->overrides ?? [];
    if (count($overrides) > 0) {
      $upsert = $this->connection
        ->upsert('evi_overrides')
        ->fields(['key', 'inheritance', 'entity_type', 'entity_id', 'override'])
        ->key('key');

      foreach ($overrides as $override => $override_value) {
        $override_value = (is_int($override_value) ? $override_value : (is_object($override_value) ? $override_value->override : 0));
        $upsert->values([
          'key' => sprintf('%s:%s:%s', $entity->getEntityTypeId(), $override, $entity->id()),
          'inheritance' => $override,
          'entity_type' => $entity->getEntityTypeId(),
          'entity_id' => $entity->id(),
          'override' => $override_value,
        ]);

        if ($override_value === 0) {
          // Set the field value to the parent.
          if ($entity->{$this->inheritance->getDestinationReferenceField()} !== NULL) {
            $referenceEntities = $entity->{$this->inheritance->getDestinationReferenceField()}->referencedEntities();
            if (count($referenceEntities) > 0) {
              $entity->{$this->inheritance->getDestinationField()} = $referenceEntities[0]->get($this->inheritance->getSourceField());
            }
          }
        }
      }

      if ($upsert->count() > 0) {
        $upsert->execute();
      }
    }
    $entity->overrides_processed = TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function entityLoadProperties(string $entity_type_id, array $entities = []): void {
    $ids = array_map(function ($entity) {
      return $entity->id();
    }, $entities);

    // Check static cache first
    $cache = &drupal_static(__METHOD__, []);
    $cache_key = $entity_type_id . ':' . implode('|', $ids);

    if (!isset($cache[$cache_key])) {
      $results = $this->connection
        ->select('evi_overrides', 'overrides')
        ->fields('overrides')
        ->condition('overrides.entity_type', $entity_type_id)
        ->condition('overrides.entity_id', $ids, 'IN')
        ->execute()
        ->fetchAll();

      $group = [];
      foreach ($results as $result) {
        $group[$result->entity_id][$result->inheritance] = $result;
      }

      $cache[$cache_key] = $group;
    }

    foreach ($entities as $entity) {
      if (isset($cache[$cache_key][$entity->id()])) {
        $entity->overrides = $cache[$cache_key][$entity->id()];
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public function updateDestination(EntityInterface $sourceEntity, EntityInterface $destinationEntity): bool {
    $this->updateOverrides($sourceEntity);
    $this->updateOverrides($destinationEntity);
    $overrides = isset($destinationEntity->overrides) && array_key_exists($this->inheritance->id(), $destinationEntity->overrides) && $destinationEntity->overrides[$this->inheritance->id()]?->override === '1';
    if (!$overrides) {
      return parent::updateDestination($sourceEntity, $destinationEntity);
    }
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function deleteEntity(EntityInterface $entity): void {
    $this->connection
      ->delete('evi_overrides')
      ->condition('entity_type', $entity->getEntityTypeId())
      ->condition('entity_id', $entity->id())
      ->execute();
  }

  /**
   * {@inheritdoc}
   */
  public function preSaveEntity(EntityInterface $entity): void {
    $this->updateOverrides($entity);
    parent::preSaveEntity($entity);
  }

}

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

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