sites_group_overrides-1.x-dev/src/FormDecorator/EntityOverrides.php

src/FormDecorator/EntityOverrides.php
<?php

declare(strict_types=1);

namespace Drupal\sites_group_overrides\FormDecorator;

use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\system\Controller\CsrfTokenController;
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\group\Entity\GroupRelationshipInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\form_decorator\ContentEntityFormDecoratorBase;
use Drupal\sites_group_overrides\Event\FieldOverrideEvent;
use Drupal\sites\ContextProvider\CurrentSiteContextInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\sites_group_overrides\SitesGroupOverridesServiceInterface;

/**
 * Implementation for all ContentEntityFormInterface forms.
 *
 * @FormDecorator()
 */
final class EntityOverrides extends ContentEntityFormDecoratorBase implements ContainerFactoryPluginInterface {

  use StringTranslationTrait;
  use DependencySerializationTrait;

  /**
   * The group relationship that corresponds to the entity.
   *
   * @var GroupRelationshipInterface
   */
  protected GroupRelationshipInterface $relationship;

  /**
   * {@inheritdoc}
   *
   * @param \Drupal\sites\ContextProvider\CurrentSiteContextInterface $currentSiteContext
   *   The current site context.
   * @param \Drupal\Core\Access\CsrfTokenGenerator $csrfToken
   *   The token generator.
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    protected SitesGroupOverridesServiceInterface $sitesGroupOverridesService,
    protected EventDispatcherInterface $eventDispatcher,
    protected ConfigFactoryInterface $configfactory,
    protected EntityTypeManagerInterface $entityTypeManager,
    protected readonly CurrentSiteContextInterface $currentSiteContext,
    protected readonly CsrfTokenGenerator $csrfToken,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, $configuration, $plugin_id, $plugin_definition) {
    return new self($configuration, $plugin_id, $plugin_definition,
      $container->get('sites_group_overrides.service'),
      $container->get('event_dispatcher'),
      $container->get('config.factory'),
      $container->get('entity_type.manager'),
      $container->get('sites.current_site'),
      $container->get('csrf_token'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function applies(): bool {
    if (!$this->inner instanceof ContentEntityFormInterface) {
      return FALSE;
    }
    // For whatever reason some entites use the 'default' form operation (Term)
    // And other have the 'edit' form opertaion (Nodes).
    if (!in_array($this->inner->getOperation(), ['edit', 'default'])) {
      return FALSE;
    }
    $relationship = $this->sitesGroupOverridesService->getRelationship($this->getEntity());
    if (!$relationship instanceof GroupRelationshipInterface) {
      return FALSE;
    }
    if (empty($this->sitesGroupOverridesService->getSynchronizableFields($relationship, $this->getEntity()))) {
      return FALSE;
    }
    $this->relationship = $relationship;
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, ...$args) {
    $form = parent::buildForm($form, $form_state, ...$args);
    $form['actions']['submit']['#value'] = $this->t('Save override');
    
    $revert_url = Url::fromRoute(
      'sites_group_overrides.revert_to_defaults',
      [
        'group' => $this->relationship->getGroupId(),
        'group_relationship' => $this->relationship->id(),
      ],
      ['query' => ['destination' => Url::fromRoute('<current>')->toString()]],
    );
    if ($revert_url->access()) {
      $form['actions']['revert'] = [
        '#type' => 'link',
        '#title' => $this->t('Revert to defaults'),
        '#url' => $revert_url,
      ];
    }
    unset($form['actions']['delete']);

    // Save the current site_id to the form to make sure the submission always
    // gets processed in the right site context.
    $form['site_id'] = [
      '#type' => 'hidden',
      '#value' => $this->currentSiteContext->getSiteFromContext()->getPluginId(),
    ];

    // Add a SCRF Token so that we can evaluate if the site_id post param is legitimite.
    $form['sites_csrf'] = [
      '#type' => 'hidden',
      '#value' => $this->csrfToken->get('sites_csrf'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $this->getEntity()->setSyncing(TRUE);
    return $this->inner->validateForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function save(array $form, FormStateInterface $form_state) {
    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
    $entity = $this->getEntity();
    $link = $entity->toLink()->toString();
    $original_entity = $this->entityTypeManager->getStorage($entity->getEntityTypeId())->load($entity->id());
    $langcode = $entity->language()->getId();
    if ($original_entity->hasTranslation($langcode)) {
      $original_entity = $original_entity->getTranslation($langcode);
    }

    // Then extract the values of fields that are not rendered through widgets,
    // by simply copying from top-level form values. This leaves the fields
    // that are not being edited within this form untouched.
    $updated = FALSE;

    // We need to "deep clone" the original values because field widgets might modify the original entity.
    $original_values = [];
    foreach ($original_entity->getFields() as $field_name => $field) {
      $original_values[$field_name] = clone $field;
    }

    foreach ($this->sitesGroupOverridesService->getSynchronizableFields($this->relationship, $entity) as $entity_field_name => $relationship_field_value) {
      $original_value = $original_values[$entity_field_name]->getValue();
      $value = NULL;
      // We want to override only if the given values differ from the original entity.
      if ($entity->get($entity_field_name)->hasAffectingChanges($original_values[$entity_field_name], $langcode)) {
        // Use the value that would be saved in the entity for the relationship.
        $entity->get($entity_field_name)->preSave();
        $event = new FieldOverrideEvent($original_entity, $entity, $entity_field_name);
        $this->eventDispatcher->dispatch($event, FieldOverrideEvent::EVENT_NAME);
        $value = $event->getValue();
      }
      $relationship_field_value->setValue($value);

      // Reset the value of the entity to the original value.
      $entity->set($entity_field_name, $original_value);
      $updated = TRUE;
    }

    if ($updated) {
      $this->relationship->save();
    }

    // Supress messages form entity forms - they contain confusing labels..
    $messages = $this->messenger()->all();
    $this->inner->save($form, $form_state);
    $this->messenger()->deleteAll();
    foreach ($messages as $type => $texts) {
      foreach ($texts as $text) {
        $this->messenger()->addMessage($text, $type);
      }
    }
    $entity->setSyncing(false);
    $this->messenger()->addStatus($this->t('%title has been saved.', ['%title' => $link]));
  }

}

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

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