delivery-8.x-1.x-dev/delivery.module

delivery.module
<?php

/**
 * @file
 * Drupal hooks and helper functions.
 */

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Database\Query\Select;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\RevisionableInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\delivery\Entity\DeliveryItem;
use Drupal\delivery\Entity\MenuLinkContent;
use Drupal\delivery\Form\MenuPushForm;
use Drupal\delivery\MenuLinkContentStorage;
use Drupal\delivery\WorkspaceListBuilder;
use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_module_implements_alter().
 */
function delivery_module_implements_alter(&$implementations, $hook) {
  if (in_array($hook, ['entity_bundle_info_alter', 'entity_base_field_info_alter', 'entity_type_build'])) {
    $group = $implementations['delivery'];
    unset($implementations['delivery']);
    $implementations['delivery'] = $group;
  }
}

/**
 * Alter queries that are tagged as workspace sensitive.
 *
 * Implements hook_query_TAG_alter().
 */
function delivery_query_workspace_sensitive_alter(AlterableInterface $query) {
  if (
    $query instanceof Select &&
    $query->getMetaData('entity_type') &&
    $active_workspace_id = $query->getMetaData('active_workspace_id') &&
    !$query->getMetaData('all_revisions')
  ) {
    $entity_type_id = $query->getMetaData('entity_type');
    $tables = &$query->getTables();
    if (array_key_exists('workspace_association', $tables)) {
      $tables['workspace_association']['join type'] = 'INNER';
      $entityType = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
      $query->innerJoin($entityType->getRevisionTable(), 'revision_table', 'workspace_association.target_entity_revision_id = revision_table.' . $entityType->getKey('revision')  . ' AND revision_table.deleted = 0');
    }
  }
}

/**
 * Implements hook_entity_access().
 */
function delivery_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
  /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspacesManager */
  $workspacesManager = \Drupal::service('workspaces.manager');
  /** @var \Drupal\workspaces\WorkspaceAssociationInterface $workspaceAssociation */
  $workspaceAssociation = \Drupal::service('workspaces.association');
  if ($operation == 'deliver') {
    if ($account->hasPermission('deliver items')) {
      return AccessResult::allowed();
    }
    return AccessResult::forbidden();
  }
  if ($workspacesManager->isEntityTypeSupported($entity->getEntityType())) {
    // Statically cache results in an array keyed by $account->id().
    $trackingWorkspaces = &drupal_static(__FUNCTION__);
    $key = $entity->getEntityTypeId() . ':' . $entity->id();
    if (!isset($trackingWorkspaces[$key])) {
      $trackingWorkspaces[$key] = $workspaceAssociation->getEntityTrackingWorkspaceIds($entity);
    }
    $activeWorkspace = $workspacesManager->getActiveWorkspace();
    if ($activeWorkspace && !in_array($activeWorkspace->id(), $trackingWorkspaces[$key])) {
      return AccessResult::forbidden();
    }
  }
  if ($entity instanceof DeliveryItem) {
    $storage = \Drupal::entityTypeManager()
      ->getStorage('delivery');
    $deliveries = $storage
      ->getQuery()
      ->condition('items', $entity->id())->execute();
    if ($delivery = $storage->load(array_pop($deliveries))) {
      return $delivery->access($operation, $account, TRUE);
    }
  }
}

/**
 * Implements hook_entity_type_build().
 *
 * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
 */
function delivery_entity_type_build(array &$entity_types) {
  /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspacesManager */
  $workspacesManager = \Drupal::service('workspaces.manager');
  $entity_types['menu_link_content']->setHandlerClass('storage', MenuLinkContentStorage::class);
  $entity_types['menu_link_content']->setClass(MenuLinkContent::class);
  // Override the list builder so we can inject our own deploy button.
  $entity_types['workspace']->setHandlerClass('list_builder', WorkspaceListBuilder::class);

  // Remove the workspace conflict constraint.
  foreach ($entity_types as $entityType) {
    $constraints = $entityType->getConstraints();
    unset($constraints['EntityWorkspaceConflict']);
    unset($constraints['EntityChanged']);
    unset($constraints['MenuTreeHierarchy']);
    // Mark file and crop entities internal. Questionable, I know.
    if ($entityType->id() === 'file' || $entityType->id() === 'crop') {
      $entityType->set('internal', TRUE);
    }
    // Allow to edit untranslatable fields.
    if (
      $entityType instanceof ContentEntityTypeInterface &&
      $entityType->isRevisionable() &&
      !$entityType->isInternal()
    ) {
      unset($constraints['EntityUntranslatableFields']);
    }

    $entityType->setConstraints($constraints);

    if ($workspacesManager->isEntityTypeSupported($entityType)) {
      // Add the required entity key.
      $entity_keys = $entityType->get('revision_metadata_keys');
      $entity_keys['deleted'] = 'deleted';
      $entityType->set('revision_metadata_keys', $entity_keys);
    }
  }
}

/**
 * Implements hook_ENTITY_TYPE_view_alter() for deliveries.
 */
function delivery_delivery_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  $build['items'] = views_embed_view(
    'delivery_status',
    'embed',
    $entity->id()
  );
}

function delivery_form_field_config_edit_form_alter(&$form, FormStateInterface $formState) {
  /** @var \Drupal\field\FieldConfigInterface $entity */
  $entity = $formState->getFormObject()->getEntity();
  $form['third_party_settings']['delivery'] = [
    '#type' => 'details',
    '#title' => t('Conflict resolution'),
    '#open' => TRUE,
    'blacklisted' => [
      '#type' => 'checkbox',
      '#title' => t('Blacklisted'),
      '#description' => t('Exclude this field from conflict resolution.'),
      '#default_value' => $entity->getThirdPartySetting('delivery', 'blacklisted', FALSE),
    ],
  ];
}

/**
 * Implements hook_form_alter().
 */
function delivery_form_alter(&$form, FormStateInterface $formState, $formId) {
  // Ensure the revision revert confirmation form works in all workspaces.
  $formState->set('workspace_safe', TRUE);
  $formObject = $formState->getFormObject();

  // Set the default language to the current workspace primary language.
  if (
    $formObject instanceof EntityFormInterface &&
    $formObject->getEntity() instanceof ContentEntityInterface &&
    $formObject->getEntity()->isTranslatable() &&
    array_key_exists('langcode', $form)
  ) {
    $form['langcode']['#access'] = $formObject->getEntity()->isNew();
    if ($formObject->getEntity()->isNew()) {
      /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspaceManager */
      $workspaceManager = \Drupal::service('workspaces.manager');
      $workspace = $workspaceManager->getActiveWorkspace();
      if (!empty($workspace->primary_language) && $defaultLanguage = $workspace->primary_language->value) {
        $form['langcode']['widget'][0]['value']['#default_value'] = $defaultLanguage;
      }
      if (!empty($workspace->secondary_languages) && !$workspace->secondary_languages->value) {
        $form['langcode']['#access'] = FALSE;
      }
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function delivery_form_menu_edit_form_alter(&$form, FormStateInterface $form_state) {
  /** @var \Drupal\workspaces\WorkspaceManagerInterface $manager */
  $workspacesManager = \Drupal::service('workspaces.manager');
  /** @var \Drupal\system\Entity\Menu $menu */
  $menu = $form_state->getFormObject()->getEntity();
  $currentUser = \Drupal::currentUser();
  $activeWorkspace = $workspacesManager->getActiveWorkspace();

  if (!$activeWorkspace->isDefaultWorkspace()) {
    $form['actions']['publish'] = [
      '#type' => 'link',
      '#title' => new TranslatableMarkup('Publish'),
      '#access' => $currentUser->hasPermission('deliver items'),
      '#attributes' => [
        'class' => ['button', 'button--primary'],
      ],
      '#weight' => 6,
      '#url' => Url::fromRoute(
        'delivery.workspace_delivery_controller',
        [
          'workspace' => $activeWorkspace->id(),
        ],
        [
          'query' => [
            'entity_type' => 'menu_link_content',
            'bundle' => $menu->id(),
            'hide_options_elements' => 1,
          ],
        ]
      ),
    ];
  }

  $menuId = $menu->id();
  $messenger = \Drupal::messenger();
  $differences = MenuPushForm::differences($menuId);
  if ($differences !== FALSE) {
    if ($differences) {
      $messenger->addWarning(t('There are @count unpublished menu changes. <a href=":link">Publish them?</a>', [
        '@count' => count($differences),
        ':link' => Url::fromRoute('delivery.menu_push', [
          'menu' => $menuId,
        ])->toString(),
      ]));
    }
    else {
      $messenger->addMessage(t('This menu is fully published.'));
    }
  }
}

/**
 * Implements hook_entity_bundle_info_alter().
 */
function delivery_entity_bundle_info_alter(&$bundles) {
  // Make sure moderation states are never translatable.
  $bundles['content_moderation_state']['content_moderation_state']['translatable'] = FALSE;
}

/**
 * Implements hook_entity_base_field_info_alter().
 */
function delivery_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
  // Make sure all languages are always in the same moderation state.
  if (isset($fields['moderation_state'])) {
    $fields['moderation_state']->setTranslatable(FALSE);
  }
  // Make sure all languages are simultaneously published.
  if (isset($fields['status'])) {
    $fields['status']->setTranslatable(FALSE);
  }

  // Set menu tree related fields revisionable.
  if ($entity_type->id() === 'menu_link_content') {
    $revisionableFields = [
      'weight',
      'expanded',
      'enabled',
      'parent',
    ];

    foreach ($revisionableFields as $revisionableField) {
      $fields[$revisionableField]->setRevisionable(TRUE);
    }
  }
}

/**
 * Implements hook_entity_base_field_info().
 *
 * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
 */
function delivery_entity_base_field_info(EntityTypeInterface $entity_type) {
  $fields = [];
  if ($entity_type->id() === 'user') {
    $fields['assigned_workspaces'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Assigned workspaces'))
      ->setDescription(t('The list of workspaces that are assigned to this user.'))
      ->setSetting('target_type', 'workspace')
      ->setSetting('handler', 'default')
      ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
      ->setDisplayOptions('view', array(
        'label' => 'above',
        'type' => 'entity_reference_label',
        'weight' => -3,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'entity_reference_autocomplete',
        'settings' => array(
          'match_operator' => 'CONTAINS',
          'size' => 60,
          'autocomplete_type' => 'tags',
          'placeholder' => '',
        ),
        'weight' => -3,
      ))
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
  }

  if ($entity_type->id() === 'workspace') {
    $fields['auto_push'] = BaseFieldDefinition::create('boolean')
      ->setLabel(new TranslatableMarkup('Auto push'))
      ->setDescription(new TranslatableMarkup('Automatically merge default revisions into the parent workspace'))
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE)
      ->setDefaultValue(FALSE)
      ->setDisplayOptions('form', [
        'type' => 'boolean_checkbox',
        'settings' => [
          'display_label' => TRUE,
        ],
        'weight' => 7,
      ])
      ->setDisplayConfigurable('form', TRUE);
  }

  /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspaceManager */
  $workspaceManager = \Drupal::service('workspaces.manager');
  // Attach a revisionable "deleted" field.
  if ($workspaceManager->isEntityTypeSupported($entity_type)) {
    $fields['deleted'] = BaseFieldDefinition::create('timestamp')
      ->setLabel(t('Deleted'))
      ->setDescription(t('Time when the item got deleted'))
      ->setInternal(TRUE)
      ->setTranslatable(FALSE)
      ->setRevisionable(TRUE)
      ->setDefaultValue(0);
  }
  return $fields;
}

function delivery_entity_update(EntityInterface $entity) {
  if ($entity instanceof ContentEntityInterface && !$entity->isSyncing()) {
    $entityType = $entity->getEntityType();

    /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspaceManager */
    $workspaceManager = \Drupal::service('workspaces.manager');
    if (!$workspaceManager->isEntityTypeSupported($entityType)) {
      return;
    }

    $activeWorkspace = $workspaceManager->getActiveWorkspace();
    if (!$activeWorkspace->auto_push->value || !$activeWorkspace->parent->entity) {
      return;
    }

    /** @var \Drupal\content_moderation\ModerationInformationInterface $content_moderation_info */
    $content_moderation_info = \Drupal::service('content_moderation.moderation_information');
    $workflow = $content_moderation_info->getWorkflowForEntity($entity);
    if (!($workflow && $workflow->getTypePlugin()->hasState($entity->moderation_state->value))) {
      return;
    }

    $current_state = $workflow->getTypePlugin()->getState($entity->moderation_state->value);
    if (!$current_state->isDefaultRevisionState()) {
      return;
    }

    /** @var \Drupal\workspaces\WorkspaceAssociationInterface $workspaceAssiociaton */
    $workspaceAssiociaton = \Drupal::service('workspaces.association');
    /** @var \Drupal\workspaces\WorkspaceInterface $parentWorkspace */
    $parentWorkspace = $activeWorkspace->parent->entity;
    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
    $storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId());

    $parentRevisions = $workspaceAssiociaton->getTrackedEntities(
      $parentWorkspace->id(),
      $entity->getEntityTypeId(),
      [$entity->id()]
    );

    if (empty($parentRevisions)) {
      $parentRevisions = array_keys($storage->getQuery()->allRevisions()
        ->notExists('workspace')
        ->condition($storage->getEntityType()->getKey('id'), $entity->id())
        ->execute());
    }
    else {
      $parentRevisions = array_keys($parentRevisions[$entity->getEntityTypeId()]);
    }

    /** @var ContentEntityInterface $result */
    $result = $storage->createRevision($entity);

    $revisionParentField = $entityType->getRevisionMetadataKey('revision_parent');
    $revisionMergeParentField = $entityType->getRevisionMetadataKey('revision_merge_parent');

    $result->{$revisionMergeParentField}->target_revision_id = $entity->getRevisionId();
    $result->{$revisionParentField}->target_revision_id = array_pop($parentRevisions);
    $result->workspace = $parentWorkspace;
    $result->setSyncing(TRUE);
    $workspaceManager->unsafeExecuteInWorkspace($parentWorkspace->id(), function () use ($result) {
      $result->save();
    });
  }
}

/**
 * Implements hook_entity_load().
 */
function delivery_entity_load(array $entities, $entity_type_id) {
  $entityType = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
  /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspaceManager */
  $workspaceManager = \Drupal::service('workspaces.manager');
  if ($workspaceManager->isEntityTypeSupported($entityType)) {
    /** @var \Drupal\workspaces\WorkspaceAssociationInterface $workspaceAssociation */
    $workspaceAssociation = \Drupal::service('workspaces.association');
    $active_workspace = $workspaceManager->getActiveWorkspace();
    if (!$active_workspace) {
      return;
    }
    $tracking = $workspaceAssociation->getTrackedEntities($active_workspace->id(), $entity_type_id, array_keys($entities));
    if (empty($tracking)) {
      return;
    }
    foreach ($entities as $entity) {
      /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
      $entity->isDefaultRevision(array_key_exists($entity->getRevisionId(), $tracking[$entity_type_id]));
    }
  }
}

/**
 * Implements hook_entity_predelete().
 */
function delivery_entity_predelete(EntityInterface $entity) {
  /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspaceManager */
  $workspaceManager = \Drupal::service('workspaces.manager');
  $entityType = $entity->getEntityType();
  if ($workspaceManager->isEntityTypeSupported($entityType) && $entity instanceof RevisionableInterface) {
    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
    $storage = \Drupal::entityTypeManager()->getStorage($entityType->id());
    $deleted = $storage->createRevision($entity);
    $deleted->deleted = \Drupal::time()->getRequestTime();
    $deleted->save();
    return EntityStorageInterface::ENTITY_SOFT_DELETE;
  }
}

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

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