multiversion-8.x-1.0-beta34/multiversion.module
multiversion.module
<?php
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Utility\Error;
use Drupal\multiversion\Entity\Storage\ContentEntityStorageInterface;
use Drupal\multiversion\Entity\WorkspaceInterface;
use Drupal\multiversion\MultiversionFieldItemList;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\views\ViewExecutable;
use Drupal\Core\Entity\EntityInterface;
use Drupal\multiversion\Entity\Workspace;
/**
* Implements hook_module_implements_alter().
*/
function multiversion_module_implements_alter(&$implementations, $hook) {
if ($hook == 'entity_type_alter') {
$group = $implementations['multiversion'];
unset($implementations['multiversion']);
$implementations = ['multiversion' => $group] + $implementations;
}
if ($hook == 'field_info_alter') {
$group = $implementations['multiversion'];
unset($implementations['multiversion']);
$implementations['multiversion'] = $group;
}
}
/**
* Implements hook_entity_type_alter().
*
* @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
*/
function multiversion_entity_type_alter(array &$entity_types) {
/** @var \Drupal\multiversion\MultiversionManagerInterface $manager */
$manager = \Drupal::service('multiversion.manager');
foreach ($entity_types as $entity_type) {
if ($manager->allowToAlter($entity_type)) {
// Make all content entity types revisionable.
if (!$entity_type->isRevisionable()) {
// We only need to set the revision key to make an entity type
// revisionable. The table names will be handled by the storage class.
// @see \Drupal\Core\Entity\Sql\SqlContentEntityStorage::initTableLayout
$keys = $entity_type->getKeys();
$keys['revision'] = 'revision_id';
$entity_type->set('entity_keys', $keys);
if ($entity_type->getRevisionTable() === null) {
$entity_type->set('revision_table', $entity_type->id() . '_revision');
}
if ($entity_type->getRevisionDataTable() === null) {
$entity_type->set('revision_data_table', $entity_type->id() . '_field_revision');
}
}
$namespace = 'Drupal\multiversion\Entity\Storage\Sql';
$original_storage_class = $entity_type->getHandlerClass('storage');
$entity_type->setHandlerClass('original_storage', $original_storage_class);
switch ($entity_type->id()) {
case 'node':
$entity_type->setHandlerClass('storage', "$namespace\\NodeStorage");
break;
case 'taxonomy_term':
$entity_type->setHandlerClass('storage', "$namespace\\TermStorage");
break;
case 'comment':
$entity_type->setHandlerClass('storage', "$namespace\\CommentStorage");
break;
case 'menu_link_content':
$entity_type->setClass('Drupal\multiversion\Entity\MenuLinkContent');
$entity_type->setHandlerClass('storage', "$namespace\\MenuLinkContentStorage");
break;
case 'file':
$entity_type->setHandlerClass('storage', "$namespace\\FileStorage");
break;
case 'media':
$entity_type->setHandlerClass('storage', "$namespace\\MediaStorage");
break;
case 'paragraph':
$entity_type->setClass('Drupal\multiversion\Entity\Paragraph');
$entity_type->setHandlerClass('storage', "$namespace\\ContentEntityStorage");
break;
case 'poll':
$entity_type->setHandlerClass('storage', "$namespace\\PollStorage");
break;
case 'crop':
$entity_type->setHandlerClass('storage', "$namespace\\CropStorage");
break;
case 'redirect':
$entity_type->setHandlerClass('storage_schema', 'Drupal\multiversion\Redirect\RedirectStorageSchema');
if (in_array($original_storage_class, [NULL, 'Drupal\Core\Entity\Sql\SqlContentEntityStorage'])) {
$entity_type->setHandlerClass('storage', "$namespace\\ContentEntityStorage");
}
break;
default:
// We can only override the storage handler for entity types we know
// what to expect of.
if (in_array($original_storage_class, [NULL, 'Drupal\Core\Entity\Sql\SqlContentEntityStorage'])) {
$entity_type->setHandlerClass('storage', "$namespace\\ContentEntityStorage");
}
break;
}
}
}
if (isset($entity_types['block_content']) && $manager->allowToAlter($entity_types['block_content'])) {
$entity_types['block']->setHandlerClass('storage', 'Drupal\multiversion\Entity\Storage\Sql\BlockStorage');
}
}
/**
* Implements hook_entity_base_field_info().
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* @return \Drupal\Core\Field\BaseFieldDefinition[]
*/
function multiversion_entity_base_field_info(EntityTypeInterface $entity_type) {
/** @var \Drupal\multiversion\MultiversionManagerInterface $manager */
$manager = \Drupal::service('multiversion.manager');
if ($manager->allowToAlter($entity_type)) {
$fields = [];
// Get the minor version only from the \Drupal::VERSION string.
$minor_version = substr(\Drupal::VERSION, 0, 3);
// @todo: Alter the entity label field to make it revisionable.
// In some scenarios where's in a state of limbo where we've already
// altered and enabled the entity type but we're given an old entity type
// definition for this hook and we get an empty revision key. However,
// these are always the entity types that Multiversion has enabled revisions
// on, so we can assume the same name of the revision key.
$revision_key = $entity_type->getKey('revision') ?: 'revision_id';
// This will essentially overwrite the revision field definition but also
// ensure that entity types that we enabled revisions for get a revision
// field definition of a type that we expect.
$fields[$revision_key] = BaseFieldDefinition::create('integer')
->setLabel(t('Revision ID'))
->setDescription(t('The local revision ID of the entity.'))
->setReadOnly(TRUE)
->setSetting('unsigned', TRUE);
// Add the revision_default field on 8.5 or higher.
if (version_compare($minor_version, '8.5', '>=')) {
$fields['revision_default'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Default revision'))
->setDescription(t('A flag indicating whether this was a default revision when it was saved.'))
->setStorageRequired(TRUE)
->setTranslatable(FALSE)
->setRevisionable(TRUE)
// We cannot tell whether existing revisions were default or not when
// they were created, but since we did not support creating non-default
// revisions in any core stable UI so far, we default to TRUE.
->setInitialValue(TRUE);
}
// This field shouldn't really be revisionable since all revisions for an
// entity will only ever exist in one and the same workspace. But we mark
// this as revisionable to make the storage query more performance because
// then we don't need to join the data table (which it isn't by default).
if ($entity_type->get('workspace') !== FALSE) {
$fields['workspace'] = BaseFieldDefinition::create('workspace_reference')
->setLabel(t('Workspace reference'))
->setDescription(t('The workspace this entity belongs to.'))
->setSetting('target_type', 'workspace')
->setRevisionable(FALSE)
->setTranslatable(FALSE)
->setCardinality(1)
->setReadOnly(TRUE);
}
$fields['_deleted'] = BaseFieldDefinition::create('boolean')
->setLabel(t('Deleted flag'))
->setDescription(t('Indicates if the entity is flagged as deleted or not.'))
->setRevisionable(TRUE)
->setTranslatable(FALSE)
->setDefaultValue(FALSE)
->setCardinality(1);
$fields['_rev'] = BaseFieldDefinition::create('revision_token')
->setLabel(t('Revision token'))
->setDescription(t('The token for this entity revision.'))
->setRevisionable(TRUE)
->setTranslatable(FALSE)
->setCardinality(1)
->setReadOnly(TRUE);
// Add the 'revision_translation_affected' field if needed. Limit this to
// Drupal version 8.4 and higher.
if (version_compare($minor_version, '8.4', '>=') && $entity_type->isTranslatable()) {
$fields[$entity_type->getKey('revision_translation_affected')] = BaseFieldDefinition::create('boolean')
->setName($entity_type->getKey('revision_translation_affected'))
->setTargetEntityTypeId($entity_type->id())
->setTargetBundle(NULL)
->setLabel(new TranslatableMarkup('Revision translation affected'))
->setDescription(new TranslatableMarkup('Indicates if the last edit of a translation belongs to current revision.'))
->setReadOnly(TRUE)
->setRevisionable(TRUE)
->setTranslatable(TRUE);
}
return $fields;
}
}
/**
* Implements hook_data_type_info_alter().
*/
function multiversion_data_type_info_alter(&$info) {
$info['entity_reference']['class'] = '\Drupal\multiversion\EntityReference';
}
/**
* Implements hook_field_info_alter().
*/
function multiversion_field_info_alter(&$info) {
if (\Drupal::state()->get('multiversion_uninstalling', FALSE)) {
return;
}
$info['uuid']['class'] = '\Drupal\multiversion\Field\UuidItem';
$info['entity_reference']['class'] = '\Drupal\multiversion\EntityReferenceItem';
$info['file']['class'] = '\Drupal\multiversion\FileItem';
$info['image']['class'] = '\Drupal\multiversion\ImageItem';
if (isset($info['entity_reference_revisions'])) {
$info['entity_reference_revisions']['class'] = '\Drupal\multiversion\EntityReferenceRevisionsItem';
}
if (\Drupal::moduleHandler()->moduleExists('pathauto')) {
$info['path']['list_class'] = MultiversionFieldItemList::class;
}
}
/**
* Implements hook_entity_base_field_info_alter().
*
* @param array $fields
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
*/
function multiversion_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
/** @var \Drupal\multiversion\MultiversionManagerInterface $manager */
$manager = \Drupal::service('multiversion.manager');
if ($manager->allowToAlter($entity_type)) {
$exclude_fields = [
$entity_type->getKey('id'),
$entity_type->getKey('revision'),
$entity_type->getKey('uuid'),
$entity_type->getKey('bundle'),
$entity_type->getKey('langcode'),
'workspace',
'_deleted',
'_rev',
];
if ($entity_type->id() == 'comment') {
$exclude_fields[] = 'comment_type';
}
foreach ($fields as $key => $field) {
if (!in_array($key, $exclude_fields)) {
$field->setRevisionable(TRUE);
}
}
}
}
/**
* Implements hook_ENTITY_TYPE_update().
*/
function multiversion_workspace_update(EntityInterface $entity) {
/** @var \Drupal\multiversion\Entity\WorkspaceInterface $entity */
if (!$entity->isPublished() && $entity->original->isPublished()) {
$default_workspace = \Drupal::getContainer()->getParameter('workspace.default');
\Drupal::service('workspace.manager')->setActiveWorkspace(Workspace::load($default_workspace));
}
}
/**
* Implements hook_ENTITY_TYPE_presave().
*/
function multiversion_workspace_presave(EntityInterface $entity) {
if ($entity->isDefaultWorkspace() && !$entity->isPublished() && $entity->original->isPublished()) {
throw new Exception('The default workspace cannot be archived.');
}
}
/**
* Implements hook_ENTITY_TYPE_update().
*/
function multiversion_paragraph_update(EntityInterface $entity) {
// Update the target_revision_id field value for the parent entity if it
// changed (for example when saving a revision after a stub revision during
// replication).
$parent = $entity->getParentEntity();
$entity_revision_parent_field_name = $entity->getEntityType()->get('entity_revision_parent_field_name_field');
if ($parent instanceof ContentEntityInterface &&
!empty($entity->workspace) &&
$entity_revision_parent_field_name &&
!empty($entity->{$entity_revision_parent_field_name}->value) &&
(
$entity->_rev->is_stub ||
(!empty($entity->original) && $entity->original->_rev->is_stub)
)
) {
$parent_field_name = $entity->{$entity_revision_parent_field_name}->value;
$storage = \Drupal::entityTypeManager()->getStorage($parent->getEntityTypeId());
$storage->resetCache([$parent->id()]);
// Load the most recent version of the parent.
$parent = $storage->load($parent->id());
if ($parent && !empty($parent->{$parent_field_name})) {
$save_parent = FALSE;
$values = $parent->{$parent_field_name}->getValue();
$updated_values = [];
foreach ($values as $delta => $value) {
$updated_values[$delta] = $value;
if ($value['target_id'] == $entity->id() && $value['target_revision_id'] != $entity->getRevisionId()) {
$updated_values[$delta]['target_revision_id'] = $entity->getRevisionId();
$save_parent = TRUE;
}
}
if ($save_parent) {
$parent->{$parent_field_name}->setValue($updated_values);
try {
$storage->saveWithoutForcingNewRevision($parent);
$storage->resetCache([$parent->id()]);
}
catch (\Exception $e) {
$details = t('Failed to save parent entity with UUID: %uuid_parent for paragraph entity with UUID: %uuid_paragraph.',
[
'%uuid_parent' => $parent->uuid(),
'%uuid_paragraph' => $entity->uuid(),
]);
\Drupal::logger('Multiversion')->error('%type: @message in %function (line %line of %file). ' . $details, Error::decodeException($e));
}
}
}
}
}
/**
* Implements hook_views_data_alter().
*/
function multiversion_views_data_alter(array &$data) {
foreach ($data as $key => $item) {
// Set standard handler for _rev field.
if (isset($data[$key]['_rev'])) {
$data[$key]['_rev']['field']['id'] = 'standard';
}
if (isset($data[$key]['_deleted'])) {
// Use status = 1 instead of status <> 0 in WHERE statement.
$data[$key]['_deleted']['filter']['use_equal'] = TRUE;
}
// Add a new filter that filters content by current active workspace.
if (isset($data[$key]['workspace'])) {
$data[$key]['current_workspace'] = [
'title' => t('Current workspace'),
'help' => t('Filters content by current active workspace.'),
'filter' => [
'field' => 'workspace',
'id' => 'current_workspace',
'label' => t('Current workspace'),
],
];
// Unset the 'Workspace reference' filter because users are not allowed to
// filter by a specific workspace, other than current active workspace.
// To filter by current active workspace will be used the 'Current workspace'
// filter.
unset($data[$key]['workspace']);
}
}
}
/**
* Implements hook_views_post_execute().
*/
function multiversion_views_post_execute(ViewExecutable $view) {
// Add deleted entities if we have rows for them.
// When we want to get deleted entities using the _deleted field, entities
// should be loaded with
// \Drupal::entityManager()->getTypeStorage($entity_type)->loadDeleted($id) or
// \Drupal::entityManager()->getTypeStorage($entity_type)->loadMultipleDeleted($ids),
// otherwise the _entity field in the view result rows will be null.
$base_field = $view->storage->get('base_field');
$table_info = $view->query->getEntityTableInfo();
$content_type_info = array_column($table_info, 'entity_type');
if (is_array($view->result) && $content_type = reset($content_type_info)) {
$manager = \Drupal::service('multiversion.manager');
$storage = \Drupal::entityTypeManager()->getStorage($content_type);
if ($storage instanceof ContentEntityStorageInterface && $manager->allowToAlter($storage->getEntityType())) {
$ids = [];
foreach ($view->result as $index => $row) {
if (empty($row->_entity) && !empty($row->{$base_field})) {
$ids[$index] = $row->{$base_field};
}
}
$entities = $storage->loadMultipleDeleted($ids);
foreach ($view->result as $index => $row) {
if (empty($row->_entity) && !empty($row->{$base_field}) && isset($entities[$row->{$base_field}])) {
$view->result[$index]->_entity = $entities[$row->{$base_field}];
}
// In all other cases unset rows that don't have a value for _entity key.
elseif (empty($row->_entity)) {
unset($view->result[$index]);
}
}
}
}
}
/**
* Implements hook_views_query_alter().
*
* @param \Drupal\views\ViewExecutable $view
* The view object about to be processed.
* @param QueryPluginBase $query
* The query plugin object for the query.
*/
function multiversion_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
// Add a new filter for default core views, it will filter deleted content.
$views_ids = [
'content',
'frontpage',
'comments_recent',
'content_recent',
'taxonomy_term',
'glossary',
'archive',
'block_content',
'poll_admin',
'poll_list',
'media_library'
];
if (in_array($view->id(), $views_ids)) {
/** @var \Drupal\multiversion\MultiversionManagerInterface $manager */
$manager = \Drupal::service('multiversion.manager');
$entity_type = $view->getBaseEntityType();
if (!$manager->isEnabledEntityType($entity_type)) {
return;
}
$base_table = $view->storage->get('base_table');
$view->query->where[1]['conditions'][] = [
'field' => $base_table . '._deleted',
'value' => FALSE,
'operator' => '=',
];
$view->query->where[1]['conditions'][] = [
'field' => $base_table . '.workspace',
'value' => multiversion_get_active_workspace_id(),
'operator' => '=',
];
}
}
/**
* Implements hook_element_info_alter().
*/
function multiversion_element_info_alter(array &$types) {
foreach ($types as &$type) {
if (!isset($type['#pre_render'])) {
$type['#pre_render'] = [];
}
$type['#pre_render'][] = 'multiversion_element_pre_render';
}
}
/**
* Element pre-render callback.
*/
function multiversion_element_pre_render($element) {
if (isset($element['#cache'])) {
if (!isset($element['#cache']['contexts'])) {
$element['#cache']['contexts'] = [];
}
$element['#cache']['contexts'] = Cache::mergeContexts(
$element['#cache']['contexts'], ['workspace']
);
}
return $element;
}
/**
* Callback for getting the active workspace ID.
*/
function multiversion_get_active_workspace_id() {
return \Drupal::service('multiversion.manager')->getActiveWorkspaceId();
}
/**
* URI callback for the workspace entity type.
*/
function multiversion_workspace_uri(WorkspaceInterface $entity) {
return $entity->id();
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function multiversion_form_node_type_edit_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
// Users don't have the option to disable revisions when using Multiversion.
// @todo: {@link https://www.drupal.org/node/2597393 See if there's a way
// to just disable this particular option.}
unset($form['workflow']['options']['#options']['revision']);
}
/**
* Implements hook_form_alter().
*/
function multiversion_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
if (isset($form['revision']['#group']) && $form['revision']['#group'] == 'revision_information') {
// Users don't have the option to disable revisions when using Multiversion.
$form['revision']['#default_value'] = TRUE;
$form['revision']['#disabled'] = TRUE;
}
}
/**
* Prepares a file destination directory.
*
* If the directory doesn't exist it tries to create it, if the directory is not
* writable it tries to make it writable. In case it can't create the directory
* or make it writable, logs the error message and returns FALSE.
* When the directory exists and it is writable returns TRUE.
*
* @param string $destination
*
* @return bool
*/
function multiversion_prepare_file_destination($destination) {
$dirname = \Drupal::service('file_system')->dirname($destination);
return file_prepare_directory($dirname, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY);
}
/**
* Implements hook_menu_links_discovered_alter().
*/
function multiversion_menu_links_discovered_alter(&$links) {
// Get all custom menu links and set links with the correct ID.
// The ID format now will be 'menu_link_content:ENTITY_UUID:ENTITY_ID' - we
// need to change it because we need new entry in the menu_tree table for the
// same link on different workspaces.
// The old ID format is 'menu_link_content:ENTITY_UUID'.
if (\Drupal::moduleHandler()->moduleExists('menu_link_content')) {
$storage = \Drupal::entityTypeManager()->getStorage('menu_link_content');
if (\Drupal::service('multiversion.manager')->isEnabledEntityType($storage->getEntityType())) {
$workspaces = Workspace::loadMultiple();
foreach ($workspaces as $workspace_id => $workspace) {
$storage->useWorkspace($workspace_id);
$menu_link_content_entities = $storage->loadMultiple();
$new_ids = [];
$links_to_purge = [];
/** @var \Drupal\menu_link_content\MenuLinkContentInterface $menu_link_content */
foreach ($menu_link_content_entities as $menu_link_content) {
// Unset links with old ID format.
$uuid = $menu_link_content->uuid();
$old_id = "menu_link_content:$uuid";
$new_id = "$old_id:" . $menu_link_content->id();
if (isset($links[$old_id])) {
$links_to_purge[] = $old_id;
unset($links[$old_id]);
}
$new_ids[$old_id] = $new_id;
if (!isset($links[$new_id])) {
$links[$new_id] = $menu_link_content->getPluginDefinition();
}
// Set a new plugin class tha will handle new ID format.
$links[$new_id]['class'] = 'Drupal\multiversion\Plugin\Menu\MenuLinkContent';
}
if ($links_to_purge) {
\Drupal::service('menu.tree_storage')->purgeMultiple($links_to_purge);
}
foreach ($links as $id => $link) {
if (!empty($link['parent']) && in_array($link['parent'], array_keys($new_ids))) {
$links[$id]['parent'] = $new_ids[$link['parent']];
}
}
$storage->useWorkspace(NULL);
}
}
}
}
/**
* Implements hook_modules_installed().
*/
function multiversion_modules_installed($modules) {
// Enable entity types provided by installed modules and supported by
// Multiversion.
$entity_type_manager = \Drupal::entityTypeManager();
$supported_entity_types = \Drupal::configFactory()
->getEditable('multiversion.settings')
->get('supported_entity_types');
$supported_entity_types = $supported_entity_types ?: [];
$entities_to_enable = [];
foreach ($supported_entity_types as $entity_type_id) {
$entity_type = $entity_type_manager->getDefinition($entity_type_id, FALSE);
if (!empty($entity_type) && in_array($entity_type->getProvider(), $modules)) {
$entities_to_enable[$entity_type_id] = $entity_type;
}
}
if (!empty($entities_to_enable)) {
\Drupal::service('multiversion.manager')->enableEntityTypes($entities_to_enable);
}
}
/**
* Implements hook_search_plugin_alter().
*/
function multiversion_search_plugin_alter(array &$definitions) {
if (isset($definitions['node_search'])) {
$definitions['node_search']['class'] = 'Drupal\multiversion\Entity\Search\NodeSearch';
}
}
/**
* Implements hook_preprocess_HOOK().
*
* Adds the workspace as a class to the body.
*/
function multiversion_preprocess_html(&$variables) {
$active_workspace = \Drupal::service('workspace.manager')
->getActiveWorkspace();
if ($active_workspace && $machine_name = $active_workspace->getMachineName()) {
// Add a new body class with the active workspace.
$variables['attributes']['class'][] = 'workspace-' . $machine_name;
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Alters the 'revision_overview_form' for provided by Diff module.
*/
function multiversion_form_revision_overview_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if (isset($form['node_revisions_table'])) {
foreach ($form['node_revisions_table'] as $key => $revision_info) {
if (empty($revision_info['operations']) || !is_array($revision_info['operations'])) {
continue;
}
if (isset($revision_info['operations']['#links']['delete'])) {
unset($form['node_revisions_table'][$key]['operations']['#links']['delete']);
}
}
}
}
/**
* Add workspace field in url_alias table.
*
* @param bool $install
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
*/
function _multiversion_add_workspace_field_in_url_alias_table($install = FALSE) {
$database = \Drupal::database();
$schema = $database->schema();
$table = 'url_alias';
$field = 'workspace';
if (!$schema->fieldExists($table, $field)) {
$spec = [
'description' => 'The workspace the alias belongs to.',
'type' => 'int',
'unsigned' => TRUE,
'default' => $install ? 1 : 0,
'size' => 'normal',
];
$schema->addField($table, $field, $spec);
}
$table_data = $database->select($table)
->fields($table)
->execute()
->fetchAll();
$entity_type_manager = \Drupal::entityTypeManager();
$entity_type_manager->clearCachedDefinitions();
$entity_ids = [];
foreach ($table_data as $row) {
$row_data = (array) $row;
$source_elements = explode('/', $row_data['source']);
if (!empty($source_elements[1]) && !empty($source_elements[2]) && is_numeric($source_elements[2])) {
if ($entity_type_manager->getDefinition($source_elements[1], FALSE)) {
$entity_ids[$source_elements[1]][$row_data['pid']] = $source_elements[2];
}
}
}
$workspaces = Workspace::loadMultiple();
foreach ($workspaces as $workspace_id => $workspace) {
foreach ($entity_ids as $entity_type_id => $ids) {
$storage = $entity_type_manager->getStorage($entity_type_id);
if ($storage instanceof ContentEntityStorageInterface) {
$storage->useWorkspace($workspace_id);
$entities = $storage->loadMultiple($ids);
$storage->useWorkspace(NULL);
}
if (empty($entities)) {
continue;
}
foreach ($ids as $pid => $entity_id) {
if (in_array($entity_id, array_keys($entities))) {
$database->update($table)
->fields([$field => $workspace_id])
->condition('pid', $pid)
->execute();
}
}
}
}
}
