diff --git a/core/modules/block_content/block_content.install b/core/modules/block_content/block_content.install index fe4526e41f00749ec3b6ba36285294ef872d532c..a15e06a08dc8a98f73e1ecf94a83c94f5bd837b4 100644 --- a/core/modules/block_content/block_content.install +++ b/core/modules/block_content/block_content.install @@ -9,6 +9,7 @@ use Drupal\Core\Entity\Form\RevisionDeleteForm; use Drupal\Core\Entity\Form\RevisionRevertForm; use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider; +use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\StringTranslation\TranslatableMarkup; /** @@ -63,3 +64,19 @@ function block_content_update_10300(): void { $manager->updateFieldStorageDefinition(\Drupal::service('entity_field.manager') ->getBaseFieldDefinitions('block_content')['reusable']); } + +/** + * Install owner field. + */ +function block_content_update_10301(): TranslatableMarkup { + $entityDefinitionUpdateManager = \Drupal::entityDefinitionUpdateManager(); + $entityType = $entityDefinitionUpdateManager->getEntityType('block_content'); + + $storage_definition = BaseFieldDefinition::create('entity_reference') + ->setLabel(new TranslatableMarkup('User ID')) + ->setSetting('target_type', 'user') + ->setTranslatable($entityType->isTranslatable()); + $entityDefinitionUpdateManager + ->installFieldStorageDefinition('uid', 'block_content', 'block_content', $storage_definition); + return \t('Installed uid field for BlockContent entities.'); +} diff --git a/core/modules/block_content/block_content.post_update.php b/core/modules/block_content/block_content.post_update.php index 3955a7033bd54ebbfb886490539d31750594881e..e318c2280cc68b585269c090e263207a44724676 100644 --- a/core/modules/block_content/block_content.post_update.php +++ b/core/modules/block_content/block_content.post_update.php @@ -7,6 +7,8 @@ use Drupal\block_content\BlockContentTypeInterface; use Drupal\Core\Config\Entity\ConfigEntityUpdater; +use Drupal\Core\Site\Settings; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\user\Entity\Role; use Drupal\views\Entity\View; @@ -92,3 +94,59 @@ function block_content_post_update_revision_type(&$sandbox = NULL) { return TRUE; }); } + +/** + * Set a default author for block content entities. + */ +function block_content_post_update_set_owner(&$sandbox = NULL): TranslatableMarkup { + $blockContentStorage = \Drupal::entityTypeManager() + ->getStorage('block_content'); + + if (!isset($sandbox['total'])) { + $sandbox['total'] = $blockContentStorage + ->getQuery() + ->accessCheck(FALSE) + ->condition('uid', NULL, 'IS NULL') + ->count() + ->execute(); + $sandbox['progress'] = 0; + + // Handle the case of 0 block to process. + if ($sandbox['total'] == 0) { + $sandbox['total'] = 1; + $sandbox['progress'] = 1; + } + } + + $ids = $blockContentStorage + ->getQuery() + ->accessCheck(FALSE) + ->condition('uid', NULL, 'IS NULL') + ->range(0, (int) Settings::get('entity_update_batch_size', 50)) + ->execute(); + + $database = \Drupal::database(); + /** @var \Drupal\block_content\BlockContentInterface $blockContent */ + foreach ($blockContentStorage->loadMultiple($ids) as $blockContent) { + // Get the revision_user from the first revision of this block to use + // as the author. + $query = $database->select('block_content_revision', 'bcr') + ->condition('id', $blockContent->id()); + $query->addExpression('MIN(revision_id)', 'revision_id'); + $revisionId = $query->execute()->fetchField(); + /** @var \Drupal\block_content\BlockContentInterface $revision */ + $revision = $blockContentStorage->loadRevision($revisionId); + + $blockContent->setOwnerId($revision->getRevisionUserId() ?? 0) + ->setSyncing(TRUE) + ->save(); + $sandbox['progress'] += 1; + } + + $sandbox['#finished'] = empty($sandbox['total']) ? 1 : ($sandbox['progress'] / $sandbox['total']); + + return new TranslatableMarkup('Processed Block Content Entities (@count/@total)', [ + '@count' => $sandbox['progress'], + '@total' => $sandbox['total'], + ]); +} diff --git a/core/modules/block_content/src/BlockContentInterface.php b/core/modules/block_content/src/BlockContentInterface.php index f6763f451c576131dd30753adb885afea074a45a..ec8a9236cf42aa6d4f8a86625dcd9ee95dd518b4 100644 --- a/core/modules/block_content/src/BlockContentInterface.php +++ b/core/modules/block_content/src/BlockContentInterface.php @@ -7,11 +7,12 @@ use Drupal\Core\Entity\EntityChangedInterface; use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\RevisionLogInterface; +use Drupal\user\EntityOwnerInterface; /** * Provides an interface defining a content block entity. */ -interface BlockContentInterface extends ContentEntityInterface, EntityChangedInterface, RevisionLogInterface, EntityPublishedInterface, RefinableDependentAccessInterface { +interface BlockContentInterface extends ContentEntityInterface, EntityChangedInterface, RevisionLogInterface, EntityPublishedInterface, RefinableDependentAccessInterface, EntityOwnerInterface { /** * Sets the block description. diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php index 81e6bfcdaeaa29bcb24d4bb15a4063f861dab9b6..df539e7cda0d927fb42e1e54d07ff9af49c8031f 100644 --- a/core/modules/block_content/src/Entity/BlockContent.php +++ b/core/modules/block_content/src/Entity/BlockContent.php @@ -8,6 +8,7 @@ use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\block_content\BlockContentInterface; +use Drupal\user\EntityOwnerTrait; /** * Defines the content block entity class. @@ -69,6 +70,7 @@ * "langcode" = "langcode", * "uuid" = "uuid", * "published" = "status", + * "owner" = "uid", * }, * revision_metadata_keys = { * "revision_user" = "revision_user", @@ -88,6 +90,7 @@ class BlockContent extends EditorialContentEntityBase implements BlockContentInterface { use RefinableDependentAccessTrait; + use EntityOwnerTrait; /** * The theme the block is being created in. @@ -191,6 +194,7 @@ public function preSaveRevision(EntityStorageInterface $storage, \stdClass $reco public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */ $fields = parent::baseFieldDefinitions($entity_type); + $fields += static::ownerBaseFieldDefinitions($entity_type); $fields['id']->setLabel(t('Content block ID')) ->setDescription(t('The content block ID.')); diff --git a/core/modules/block_content/tests/src/Functional/Rest/BlockContentResourceTestBase.php b/core/modules/block_content/tests/src/Functional/Rest/BlockContentResourceTestBase.php index f3af50a1f58c12fbf29fd1e5f09c334e5c558391..ddc8d183ecd11aa9bf2bde66dd069db3ec249970 100644 --- a/core/modules/block_content/tests/src/Functional/Rest/BlockContentResourceTestBase.php +++ b/core/modules/block_content/tests/src/Functional/Rest/BlockContentResourceTestBase.php @@ -8,6 +8,7 @@ use Drupal\block_content\Entity\BlockContentType; use Drupal\Core\Cache\Cache; use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase; +use Drupal\user\Entity\User; /** * ResourceTestBase for BlockContent entity. @@ -92,6 +93,7 @@ protected function createEntity() { * {@inheritdoc} */ protected function getExpectedNormalizedEntity() { + $author = User::load($this->entity->getOwnerId()); return [ 'id' => [ [ @@ -171,6 +173,14 @@ protected function getExpectedNormalizedEntity() { 'value' => FALSE, ], ], + 'uid' => [ + [ + 'target_id' => (int) $author->id(), + 'target_type' => 'user', + 'target_uuid' => $author->uuid(), + 'url' => base_path() . 'user/' . $author->id(), + ], + ], ]; } diff --git a/core/modules/block_content/tests/src/Functional/Update/BlockContentUpdateTest.php b/core/modules/block_content/tests/src/Functional/Update/BlockContentUpdateTest.php index 4fa00b2f0f920f3b1cf02883edd7baecdaf343a6..8e4048039d60b4f48c34c93858d3014e5138a8d7 100644 --- a/core/modules/block_content/tests/src/Functional/Update/BlockContentUpdateTest.php +++ b/core/modules/block_content/tests/src/Functional/Update/BlockContentUpdateTest.php @@ -4,6 +4,7 @@ namespace Drupal\Tests\block_content\Functional\Update; +use Drupal\block_content\Entity\BlockContent; use Drupal\block_content\Entity\BlockContentType; use Drupal\FunctionalTests\Update\UpdatePathTestBase; use Drupal\user\Entity\User; @@ -125,4 +126,61 @@ public function testBlockLibraryPermissionsUpdate(): void { $this->assertTrue($user->hasPermission('access block library')); } + /** + * Tests adding an owner to block content. + * + * @see block_content_update_10201() + * @see block_content_post_update_set_owner() + */ + public function testAddAndSetOwnerField(): void { + $user1 = $this->drupalCreateUser(); + $user2 = $this->drupalCreateUser(); + $user3 = $this->drupalCreateUser(); + + $block1 = BlockContent::create([ + 'info' => 'Test 1', + 'type' => 'basic', + 'revision_user' => $user1->id(), + ]); + $block1->save(); + $block1->setNewRevision(); + $block1->setRevisionUserId($user2->id())->save(); + + $block2 = BlockContent::create([ + 'info' => 'Test 2', + 'type' => 'basic', + 'revision_user' => $user2->id(), + ]); + $block2->save(); + $block2->setNewRevision(); + $block2->setRevisionUserId($user3->id())->save(); + + $block3 = BlockContent::create([ + 'info' => 'Test 3', + 'type' => 'basic', + 'revision_user' => $user3->id(), + ]); + $block3->save(); + $block3->setNewRevision(); + $block3->setRevisionUserId($user1->id())->save(); + + $block4 = BlockContent::create([ + 'info' => 'Test 4', + 'type' => 'basic', + 'revision_user' => NULL, + ]); + $block4->save(); + + $this->runUpdates(); + + $block1 = BlockContent::load($block1->id()); + $this->assertEquals($user1->id(), $block1->getOwnerId()); + $block2 = BlockContent::load($block2->id()); + $this->assertEquals($user2->id(), $block2->getOwnerId()); + $block3 = BlockContent::load($block3->id()); + $this->assertEquals($user3->id(), $block3->getOwnerId()); + $block4 = BlockContent::load($block4->id()); + $this->assertEquals(0, $block4->getOwnerId()); + } + } diff --git a/core/modules/jsonapi/tests/src/Functional/BlockContentTest.php b/core/modules/jsonapi/tests/src/Functional/BlockContentTest.php index 4a870fdea63caac660b31c9bf14383b12eeb65f2..5a6ca80e3886a492363417e4e62689b057d4f09b 100644 --- a/core/modules/jsonapi/tests/src/Functional/BlockContentTest.php +++ b/core/modules/jsonapi/tests/src/Functional/BlockContentTest.php @@ -194,6 +194,19 @@ protected function getExpectedDocument() { 'self' => ['href' => $base_url->toString() . '/relationships/revision_user' . $version_query_string], ], ], + 'uid' => [ + 'data' => [ + 'id' => $this->entity->getOwner()->uuid(), + 'meta' => [ + 'drupal_internal__target_id' => $this->entity->getOwnerId(), + ], + 'type' => 'user--user', + ], + 'links' => [ + 'related' => ['href' => $base_url->toString() . '/uid' . $version_query_string], + 'self' => ['href' => $base_url->toString() . '/relationships/uid' . $version_query_string], + ], + ], ], ], ];