You are here

abstract class ConfigEntityRevisionsConverterBase in Config Entity Revisions 8.2

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

Parameter converter for upcasting entity IDs to full objects.

This is useful in cases where the dynamic elements of the path can't be auto-determined; for example, if your path refers to multiple of the same type of entity ("example/{node1}/foo/{node2}") or if the path can act on any entity type ("example/{entity_type}/{entity}/foo").

In order to use it you should specify some additional options in your route:


example.route:
  path: foo/{example}
  options:
    parameters:
      example:
        type: entity:node

If you want to have the entity type itself dynamic in the url you can specify it like the following:


example.route:
  path: foo/{entity_type}/{example}
  options:
    parameters:
      example:
        type: entity:{entity_type}

If your route needs to support pending revisions, you can specify the "load_latest_revision" parameter. This will ensure that the latest revision is returned, even if it is not the default one:


example.route:
  path: foo/{example}
  options:
    parameters:
      example:
        type: entity:node
        load_latest_revision: TRUE

When dealing with translatable entities, the "load_latest_revision" flag will make this converter load the latest revision affecting the translation matching the content language for the current request. If none can be found it will fall back to the latest revision. For instance, if an entity has an English default revision (revision 1) and an Italian pending revision (revision 2), "/foo/1" will return the former, while "/it/foo/1" will return the latter.

Hierarchy

Expanded class hierarchy of ConfigEntityRevisionsConverterBase

See also

entities_revisions_translations

3 files declare their use of ConfigEntityRevisionsConverterBase
ContactFormRevisionsConverter.php in modules/contact_form_revisions/src/ParamConverter/ContactFormRevisionsConverter.php
ViewRevisionsConverter.php in modules/view_revisions/src/ParamConverter/ViewRevisionsConverter.php
WebformRevisionsConverter.php in modules/webform_revisions/src/ParamConverter/WebformRevisionsConverter.php

File

src/ConfigEntityRevisionsConverterBase.php, line 65

Namespace

Drupal\config_entity_revisions
View source
abstract class ConfigEntityRevisionsConverterBase extends AdminPathConfigEntityConverter implements ConfigEntityRevisionsConverterBaseInterface {

  /**
   * Stores the tempstore factory.
   *
   * @var \Drupal\Core\TempStore\SharedTempStoreFactory
   */
  protected $tempStoreFactory;

  /**
   * A prefix for tempstore keys - empty if tempstore is not used.
   */
  protected function tempstorePrefix() {
    return '';
  }

  /**
   * Default implementation of containerFor - the container is the object.
   */
  protected function containerFor($config_entity) {
    return $config_entity;
  }

  /**
   * Constructs a new converter.
   *
   * @param \Drupal\Core\Entity\EntityManagerInterface $entityManager
   *   The entity manager.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   * @param \Drupal\Core\TempStore\SharedTempStoreFactory $tempStoreFactory
   *   The factory for the temp store object.
   * @param \Drupal\Core\Routing\AdminContext $adminContext
   *   The admin context.
   */
  public function __construct(EntityManagerInterface $entityManager, ConfigFactoryInterface $configFactory, SharedTempStoreFactory $tempStoreFactory = NULL, AdminContext $adminContext = NULL) {

    // The config factory and admin context are new arguments due to changing
    // the parent. Avoid an error on updated sites by falling back to getting
    // them from the container.
    // @todo Remove in 8.2.x in https://www.drupal.org/node/2674328.
    if (!$configFactory) {
      $configFactory = \Drupal::configFactory();
    }
    if (!$adminContext) {
      $adminContext = \Drupal::service('router.admin_context');
    }
    parent::__construct($entityManager, $configFactory, $adminContext);
    $this->tempStoreFactory = $tempStoreFactory;
  }

  /**
   * {@inheritdoc}
   */
  public function convert($value, $definition, $name, array $defaults) {

    /* @var $config_entity \Drupal\config_entity_revisions\ConfigEntityRevisionsConfigEntityInterface */
    if (!($config_entity = parent::convert($value, $definition, $name, $defaults))) {
      return;
    }

    // Get the temp store for this variable if it needs one. Attempt to load the
    // view from the temp store, synchronize its status with the existing view,
    // and store the lock metadata.
    $tempstorePrefix = $this
      ->tempstorePrefix();
    $temp_store = $tempstorePrefix ? $this->tempStoreFactory
      ->get($tempstorePrefix) : NULL;
    if (!$config_entity) {
      return NULL;
    }

    /* @var $revisionEntity ConfigEntityRevisionsConfigEntityInterface */
    $revisionEntity = NULL;

    // Get the config_entity_revisions entity, if one exists.
    $revisionsID = $config_entity
      ->getContentEntityId();

    /* @var $content_entity_storage ConfigEntityRevisionsRevisionStorageHandlerInterface */
    $content_entity_storage = $this->entityManager
      ->getStorage('config_entity_revisions');
    if (!$revisionsID) {
      $revisionsID = $content_entity_storage
        ->createInitialRevision($config_entity);
    }
    $content_entity_storage
      ->setConfigEntity($config_entity);

    // If a specific revision is provided or implied by a submission ID, use
    // it.
    $specific_revision = FALSE;
    if (!empty($defaults['revision_id']) && $defaults['revision_id'] != 'default') {
      $specific_revision = $defaults['revision_id'];
    }
    elseif ($config_entity
      ->hasOwnContent() && !empty($defaults[$config_entity
      ->revisionsEntityName()])) {

      // Load the content entity and get the config entity revision from it
      // (if any).
      $content_storage = $this->entityManager
        ->getStorage($config_entity
        ->revisionsEntityName());
      $content = $content_storage
        ->load($defaults[$config_entity
        ->contentParameterName()]);
      if ($content->{$config_entity
        ->contentParentReferenceField()}) {
        $specific_revision = $content->{$config_entity
          ->contentParentReferenceField()}->target_id;
      }
    }

    // If no specific revision has been given, check to see whether we should
    // use the latest revision or the latest published revision.
    if ($specific_revision) {
      $revisionEntity = $content_entity_storage
        ->loadRevision($specific_revision);
    }
    elseif (array_key_exists('load_latest_revision', $definition)) {
      $revisionEntity = $content_entity_storage
        ->getLatestRevision();
    }
    else {
      $revisionEntity = $content_entity_storage
        ->getLatestPublishedRevision();

      // If there's no latest published revision and the user has admin
      // permissions, get the latest revision instead.
      if (!$revisionEntity && \Drupal::currentUser()
        ->hasPermission($config_entity
        ->adminPermission()) && is_null($revisionEntity)) {
        $revisionEntity = $content_entity_storage
          ->getLatestRevision();
      }
    }
    if (is_null($revisionEntity)) {
      return NULL;
    }

    // Now that we know the revision ID to use, we can check whether we were
    // already editing it.
    $temp_store_key = $value . '-' . $revisionEntity
      ->getRevisionId();
    if ($temp_store && ($container = $temp_store
      ->get($temp_store_key))) {
      if ($config_entity
        ->status()) {
        $container
          ->enable();
      }
      else {
        $container
          ->disable();
      }
      $container->lock = $temp_store
        ->getMetadata($temp_store_key);
    }
    else {
      if ($revisionEntity) {

        // Otherwise, decorate the existing view for use in the UI.
        $config_entity = $content_entity_storage
          ->getConfigEntity($revisionEntity);
      }
      $container = $this
        ->containerFor($config_entity);
    }
    return $container;
  }

  /**
   * Determines the entity type ID given a route definition and route defaults.
   *
   * @param mixed $definition
   *   The parameter definition provided in the route options.
   * @param string $name
   *   The name of the parameter.
   * @param array $defaults
   *   The route defaults array.
   *
   * @return string
   *   The entity type ID.
   *
   * @throws ParamNotConvertedException
   *   Thrown when the dynamic entity type is not found in the route defaults.
   */
  public function getEntityTypeFromDefaults($definition, $name, array $defaults) {
    $entity_type_id = substr($definition['type'], strlen('entity:'));

    // If the entity type is dynamic, it will be pulled from the route defaults.
    if (strpos($entity_type_id, '{') === 0) {
      $entity_type_slug = substr($entity_type_id, 1, -1);
      if (!isset($defaults[$entity_type_slug])) {
        throw new ParamNotConvertedException(sprintf('The "%s" parameter was not converted because the "%s" parameter is missing', $name, $entity_type_slug));
      }
      $entity_type_id = $defaults[$entity_type_slug];
    }
    return $entity_type_id;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AdminPathConfigEntityConverter::$adminContext protected property The route admin context to determine whether a route is an admin one.
AdminPathConfigEntityConverter::$configFactory protected property The config factory.
AdminPathConfigEntityConverter::applies public function Determines if the converter applies to a specific route and variable. Overrides EntityConverter::applies 1
ConfigEntityRevisionsConverterBase::$tempStoreFactory protected property Stores the tempstore factory.
ConfigEntityRevisionsConverterBase::containerFor protected function Default implementation of containerFor - the container is the object. 1
ConfigEntityRevisionsConverterBase::convert public function Converts path variables to their corresponding objects. Overrides AdminPathConfigEntityConverter::convert
ConfigEntityRevisionsConverterBase::getEntityTypeFromDefaults public function Determines the entity type ID given a route definition and route defaults. Overrides DynamicEntityTypeParamConverterTrait::getEntityTypeFromDefaults
ConfigEntityRevisionsConverterBase::tempstorePrefix protected function A prefix for tempstore keys - empty if tempstore is not used. 1
ConfigEntityRevisionsConverterBase::__construct public function Constructs a new converter. Overrides AdminPathConfigEntityConverter::__construct
DeprecatedServicePropertyTrait::__get public function Allows to access deprecated/removed properties.
EntityConverter::$deprecatedProperties protected property
EntityConverter::$entityRepository protected property Entity repository.
EntityConverter::$entityTypeManager protected property Entity type manager which performs the upcasting in the end.
EntityConverter::getLatestTranslationAffectedRevision Deprecated protected function Returns the latest revision translation of the specified entity.
EntityConverter::languageManager protected function Returns a language manager instance.
EntityConverter::loadRevision Deprecated protected function Loads the specified entity revision.