ConfigEntityRevisionsConfigEntityTrait.php in Config Entity Revisions 8.2
Namespace
Drupal\config_entity_revisionsFile
src/ConfigEntityRevisionsConfigEntityTrait.phpView source
<?php
namespace Drupal\config_entity_revisions;
use Drupal\content_moderation\Plugin\Field\ModerationStateFieldItemList;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\Plugin\DataType\EntityAdapter;
use Drupal\Core\Entity\RevisionableInterface;
use Drupal\Core\TypedData\ListDataDefinition;
/**
* Trait ConfigEntityRevisionsConfigEntityTrait.
*
* @package Drupal\config_entity_revisions
*/
trait ConfigEntityRevisionsConfigEntityTrait {
/**
* The ID of the revision that was loaded.
*
* @var int
*/
public $loadedRevisionId;
/**
* Whether this revision is the default one.
*
* @var boolean
*/
public $isDefaultRevision = FALSE;
/*
* Declare these fields so they're put in the storage object instead of the
* ViewsUI object during entity building in the case of ViewRevisions.
* We can then access them in createUpdateRevision.
*/
/**
* The revision.
*
* @var int
*/
protected $revision;
/**
* The revision_log_message.
*
* @var array
*/
protected $revision_log_message;
/**
* The current moderation state for this revision.
*
* @var \Drupal\content_moderation\Plugin\Field\ModerationStateFieldItemList
*/
public $moderation_state;
/**
* Constructs an Entity object.
*
* @param array $values
* An array of values to set, keyed by property name. If the entity type
* has bundles, the bundle key has to be specified.
* @param string $entity_type
* The type of the entity to create.
*/
public function __construct(array $values, $entity_type) {
parent::__construct($values, $entity_type);
$this->entityTypeManager = \Drupal::service('entity_type.manager');
// Add moderation info field.
$entity_type_info = ConfigEntityRevisionsEntityTypeInfo::create(\Drupal::getContainer());
$moderation_fields = $entity_type_info
->entityExtraFieldInfo();
if (!empty($moderation_fields['config_entity_revisions'][$this
->getBundleName()]) && $this
->getContentEntity()) {
// NB: By feeding the content entity as the parent, we dont need to
// override the ModerationStateFieldItemList class.
$entity_adapter = EntityAdapter::createFromEntity($this
->getContentEntity());
$definition = ListDataDefinition::createFromItemType('field_item:string');
$this->moderation_state = ModerationStateFieldItemList::createInstance($definition, 'moderation_state', $entity_adapter);
}
}
/**
* Restore the entity type manager after deserialisation.
*/
public function __wakeup() {
$this->entityTypeManager = \Drupal::service('entity_type.manager');
}
/**
* The module implementing config entity revisions.
*
* @return string
* The name of the module implementing the API.
*/
public function moduleName() {
return $this->constants['module_name'];
}
/**
* The config entity name.
*
* @return string
* The name of the entity being revisioned.
*/
public function configEntityName() {
return $this->constants['config_entity_name'];
}
/**
* The content entity name in which revisions are being stored.
*
* @return string
* The name of the content entity in which revisions are being stored.
*/
public function revisionsEntityName() {
return $this->constants['revisions_entity_name'];
}
/**
* The bundle name for content entities.
*
* @return string
* The bundle name for content entities in which revisions are being stored.
*/
public function getBundleName() {
return $this->constants['bundle_name'];
}
/**
* The config entity setting name in which content entity ids are stored.
*
* @return string
* The name of the setting.
*/
public function settingName() {
return $this->constants['setting_name'];
}
/**
* The human readable title for this entity.
*
* @return string
* The proper name (displayed to the user) of the module implementing the
* API.
*/
public function title() {
return $this->constants['title'];
}
/**
* Whether this config entity has its own content entities.
*
* (eg Webforms have webform submissions).
*
* @return bool
* Does the config entity have its own content entities?
*/
public function hasOwnContent() {
return $this->constants['has_own_content'];
}
/**
* The name of the content entity type.
*
* @return string
* The name of the content entities that the config entity has.
*/
public function contentEntityType() {
return $this->constants['content_entity_type'];
}
/**
* Get the name of the parameter for this content.
*
* @return string
* The name of the parameter used for this content.
*/
public function contentParameterName() {
return $this->constants['content_parameter_name'];
}
/**
* Get the content's parent reference field.
*
* @return string
* The name of the field referencing the parent.
*/
public function contentParentReferenceField() {
return $this->constants['content_parent_reference_field'];
}
/**
* Return the name of the admin permission for this entity.
*
* @return string
* The name of the admin permission.
*/
public function adminPermission() {
return $this->constants['admin_permission'];
}
/**
* Return whether the entity has a canonical URL.
*
* @return bool
* Whether the entity has a canonical URL.
*/
public function hasCanonicalUrl() {
return $this->constants['has_canonical_url'] ?: FALSE;
}
/**
* Return the preview form ID, if applicable.
*
* @return mixed
* The preview form id, if applicable, or NULL.
*/
public function previewFormId() {
return $this->constants['preview_form_id'] ?: NULL;
}
/**
* Get the revisioned entity - itself by default.
*
* @return \Drupal\Core\Config\Entity\ConfigEntityInterface
* The entity which is revisioned.
*/
public function revisionedEntity() {
return $this;
}
/**
* Set in the configEntity an identifier for the matching content entity.
*
* @param mixed $contentEntityID
* The ID used to match the content entity.
*/
public function setContentEntityId($contentEntityID) {
$this
->setThirdPartySetting($this
->moduleName(), 'contentEntity_id', $contentEntityID);
}
/**
* Get from the configEntity the ID of the matching content entity.
*
* @return int|null
* The ID (if any) of the matching content entity.
*/
public function getContentEntityId() {
return $this
->getThirdPartySetting($this
->moduleName(), 'contentEntity_id');
}
/**
* Gets the revision identifier of the entity.
*
* @return int
* The revision identifier of the entity, or NULL if the entity does not
* have a revision identifier.
*/
public function getRevisionId() {
return $this->loadedRevisionId;
}
/**
* Get the revisions entity storage.
*
* @return \Drupal\Core\Entity\ContentEntityStorageInterface
* The storage for the revisions entity.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function contentEntityStorage() {
return $this->entityTypeManager
->getStorage('config_entity_revisions');
}
/**
* Default revision of revisions entity that matches the config entity.
*
* @return \Drupal\Core\Entity\EntityInterface|null
* The matching entity.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function getContentEntity() {
$contentEntityID = $this
->getContentEntityId();
if (!$contentEntityID) {
return NULL;
}
/* @var $storage \Drupal\Core\Entity\ContentEntityStorageInterface */
$storage = $this
->contentEntityStorage();
// Get the matching revision ID if one is provided.
return $this
->getRevisionId() ? $storage
->loadRevision($this
->getRevisionId()) : $storage
->load($contentEntityID);
}
/**
* Determines whether a new revision should be created on save.
*
* @return bool
* TRUE if a new revision should be created.
*
* @see \Drupal\Core\Entity\EntityInterface::setNewRevision()
*/
public function isNewRevision() {
return $this->newRevision || $this
->getEntityType()
->hasKey('revision') && !$this
->getRevisionId();
}
/**
* Enforces an entity to be saved as a new revision.
*
* @param bool $value
* (optional) Whether a new revision should be saved.
*
* @throws \LogicException
* Thrown if the entity does not support revisions.
*
* @see \Drupal\Core\Entity\EntityInterface::isNewRevision()
*/
public function setNewRevision($value = TRUE) {
if (!$this
->getEntityType()
->hasKey('revision')) {
throw new \LogicException("Entity type {$this->getEntityTypeId()} does not support revisions.");
}
if ($value && !$this->newRevision) {
// When saving a new revision, set any existing revision ID to NULL so as
// to ensure that a new revision will actually be created.
$this
->set($this
->getEntityType()
->getKey('revision'), NULL);
}
elseif (!$value && $this->newRevision) {
// If ::setNewRevision(FALSE) is called after ::setNewRevision(TRUE) we
// have to restore the loaded revision ID.
$this
->set($this
->getEntityType()
->getKey('revision'), $this
->getLoadedRevisionId());
}
$this->newRevision = $value;
}
/**
* Gets the loaded Revision ID of the entity.
*
* @return int
* The loaded Revision identifier of the entity, or NULL if the entity
* does not have a revision identifier.
*/
public function getLoadedRevisionId() {
return $this->loadedRevisionId;
}
/**
* Updates the loaded Revision ID with the revision ID.
*
* This method should not be used, it could unintentionally cause the original
* revision ID property value to be lost.
*
* @return $this
* @internal
*
*/
public function updateLoadedRevisionId() {
$this->loadedRevisionId = $this
->getRevisionId() ?: $this->loadedRevisionId;
return $this;
}
/**
* Checks if this entity is the default revision.
*
* @param bool $new_value
* (optional) A Boolean to (re)set the isDefaultRevision flag.
*
* @return bool
* TRUE if the entity is the default revision, FALSE otherwise. If
* $new_value was passed, the previous value is returned.
*/
public function isDefaultRevision($new_value = NULL) {
$return = $this->isDefaultRevision;
if (isset($new_value)) {
$this->isDefaultRevision = (bool) $new_value;
}
// New entities should always ensure at least one default revision exists,
// creating an entity without a default revision is an invalid state.
return $this
->isNew() || $return;
}
/**
* Checks whether the entity object was a default revision when it was saved.
*
* @return bool
* TRUE if the entity object was a revision, FALSE otherwise.
*/
public function wasDefaultRevision() {
/** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */
$entity_type = $this
->getEntityType();
if (!$entity_type
->isRevisionable()) {
return TRUE;
}
$revision_default_key = $entity_type
->getRevisionMetadataKey('revision_default');
$value = $this
->isNew() || $this
->get($revision_default_key)->value;
return $value;
}
/**
* Checks if this entity is the latest revision.
*
* @return bool
* TRUE if the entity is the latest revision, FALSE otherwise.
*/
public function isLatestRevision() {
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
$storage = $this
->entityTypeManager()
->getStorage($this
->getEntityTypeId());
return $this
->getLoadedRevisionId() == $storage
->getLatestRevisionId($this
->id());
}
/**
* Acts on a revision before it gets saved.
*
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The entity storage object.
* @param \stdClass $record
* The revision object.
*/
public function preSaveRevision(EntityStorageInterface $storage, \stdClass $record) {
}
/**
* {@inheritdoc}
*/
public function set($property_name, $value) {
if ($this instanceof EntityWithPluginCollectionInterface) {
$plugin_collections = $this
->getPluginCollections();
if (isset($plugin_collections[$property_name])) {
// If external code updates the settings, pass it along to the plugin.
$plugin_collections[$property_name]
->setConfiguration($value);
}
}
// Special handling for the moderation state.
if (isset($this->{$property_name}) && $this->{$property_name} instanceof ModerationStateFieldItemList) {
$this->moderation_state
->setValue($value);
$this
->getContentEntity()->moderation_state
->setValue($value);
}
else {
$this->{$property_name} = $value;
}
return $this;
}
/**
* Save an updated version of the entity.
*
* In this case, we only save the entity if this new revision is/will be the
* default revision. In other cases, we're just updating the content revision.
*/
public function save() {
// Configuration entity IDs are strings, and '0' is a valid ID.
$id = $this
->id();
if ($id === NULL || $id === '') {
throw new EntityMalformedException('The entity does not have an ID.');
}
$contentEntityStorage = $this
->contentEntityStorage();
$contentEntityStorage
->setConfigEntity($this);
$next_choice_id = $contentEntityStorage
->getLatestPublishedRevisionOrLatestId($this
->getRevisionId());
$new_moderation_state = $this
->get('moderation_state');
$new_moderation_state = $new_moderation_state ? $new_moderation_state->value : 'published';
// Only save the config entity if this is going to be the default revision
// (ie the last published revision or the last revision if none are
// published).
// Ensure the content entity is always added/updated.
$new_default = $new_moderation_state == 'published' || $this
->getRevisionId() == $next_choice_id;
if ($new_default) {
$result = parent::save($this);
}
else {
// We need to save $latest's entity into the config entity if it has
// changed.
$next_choice_revision = $contentEntityStorage
->loadRevision($next_choice_id);
$next_choice = $contentEntityStorage
->getConfigEntity($next_choice_revision);
$result = $next_choice
->save();
}
// And then also update the content entity for our latest change.
$contentEntityStorage
->createUpdateRevision($this);
return $result;
}
/**
* Gets an array of placeholders for this entity.
*
* Individual entity classes may override this method to add additional
* placeholders if desired. If so, they should be sure to replicate the
* property caching logic.
*
* @param string $rel
* The link relationship type, for example: canonical or edit-form.
*
* @return array
* An array of URI placeholders.
*/
protected function urlRouteParameters($rel) {
$uri_route_parameters = [];
if (!in_array($rel, [
'collection',
'add-page',
'add-form',
], TRUE)) {
// The entity ID is needed as a route parameter.
$uri_route_parameters[$this
->getEntityTypeId()] = $this
->id();
}
if ($rel === 'add-form' && $this
->getEntityType()
->hasKey('bundle')) {
$parameter_name = $this
->getEntityType()
->getBundleEntityType() ?: $this
->getEntityType()
->getKey('bundle');
$uri_route_parameters[$parameter_name] = $this
->bundle();
}
if ($rel === 'revision' && $this instanceof RevisionableInterface) {
$uri_route_parameters[$this
->getEntityTypeId() . '_revision'] = $this
->getRevisionId();
}
if (!is_null($this->loadedRevisionId)) {
$uri_route_parameters += [
'revision_id' => $this->loadedRevisionId,
];
}
return $uri_route_parameters;
}
}
Traits
Name | Description |
---|---|
ConfigEntityRevisionsConfigEntityTrait | Trait ConfigEntityRevisionsConfigEntityTrait. |