workbench_moderation.module 9.23 KB
Newer Older
larowlan's avatar
larowlan committed
1 2 3 4
<?php

/**
 * @file
5
 * Contains workbench_moderation.module.
larowlan's avatar
larowlan committed
6
 *
larowlan's avatar
larowlan committed
7
 * @todo include UI bits of https://www.drupal.org/node/2429153
8
 * @todo How to remove the live version (i.e. published => draft without new
larowlan's avatar
larowlan committed
9
 *   revision) - i.e. unpublish
larowlan's avatar
larowlan committed
10 11
 */

12
use Drupal\Core\Access\AccessResult;
13 14
use Drupal\Core\Action\Plugin\Action\PublishAction;
use Drupal\Core\Action\Plugin\Action\UnpublishAction;
15
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
16
use Drupal\Core\Entity\EntityInterface;
larowlan's avatar
larowlan committed
17
use Drupal\Core\Entity\EntityTypeInterface;
18
use Drupal\Core\Form\FormStateInterface;
larowlan's avatar
larowlan committed
19
use Drupal\Core\Routing\RouteMatchInterface;
20 21
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;
22 23 24 25
use Drupal\node\Plugin\Action\PublishNode;
use Drupal\node\Plugin\Action\UnpublishNode;
use Drupal\workbench_moderation\Plugin\Action\ModerationOptOutPublishNode;
use Drupal\workbench_moderation\Plugin\Action\ModerationOptOutUnpublishNode;
26
use Drupal\workbench_moderation\Plugin\Menu\EditTab;
larowlan's avatar
larowlan committed
27 28 29 30

/**
 * Implements hook_help().
 */
Crell's avatar
Crell committed
31
function workbench_moderation_help($route_name, RouteMatchInterface $route_match) {
larowlan's avatar
larowlan committed
32
  switch ($route_name) {
33
    // Main module help for the workbench_moderation module.
34
    case 'help.page.workbench_moderation':
larowlan's avatar
larowlan committed
35 36
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
37
      $output .= '<p>' . t('Provides basic moderation for content') . '</p>';
larowlan's avatar
larowlan committed
38 39 40 41 42 43 44 45 46
      return $output;

    default:
  }
}

/**
 * Implements hook_entity_base_field_info().
 */
Crell's avatar
Crell committed
47
function workbench_moderation_entity_base_field_info(EntityTypeInterface $entity_type) {
48
  return \Drupal::service('workbench_moderation.entity_type')->entityBaseFieldInfo($entity_type);
larowlan's avatar
larowlan committed
49 50
}

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
/**
 * Implements hook_module_implements_alter().
 */
function workbench_moderation_module_implements_alter(&$implementations, $hook) {
  /** @var \Drupal\workbench_moderation\InlineEditingDisabler $inline_editing_disabler */
  $inline_editing_disabler = \Drupal::service('workbench_moderation.inline_editing_disabler');
  $inline_editing_disabler->moduleImplementsAlter($implementations, $hook);
}

/**
 * Implements hook_entity_view_alter().
 */
function workbench_moderation_entity_view_alter(&$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  /** @var \Drupal\workbench_moderation\InlineEditingDisabler $inline_editing_disabler */
  $inline_editing_disabler = \Drupal::service('workbench_moderation.inline_editing_disabler');
  $inline_editing_disabler->entityViewAlter($build, $entity, $display);
}

69 70 71
/**
 * Implements hook_entity_type_alter().
 */
Crell's avatar
Crell committed
72
function workbench_moderation_entity_type_alter(array &$entity_types) {
73
  \Drupal::service('workbench_moderation.entity_type')->entityTypeAlter($entity_types);
74 75
}

76 77 78
/**
 * Implements hook_entity_operation().
 */
Crell's avatar
Crell committed
79
function workbench_moderation_entity_operation(EntityInterface $entity) {
80
  return \Drupal::service('workbench_moderation.entity_type')->entityOperation($entity);
81 82
}

larowlan's avatar
larowlan committed
83 84 85
/**
 * Sets required flag based on enabled state.
 */
Crell's avatar
Crell committed
86
function workbench_moderation_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
87
  return \Drupal::service('workbench_moderation.entity_type')->entityBundleFieldInfoAlter($fields, $entity_type, $bundle);
larowlan's avatar
larowlan committed
88 89
}

90 91 92 93 94 95 96
/**
 * Implements hook_entity_load().
 */
function workbench_moderation_entity_storage_load(array $entities, $entity_type_id) {
  return \Drupal::service('workbench_moderation.entity_operations')->entityStorageLoad($entities, $entity_type_id);
}

larowlan's avatar
larowlan committed
97
/**
98
 * Implements hook_entity_presave().
larowlan's avatar
larowlan committed
99
 */
Crell's avatar
Crell committed
100
function workbench_moderation_entity_presave(EntityInterface $entity) {
101
  return \Drupal::service('workbench_moderation.entity_operations')->entityPresave($entity);
larowlan's avatar
larowlan committed
102
}
103

104 105 106 107 108 109 110 111 112 113 114 115 116 117
/**
 * Implements hook_entity_insert().
 */
function workbench_moderation_entity_insert(EntityInterface $entity) {
  return \Drupal::service('workbench_moderation.entity_operations')->entityInsert($entity);
}

/**
 * Implements hook_entity_update().
 */
function workbench_moderation_entity_update(EntityInterface $entity) {
  return \Drupal::service('workbench_moderation.entity_operations')->entityUpdate($entity);
}

118 119 120
/**
 * Implements hook_local_tasks_alter().
 */
Crell's avatar
Crell committed
121
function workbench_moderation_local_tasks_alter(&$local_tasks) {
122 123 124 125 126 127 128 129 130 131
  $content_entity_type_ids = array_keys(array_filter(\Drupal::entityTypeManager()->getDefinitions(), function (EntityTypeInterface $entity_type) {
    return $entity_type->isRevisionable();
  }));

  foreach ($content_entity_type_ids as $content_entity_type_id) {
    if (isset($local_tasks["entity.$content_entity_type_id.edit_form"])) {
      $local_tasks["entity.$content_entity_type_id.edit_form"]['class'] = EditTab::class;
      $local_tasks["entity.$content_entity_type_id.edit_form"]['entity_type_id'] = $content_entity_type_id;
    }
  }
132
}
133 134 135 136

/**
 * Implements hook_form_alter().
 */
Crell's avatar
Crell committed
137
function workbench_moderation_form_alter(&$form, FormStateInterface $form_state, $form_id) {
138
  return \Drupal::service('workbench_moderation.entity_type')->bundleFormAlter($form, $form_state, $form_id);
139
}
140 141 142 143 144 145 146 147

/**
 * Implements hook_preprocess_HOOK().
 *
 * Many default node templates rely on $page to determine whether to output the
 * node title as part of the node content.
 */
function workbench_moderation_preprocess_node(&$variables) {
becw's avatar
becw committed
148
  \Drupal::service('workbench_moderation.workbench_preprocess')->preprocessNode($variables);
149
}
150 151 152 153 154 155 156

/**
 * Implements hook_entity_extra_field_info().
 */
function workbench_moderation_entity_extra_field_info() {
  return \Drupal::service('workbench_moderation.entity_type')->entityExtraFieldInfo();
}
157 158 159 160 161 162 163

/**
 * Implements hook_entity_view().
 */
function workbench_moderation_entity_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) {
  \Drupal::service('workbench_moderation.entity_operations')->entityView($build, $entity, $display, $view_mode);
}
164 165 166 167 168 169 170 171 172

/**
 * Implements hook_entity_access().
 *
 * Nodes in particular should be viewable if unpublished and the user has
 * the appropriate permission. This permission is therefore effectively
 * mandatory for any user that wants to moderate things.
 */
function workbench_moderation_node_access(NodeInterface $entity, $operation, AccountInterface $account) {
Crell's avatar
Crell committed
173 174 175
  /** @var \Drupal\workbench_moderation\ModerationInformationInterface $modinfo */
  $moderation_info = Drupal::service('workbench_moderation.moderation_information');

176 177 178 179 180
  if ($operation == 'view') {
    return (!$entity->isPublished())
      ? AccessResult::allowedIfHasPermission($account, 'view any unpublished content')
      : AccessResult::neutral();
  }
Crell's avatar
Crell committed
181
  elseif ($operation == 'update' && $moderation_info->isModeratableEntity($entity) && $entity->moderation_information && $entity->moderation_information->target_id) {
182 183 184 185 186 187 188
    /** @var \Drupal\workbench_moderation\StateTransitionValidation $transition_validation */
    $transition_validation = \Drupal::service('workbench_moderation.state_transition_validation');

    return $transition_validation->getValidTransitionTargets($entity, $account)
      ? AccessResult::neutral()
      : AccessResult::forbidden();
  }
189
}
190 191 192 193 194 195 196 197 198 199 200

/**
 * Implements hook_theme().
 */
function workbench_moderation_theme($existing, $type, $theme, $path) {
  $themes['entity_moderation_form'] = [
    'render element' => 'form',
  ];

  return $themes;
}
Crell's avatar
Crell committed
201

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
/**
 * Implements hook_action_info_alter().
 */
function workbench_moderation_action_info_alter(&$definitions) {

  // The publish/unpublish actions are not valid on moderated entities. So swap
  // their implementations out for alternates that will become a no-op on a
  // moderated node. If another module has already swapped out those classes,
  // though, we'll be polite and do nothing.
  if (isset($definitions['node_publish_action']['class']) && $definitions['node_publish_action']['class'] == PublishNode::class) {
    $definitions['node_publish_action']['class'] = ModerationOptOutPublishNode::class;
  }
  if (isset($definitions['node_unpublish_action']['class']) && $definitions['node_unpublish_action']['class'] == UnpublishNode::class) {
    $definitions['node_unpublish_action']['class'] = ModerationOptOutUnpublishNode::class;
  }
217 218 219 220 221 222
  if (isset($definitions['entity:publish_action:node']['class']) && $definitions['entity:publish_action:node']['class'] == PublishAction::class) {
    $definitions['entity:publish_action:node']['class'] = ModerationOptOutPublishNode::class;
  }
  if (isset($definitions['entity:unpublish_action:node']['class']) && $definitions['entity:unpublish_action:node']['class'] == UnpublishAction::class) {
    $definitions['entity:publish_action:node']['class'] = ModerationOptOutUnpublishNode::class;
  }
223 224
}

Crell's avatar
Crell committed
225 226
/**
 * Implements hook_views_data_alter().
227 228
 *
 * @todo Use \Drupal\workbench_moderation\ViewsData
Crell's avatar
Crell committed
229 230
 */
function workbench_moderation_views_data_alter(array &$data) {
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246

  /** @var \Drupal\workbench_moderation\ModerationInformationInterface $mod_info */
  $mod_info = \Drupal::service('workbench_moderation.moderation_information');

  /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $etm */
  $etm = \Drupal::service('entity_type.manager');

  $revisionable_types = $mod_info->selectRevisionableEntities($etm->getDefinitions());

  foreach ($revisionable_types as $type) {
    $data[$type->getRevisionTable()]['latest_revision'] = [
      'title' => t('Is Latest Revision'),
      'help' => t('Restrict the view to only revisions that are the latest revision of their entity.'),
      'filter' => ['id' => 'latest_revision'],
    ];
  }
Crell's avatar
Crell committed
247
}