cached_moderation_state-1.0.0-alpha2/cached_moderation_state.module
cached_moderation_state.module
<?php
/**
* @file
* Hook implementations for this module.
*
* Copyright (C) 2022 Library Solutions, LLC (et al.).
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
use Drupal\cached_moderation_state\HiddenFieldConfig;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\RevisionableInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\field\Entity\FieldConfig;
/**
* Implements hook_entity_bundle_field_info_alter().
*
* Hides the 'cached_moderation_state' field in the Field UI.
*/
function cached_moderation_state_entity_bundle_field_info_alter(&$fields = []) {
// Ensure that this function was supplied an iterable before continuing.
// @see https://www.drupal.org/project/drupal/issues/2346347
if (!\is_iterable($fields)) {
return;
}
// At the time of writing, and in all versions of Drupal with which this
// module is currently compatible, FieldConfig is a child of EntityBase, which
// in turn provides EntityBase::__construct() and EntityInterface::toArray().
//
// This module consumes these methods for the purpose of switching the
// instance type of field configuration entities that we want to hide from
// Drupal's Field UI (see further below).
//
// By checking that FieldConfig implements EntityBase, we can reliably
// serialize and unserialize fields to change their instance type.
if (!\is_subclass_of(FieldConfig::class, EntityBase::class)) {
return;
}
// We also need FieldConfig to implement FieldDefinitionInterface so that we
// can safely consume FieldDefinitionInterface::getType().
if (!\is_subclass_of(FieldConfig::class, FieldDefinitionInterface::class)) {
return;
}
foreach ($fields as &$field) {
// Ensure that this field is a proper FieldConfig instance; not simply an
// instance of a descendant class. This check ensures that we can safely
// avoid lateral polymorphism when switching this field's instance type,
// which could adversely affect functionality.
if (!\is_object($field) || \get_class($field) !== FieldConfig::class) {
continue;
}
if ($field instanceof FieldConfig && $field->getType() === 'cached_moderation_state') {
// NOTE: We intentionally use the raw constructor here instead of
// EntityInterface::create() since the latter won't construct a
// HiddenFieldConfig as intended.
$field = new HiddenFieldConfig($field->toArray(), $field->getEntityTypeId());
}
}
}
/**
* Implements hook_entity_create().
*
* Ensures that all entities are created with a 'cached_moderation_state' item.
*/
function cached_moderation_state_entity_create(EntityInterface $entity) {
if ($entity instanceof FieldableEntityInterface && $entity->hasField('cached_moderation_state')) {
if (!$entity->cached_moderation_state->first()) {
$entity->cached_moderation_state->appendItem();
}
}
}
/**
* Implements hook_entity_field_access().
*
* Forbids access to 'cached_moderation_state' on the premise that it should
* only be accessed programmatically.
*/
function cached_moderation_state_entity_field_access($operation, FieldDefinitionInterface $field_definition) {
if ($field_definition->getType() === 'cached_moderation_state') {
return AccessResult::forbidden('This field can only be accessed programmatically.');
}
return AccessResult::neutral();
}
/**
* Implements hook_entity_load().
*
* Ensures that all loaded entities have a 'cached_moderation_state' item.
*/
function cached_moderation_state_entity_load(array $entities) {
foreach ($entities as $entity) {
if ($entity instanceof EntityInterface) {
// Invoke our implementation of hook_entity_create() for this entity.
\cached_moderation_state_entity_create($entity);
}
}
}
/**
* Implements hook_entity_presave().
*
* Prevents the creation of revisions during a batch update.
*/
function cached_moderation_state_entity_presave(EntityInterface $entity) {
/** @var \Drupal\cached_moderation_state\BatchUpdateHandlerInterface */
$batch_update_handler = \Drupal::service('cached_moderation_state.batch_update_handler');
if ($batch_update_handler->isEntityUpdateInProgress()) {
// Unset the original field value to allow updating non-default revisions.
// @see https://www.drupal.org/project/drupal/issues/2859042
unset($entity->original->cached_moderation_state);
if ($entity instanceof RevisionableInterface && $entity->getEntityType()->isRevisionable()) {
// Prevent the creation of new revisions during batch update.
$entity->setNewRevision(FALSE);
}
}
}
/**
* Implements hook_ENTITY_TYPE_insert() for 'workflow'.
*
* Adds or removes the 'cached_moderation_state' field where necessary.
*/
function cached_moderation_state_workflow_insert() {
/** @var \Drupal\cached_moderation_state\FieldConfigHandlerInterface */
$field_config_handler = \Drupal::service('cached_moderation_state.field_config_handler');
$field_config_handler->sync();
}
/**
* Implements hook_ENTITY_TYPE_update() for 'workflow'.
*
* Adds or removes the 'cached_moderation_state' field where necessary.
*/
function cached_moderation_state_workflow_update() {
/** @var \Drupal\cached_moderation_state\FieldConfigHandlerInterface */
$field_config_handler = \Drupal::service('cached_moderation_state.field_config_handler');
$field_config_handler->sync();
}
