You are here

abstract class ConfigEntityRevisionsControllerBase in Config Entity Revisions 8

Same name and namespace in other branches
  1. 8.2 src/ConfigEntityRevisionsControllerBase.php \Drupal\config_entity_revisions\ConfigEntityRevisionsControllerBase
  2. 1.x src/ConfigEntityRevisionsControllerBase.php \Drupal\config_entity_revisions\ConfigEntityRevisionsControllerBase

Controller to make library functions available to various consumers.

Hierarchy

Expanded class hierarchy of ConfigEntityRevisionsControllerBase

2 files declare their use of ConfigEntityRevisionsControllerBase
ViewsRevisionsController.php in modules/views_revisions/src/Controller/ViewsRevisionsController.php
WebformRevisionsController.php in modules/webform_revisions/src/Controller/WebformRevisionsController.php

File

src/ConfigEntityRevisionsControllerBase.php, line 22

Namespace

Drupal\config_entity_revisions
View source
abstract class ConfigEntityRevisionsControllerBase extends ControllerBase implements ConfigEntityRevisionsControllerInterface {

  /**
   * The renderer service.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * Wrapper object for simple configuration from diff.settings.yml.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $config;

  /**
   * Wrapper object for simple configuration from diff.settings.yml.
   *
   * @var \Drupal\diff\DiffEntityComparison;
   */
  protected $entityComparison;

  /**
   * Serialiser service.
   *
   * @var Serializer;
   */
  protected $serialiser;

  /**
   * Container instance.
   *
   * @var ContainerInterface
   */
  protected $container;

  /**
   * Date formatter service.
   *
   * @var DateFormatterInterface
   */
  protected $dateFormatter;

  /**
   * The database connection.
   *
   * @var Connection
   */
  protected $connection;

  /**
   * Constructs a ConfigEntityRevisionsController object.
   *
   * @param ContainerInterface $container
   *   The container interface object.
   * @param DateFormatterInterface $date_formatter
   *   The date formatter service.
   * @param RendererInterface $renderer
   *   The renderer service.
   * @param ImmutableConfig $config
   *   The configuration service.
   * @param DiffEntityComparison $entity_comparison
   *   The diff entity comparison service.
   * @param EntityTypeManager $entity_type_manager
   *   The entity type manager.
   * @param AccountProxyInterface $current_user
   *   The current user.
   * @param Serializer $serialiser
   *   The serialiser service.
   * @param Connection $connection
   *   The database connection.
   */
  public function __construct(ContainerInterface $container, DateFormatterInterface $date_formatter, RendererInterface $renderer, ImmutableConfig $config, DiffEntityComparison $entity_comparison, EntityTypeManager $entity_type_manager, AccountProxyInterface $current_user, Serializer $serialiser, Connection $connection) {
    $this->container = $container;
    $this->dateFormatter = $date_formatter;
    $this->renderer = $renderer;
    $this->config = $config;
    $this->entityComparison = $entity_comparison;
    $this->entityTypeManager = $entity_type_manager;
    $this->currentUser = $current_user;
    $this->serialiser = $serialiser;
    $this->connection = $connection;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container, $container
      ->get('date.formatter'), $container
      ->get('renderer'), $container
      ->get('config.factory')
      ->get('diff.settings'), $container
      ->get('diff.entity_comparison'), $container
      ->get('entity_type.manager'), $container
      ->get('current_user'), $container
      ->get('serializer'), $container
      ->get('database'));
  }

  /**
   * Create an initial revision record.
   *
   * @param ConfigEntityRevisionsInterface $config_entity
   *   The configuration entity.
   *
   * @return ContentEntityInterface|NULL
   *   The content entity created.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function createInitialRevision(ConfigEntityRevisionsInterface $config_entity) {
    $contentID = $config_entity
      ->getContentEntityID();

    // Already created.
    if ($contentID) {
      return NULL;
    }

    /**
     * Make a content revisions entity using either the previous version of
     * the config entity or (failing that) the current version.
     * We're doing this here rather than in the update hook because we want
     * to save the reference to the entity config entity version that is being
     * saved now.
     */

    /* @var $originalEntity ConfigEntityInterface */
    $originalEntity = $config_entity
      ->configEntityStorage()
      ->load($config_entity
      ->id());
    $source = $originalEntity ? $originalEntity : $config_entity;
    $bundle_type = $config_entity
      ->getEntityTypeId() . "_revisions";
    $user_id = $this->container
      ->get('current_user')
      ->id();
    $request_time = $this->container
      ->get('datetime.time')
      ->getRequestTime();

    /* @var $contentEntity ContentEntityInterface */
    $contentEntity = $config_entity
      ->contentEntityStorage()
      ->create([
      'form' => $source
        ->get('uuid'),
      'configuration' => $this->serialiser
        ->serialize($source, 'json'),
      'type' => $bundle_type,
    ]);

    // Set revision info.
    $contentEntity
      ->setNewRevision(TRUE);
    $contentEntity->revision_log = 'Original revision';
    $contentEntity
      ->setRevisionCreationTime($request_time);
    $contentEntity
      ->setRevisionUserId($user_id);
    $contentEntity->moderation_state->value = 'draft';
    $contentEntity
      ->save();
    $contentID = $contentEntity
      ->id();
    $config_entity
      ->setContentEntityID($contentID);
    $config_entity
      ->save();
    return $contentEntity;
  }

  /**
   * Create revision when a new config entity version is saved.
   *
   * @param ConfigEntityRevisionsInterface $config_entity
   *   The configuration entity.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function createUpdateRevision(ConfigEntityRevisionsInterface $config_entity) {

    /* @var $revisionsEntity \Drupal\config_entity_revisions\ConfigEntityRevisionsEntityInterface */
    $revisionsEntity = NULL;
    $previous_state = FALSE;
    if (!empty($config_entity
      ->getRevisionId())) {
      $revisionsEntity = $config_entity
        ->contentEntityStorage()
        ->loadRevision($config_entity
        ->getRevisionID());
      $previous_state = $revisionsEntity->moderation_state->value;
    }
    else {
      $contentID = $config_entity
        ->getContentEntityID();
      if (is_null($contentID)) {

        // No related content entity yet.
        return;
      }
      $revisionsEntity = $config_entity
        ->contentEntityStorage()
        ->load($contentID);
    }
    $revisionsEntity
      ->set('configuration', $this->serialiser
      ->serialize($config_entity, 'json'));
    $revisionsEntity
      ->setRevisionUserId($this->currentUser
      ->id());
    $revisionsEntity
      ->setRevisionCreationTime($this->container
      ->get('datetime.time')
      ->getRequestTime());
    $new_message = $config_entity
      ->get('revision_log_message')[0]['value'];
    $new_revision = $config_entity
      ->get('revision');
    $moderation_state = is_null($config_entity
      ->get('moderation_state')) ? null : $config_entity
      ->get('moderation_state')[0]['value'];
    $published = NULL;
    if (!is_null($moderation_state)) {
      $published = $moderation_state == 'published';
    }
    if (is_null($moderation_state) && is_null($new_revision)) {
      $new_revision = FALSE;
    }
    if (!is_null($new_message)) {
      $revisionsEntity
        ->setRevisionLogMessage($config_entity
        ->get('revision_log_message')[0]['value']);
    }
    $revisionsEntity
      ->setNewRevision($new_revision);
    if (!is_null($moderation_state)) {
      $revisionsEntity->moderation_state = $moderation_state;
    }
    if (!is_null($published)) {
      if ($published) {
        $revisionsEntity
          ->setPublished();
      }
      else {
        $revisionsEntity
          ->setUnpublished();
      }
      $revisionsEntity
        ->isDefaultRevision($published);
    }
    $revisionsEntity
      ->save();
    if (($previous_state == 'published') !== $published) {

      // Modify another revision to be published and default if possible.
      $this
        ->resetDefaultRevision($revisionsEntity);
    }
  }

  /**
   * Make default the most recently published revision or the most recent
   * revision.
   *
   * This is needed because content_moderation has a concept of a default
   * revision, which this module doesn't really care about, but which will
   * cause problems if we attempt to delete a revision that's marked as the
   * default.
   *
   * @param ContentEntityInterface $content_entity
   *   The content (revisions) entity.
   */
  public function resetDefaultRevision(ContentEntityInterface $content_entity) {
    $content_entity_id = $content_entity
      ->id();
    $revisions = $this->connection
      ->select("config_entity_revisions_revision", 'c')
      ->fields('c', [
      'revision',
      'revision_default',
      'published',
    ])
      ->condition('id', $content_entity_id)
      ->orderBy('revision', 'DESC')
      ->execute()
      ->fetchAllAssoc('revision');
    $first_published = NULL;
    $first_revision = NULL;
    $remove_default = [];
    foreach ($revisions as $revision) {
      if (!$first_revision) {
        $first_revision = $revision;
      }
      if ($revision->published && !$first_published) {
        $first_published = $revision;
      }
      if ($revision->revision_default) {
        $remove_default[$revision->revision] = 1;
      }
    }
    $default_revision = $first_published ?: $first_revision;
    if ($default_revision) {
      unset($remove_default[$default_revision->revision]);
    }
    if (!empty($remove_default)) {
      $this->connection
        ->update("config_entity_revisions_revision")
        ->condition('revision', array_keys($remove_default), 'IN')
        ->fields([
        'revision_default' => 0,
      ])
        ->execute();
    }
    if ($default_revision) {
      if (!$default_revision->revision_default) {
        $this->connection
          ->update("config_entity_revisions_revision")
          ->condition('revision', $default_revision->revision)
          ->fields([
          'revision_default' => 1,
        ])
          ->execute();
      }
      $this->connection
        ->update("config_entity_revisions")
        ->condition('id', $content_entity_id)
        ->fields([
        'revision' => $default_revision->revision,
      ])
        ->execute();
    }
  }

  /**
   * Get a list of revision IDs for a content entity.
   */
  public function getRevisionIds($content_entity_id) {
    $revisions = $this->connection
      ->select("config_entity_revisions_revision", 'c')
      ->fields('c', [
      'revision',
    ])
      ->condition('id', $content_entity_id)
      ->execute()
      ->fetchCol();
    return $revisions;
  }

  /**
   * Delete a single revision.
   *
   * @param ContentEntityInterface $revision
   *   The revision to be deleted.
   */
  public function deleteRevision($revision) {
    $was_default = $revision
      ->isDefaultRevision();
    $revisions = $this
      ->getRevisionIds($revision
      ->id());
    if ($was_default) {

      // Change the default to the next newer (if we're deleting the default,
      // there must be no published revisions so it doesn't matter which we
      // choose. Ensure revision_default isn't set on our revision in
      // config_entity_revisions_revision - $was_default can return FALSE
      // even when that value is 1, and that will cause the content moderation
      // module (which does look at that field) to throw an exception.
      $this->connection
        ->update("config_entity_revisions_revision")
        ->condition('id', $revision
        ->id())
        ->fields([
        'revision_default' => 0,
      ])
        ->execute();
      $revision_to_use = $revisions[0] == $this->revision
        ->getRevisionId() ? $revisions[1] : $revisions[0];
      $new_default = $this->configEntityRevisionsStorage
        ->loadRevision($revision_to_use);
      $new_default
        ->enforceIsNew(FALSE);
      $new_default
        ->isDefaultRevision(TRUE);
      $new_default
        ->save();
    }
    $this->entityTypeManager
      ->getStorage('config_entity_revisions')
      ->deleteRevision($revision
      ->getRevisionId());
  }

  /**
   * Delete revisions when a config entity is deleted.
   *
   * @param ConfigEntityRevisionsInterface $config_entity
   *   The configuration entity being deleted.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  public function deleteRevisions(ConfigEntityRevisionsInterface $config_entity) {
    $contentEntity = $config_entity
      ->getContentEntity();
    if ($contentEntity) {
      $config_entity
        ->contentEntityStorage()
        ->delete([
        $contentEntity,
      ]);
    }
  }

  /**
   * Load a particular revision of a config entity.
   *
   * @param int $revision
   *   The revision ID to load.
   * @param mixed $entity
   *   The entity type to load.
   *
   * @return mixed
   *   The loaded revision or NULL.
   */
  public function loadConfigEntityRevision($revision = NULL, $entity = '') {
    $config_entity_name = $this
      ->config_entity_name();
    if (!$entity) {
      try {
        $match = \Drupal::service('router')
          ->matchRequest(\Drupal::request());
      } catch (\Exception $exception) {
        $match = [];
      }
      $entity = isset($match[$config_entity_name]) ? $match[$config_entity_name] : NULL;
    }
    if (is_string($entity)) {
      $entity = $this->entityTypeManager
        ->getStorage($config_entity_name)
        ->load($entity);
    }
    if ($revision) {
      $revisionsEntity = $this->entityTypeManager
        ->getStorage('config_entity_revisions')
        ->loadRevision($revision);
      $entity = \Drupal::getContainer()
        ->get('serializer')
        ->deserialize($revisionsEntity
        ->get('configuration')->value, get_class($entity), 'json');

      // The result of serialising and then deserialising is not an exact
      // copy of the original. This causes problems downstream if we don't fix
      // a few attributes here.
      $entity
        ->set('settingsOriginal', $entity
        ->get('settings'));
      $entity
        ->set('enforceIsNew', FALSE);

      // Record the revision ID in the config entity so we can quickly and
      // easily access the revision record if needed (eg for edit form revision
      // message).
      $entity
        ->updateLoadedRevisionId($revisionsEntity
        ->getRevisionId());
    }
    return $entity;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ConfigEntityRevisionsControllerBase::$config protected property Wrapper object for simple configuration from diff.settings.yml.
ConfigEntityRevisionsControllerBase::$connection protected property The database connection.
ConfigEntityRevisionsControllerBase::$container protected property Container instance.
ConfigEntityRevisionsControllerBase::$dateFormatter protected property Date formatter service.
ConfigEntityRevisionsControllerBase::$entityComparison protected property Wrapper object for simple configuration from diff.settings.yml.
ConfigEntityRevisionsControllerBase::$renderer protected property The renderer service.
ConfigEntityRevisionsControllerBase::$serialiser protected property Serialiser service.
ConfigEntityRevisionsControllerBase::create public static function Instantiates a new instance of this class. Overrides ControllerBase::create
ConfigEntityRevisionsControllerBase::createInitialRevision public function Create an initial revision record. Overrides ConfigEntityRevisionsControllerInterface::createInitialRevision
ConfigEntityRevisionsControllerBase::createUpdateRevision public function Create revision when a new config entity version is saved. Overrides ConfigEntityRevisionsControllerInterface::createUpdateRevision
ConfigEntityRevisionsControllerBase::deleteRevision public function Delete a single revision.
ConfigEntityRevisionsControllerBase::deleteRevisions public function Delete revisions when a config entity is deleted. Overrides ConfigEntityRevisionsControllerInterface::deleteRevisions
ConfigEntityRevisionsControllerBase::getRevisionIds public function Get a list of revision IDs for a content entity.
ConfigEntityRevisionsControllerBase::loadConfigEntityRevision public function Load a particular revision of a config entity.
ConfigEntityRevisionsControllerBase::resetDefaultRevision public function Make default the most recently published revision or the most recent revision.
ConfigEntityRevisionsControllerBase::__construct public function Constructs a ConfigEntityRevisionsController object. Overrides ConfigEntityRevisionsControllerInterface::__construct
ConfigEntityRevisionsControllerInterface::revisionShowTitle public function Default implementation providing a title for a rendered revision. 2
ControllerBase::$configFactory protected property The configuration factory.
ControllerBase::$currentUser protected property The current user service. 1
ControllerBase::$entityFormBuilder protected property The entity form builder.
ControllerBase::$entityManager protected property The entity manager.
ControllerBase::$entityTypeManager protected property The entity type manager.
ControllerBase::$formBuilder protected property The form builder. 2
ControllerBase::$keyValue protected property The key-value storage. 1
ControllerBase::$languageManager protected property The language manager. 1
ControllerBase::$moduleHandler protected property The module handler. 2
ControllerBase::$stateService protected property The state service.
ControllerBase::cache protected function Returns the requested cache bin.
ControllerBase::config protected function Retrieves a configuration object.
ControllerBase::container private function Returns the service container.
ControllerBase::currentUser protected function Returns the current user. 1
ControllerBase::entityFormBuilder protected function Retrieves the entity form builder.
ControllerBase::entityManager Deprecated protected function Retrieves the entity manager service.
ControllerBase::entityTypeManager protected function Retrieves the entity type manager.
ControllerBase::formBuilder protected function Returns the form builder service. 2
ControllerBase::keyValue protected function Returns a key/value storage collection. 1
ControllerBase::languageManager protected function Returns the language manager service. 1
ControllerBase::moduleHandler protected function Returns the module handler. 2
ControllerBase::redirect protected function Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait::redirect
ControllerBase::state protected function Returns the state storage service.
LinkGeneratorTrait::$linkGenerator protected property The link generator. 1
LinkGeneratorTrait::getLinkGenerator Deprecated protected function Returns the link generator.
LinkGeneratorTrait::l Deprecated protected function Renders a link to a route given a route name and its parameters.
LinkGeneratorTrait::setLinkGenerator Deprecated public function Sets the link generator service.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
UrlGeneratorTrait::$urlGenerator protected property The url generator.
UrlGeneratorTrait::getUrlGenerator Deprecated protected function Returns the URL generator service.
UrlGeneratorTrait::setUrlGenerator Deprecated public function Sets the URL generator service.
UrlGeneratorTrait::url Deprecated protected function Generates a URL or path for a specific route based on the given parameters.