diff --git a/core/modules/block_content/block_content.install b/core/modules/block_content/block_content.install index 6af2ac4..73cbdd8 100644 --- a/core/modules/block_content/block_content.install +++ b/core/modules/block_content/block_content.install @@ -5,7 +5,10 @@ * Install, update and uninstall functions for the block_content module. */ +use Drupal\block_content\BlockContentStorageSchema; use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Add 'revision_translation_affected' field to 'block_content' entities. @@ -72,3 +75,53 @@ function block_content_update_8300() { $definition_update_manager->updateEntityType($entity_type); } + +/** + * Add a publishing status field for block_content entities. + */ +function block_content_update_8400() { + // Add the published entity key to the block_content entity type. + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + $entity_type = $definition_update_manager->getEntityType('block_content'); + $entity_keys = $entity_type->getKeys(); + $entity_keys['published'] = 'status'; + $entity_type->set('entity_keys', $entity_keys); + $definition_update_manager->updateEntityType($entity_type); + + // Install the publishing status field to the block_content entity type. + $status = BaseFieldDefinition::create('boolean') + ->setLabel(new TranslatableMarkup('Publishing status')) + ->setDescription(new TranslatableMarkup('A boolean indicating the published state.')) + ->setRevisionable(TRUE) + ->setTranslatable(TRUE) + ->setRequired(TRUE) + ->setDefaultValue(TRUE); + + $has_content_translation_status_field = \Drupal::moduleHandler()->moduleExists('content_translation') && $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'block_content'); + if ($has_content_translation_status_field) { + $status->setInitialValueFromField('content_translation_status'); + } + else { + $status->setInitialValue(1); + } + $definition_update_manager->installFieldStorageDefinition('status', 'block_content', 'block_content', $status); + + // Uninstall the 'content_translation_status' field if needed. + $database = \Drupal::database(); + if ($has_content_translation_status_field) { + // First we have to remove the field data. + $database->update($entity_type->getDataTable()) + ->fields(['content_translation_status' => NULL]) + ->execute(); + + // A site may have disabled revisionability for this entity type. + if ($entity_type->isRevisionable()) { + $database->update($entity_type->getRevisionDataTable()) + ->fields(['content_translation_status' => NULL]) + ->execute(); + } + + $content_translation_status = $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'block_content'); + $definition_update_manager->uninstallFieldStorageDefinition($content_translation_status); + } +} diff --git a/core/modules/block_content/src/BlockContentAccessControlHandler.php b/core/modules/block_content/src/BlockContentAccessControlHandler.php index d0c19c5..6760b39 100644 --- a/core/modules/block_content/src/BlockContentAccessControlHandler.php +++ b/core/modules/block_content/src/BlockContentAccessControlHandler.php @@ -19,7 +19,7 @@ class BlockContentAccessControlHandler extends EntityAccessControlHandler { */ protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) { if ($operation === 'view') { - return AccessResult::allowed(); + return AccessResult::allowedIf($entity->isPublished() || $account->hasPermission('administer blocks')); } return parent::checkAccess($entity, $operation, $account); } diff --git a/core/modules/block_content/src/BlockContentInterface.php b/core/modules/block_content/src/BlockContentInterface.php index 130cae1..75fdc59 100644 --- a/core/modules/block_content/src/BlockContentInterface.php +++ b/core/modules/block_content/src/BlockContentInterface.php @@ -4,12 +4,13 @@ use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityChangedInterface; +use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\RevisionLogInterface; /** * Provides an interface defining a custom block entity. */ -interface BlockContentInterface extends ContentEntityInterface, EntityChangedInterface, RevisionLogInterface { +interface BlockContentInterface extends ContentEntityInterface, EntityChangedInterface, RevisionLogInterface, EntityPublishedInterface { /** * Returns the block revision log message. diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php index 76071df..7e9117e 100644 --- a/core/modules/block_content/src/Entity/BlockContent.php +++ b/core/modules/block_content/src/Entity/BlockContent.php @@ -3,7 +3,9 @@ namespace Drupal\block_content\Entity; use Drupal\Core\Entity\ContentEntityBase; +use Drupal\Core\Entity\EditorialContentEntityBase; use Drupal\Core\Entity\EntityChangedTrait; +use Drupal\Core\Entity\EntityPublishedTrait; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Field\BaseFieldDefinition; @@ -51,7 +53,8 @@ * "bundle" = "type", * "label" = "info", * "langcode" = "langcode", - * "uuid" = "uuid" + * "uuid" = "uuid", + * "published" = "status", * }, * revision_metadata_keys = { * "revision_user" = "revision_user", @@ -68,9 +71,7 @@ * caching. * See https://www.drupal.org/node/2284917#comment-9132521 for more information. */ -class BlockContent extends ContentEntityBase implements BlockContentInterface { - - use EntityChangedTrait; +class BlockContent extends EditorialContentEntityBase implements BlockContentInterface { /** * The theme the block is being created in. @@ -174,6 +175,8 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { $fields['type']->setLabel(t('Block type')) ->setDescription(t('The block type.')); + $fields['revision_log']->setDescription(t('The log entry explaining the changes in this revision.')); + $fields['info'] = BaseFieldDefinition::create('string') ->setLabel(t('Block description')) ->setDescription(t('A brief description of your block.')) @@ -187,35 +190,12 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setDisplayConfigurable('form', TRUE) ->addConstraint('UniqueField', []); - $fields['revision_log'] = BaseFieldDefinition::create('string_long') - ->setLabel(t('Revision log message')) - ->setDescription(t('The log entry explaining the changes in this revision.')) - ->setRevisionable(TRUE) - ->setDisplayOptions('form', [ - 'type' => 'string_textarea', - 'weight' => 25, - 'settings' => [ - 'rows' => 4, - ], - ]); - $fields['changed'] = BaseFieldDefinition::create('changed') ->setLabel(t('Changed')) ->setDescription(t('The time that the custom block was last edited.')) ->setTranslatable(TRUE) ->setRevisionable(TRUE); - $fields['revision_created'] = BaseFieldDefinition::create('created') - ->setLabel(t('Revision create time')) - ->setDescription(t('The time that the current revision was created.')) - ->setRevisionable(TRUE); - - $fields['revision_user'] = BaseFieldDefinition::create('entity_reference') - ->setLabel(t('Revision user')) - ->setDescription(t('The user ID of the author of the current revision.')) - ->setSetting('target_type', 'user') - ->setRevisionable(TRUE); - $fields['revision_translation_affected'] = BaseFieldDefinition::create('boolean') ->setLabel(t('Revision translation affected')) ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.')) diff --git a/core/modules/block_content/src/Tests/BlockContentUpdateTest.php b/core/modules/block_content/src/Tests/Update/BlockContentUpdateTest.php similarity index 57% rename from core/modules/block_content/src/Tests/BlockContentUpdateTest.php rename to core/modules/block_content/src/Tests/Update/BlockContentUpdateTest.php index 77c12c6..888607e 100644 --- a/core/modules/block_content/src/Tests/BlockContentUpdateTest.php +++ b/core/modules/block_content/src/Tests/Update/BlockContentUpdateTest.php @@ -1,6 +1,6 @@ databaseDumpFiles = [ - __DIR__ . '/../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz', + __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8-rc1.filled.standard.php.gz', ]; } @@ -43,4 +44,27 @@ public function testSimpleUpdates() { $this->assertEqual('block_content_field_revision', $entity_type->getRevisionDataTable()); } + /** + * Tests adding a status field to the block content entity type. + * + * @see block_content_update_8400() + */ + public function testStatusFieldAddition() { + $schema = \Drupal::database()->schema(); + $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + + // Run updates. + $this->runUpdates(); + + // Check that the field exists and has the correct label. + $updated_field = $entity_definition_update_manager->getFieldStorageDefinition('status', 'block_content'); + $this->assertEqual('Publishing status', $updated_field->getLabel()); + + $content_translation_status = $entity_definition_update_manager->getFieldStorageDefinition('content_translation_status', 'block_content'); + $this->assertNull($content_translation_status); + + $this->assertFalse($schema->fieldExists('block_content_field_revision', 'content_translation_status')); + $this->assertFalse($schema->fieldExists('block_content_field_data', 'content_translation_status')); + } + } diff --git a/core/modules/block_content/tests/src/Functional/UnpublishedBlockTest.php b/core/modules/block_content/tests/src/Functional/UnpublishedBlockTest.php new file mode 100644 index 0000000..082a1ae --- /dev/null +++ b/core/modules/block_content/tests/src/Functional/UnpublishedBlockTest.php @@ -0,0 +1,49 @@ + 'Test block', + 'type' => 'basic', + ]); + $block_content->save(); + + $this->placeBlock('block_content:' . $block_content->uuid()); + + $this->drupalGet(''); + $page = $this->getSession()->getPage(); + $this->assertTrue($page->has('css', '.block-block-content' . $block_content->uuid())); + + $block_content->setPublished(FALSE); + $block_content->save(); + + $this->drupalGet(''); + $page = $this->getSession()->getPage(); + $this->assertFalse($page->has('css', '.block-block-content' . $block_content->uuid())); + } +} diff --git a/core/modules/content_translation/content_translation.install b/core/modules/content_translation/content_translation.install index dc12d9f..67b161c 100644 --- a/core/modules/content_translation/content_translation.install +++ b/core/modules/content_translation/content_translation.install @@ -5,6 +5,8 @@ * Installation functions for Content Translation module. */ +use \Drupal\Core\Entity\Sql\SqlEntityStorageInterface; +use \Drupal\Core\Language\LanguageInterface; use \Drupal\Core\Url; /** @@ -44,3 +46,57 @@ function content_translation_update_8001() { function content_translation_update_8002() { \Drupal::service('plugin.manager.field.field_type')->clearCachedDefinitions(); } + +/** + * Fix the initial values for content translation metadata fields. + */ +function content_translation_update_8400() { + $database = \Drupal::database(); + /** @var \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager */ + $content_translation_manager = \Drupal::service('content_translation.manager'); + /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */ + $last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository'); + $entity_type_manager = \Drupal::entityTypeManager(); + $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + + foreach ($content_translation_manager->getSupportedEntityTypes() as $entity_type_id => $entity_type_definition) { + $storage = $entity_type_manager->getStorage($entity_type_id); + if ($storage instanceof SqlEntityStorageInterface) { + $entity_type = $entity_definition_update_manager->getEntityType($entity_type_id); + $storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id); + + // Since the entity type is managed by Content Translation, we can assume + // that it is translatable, so we use the data and revision data tables. + $tables_to_update = [$entity_type->getDataTable()]; + if ($entity_type->isRevisionable()) { + $tables_to_update += [$entity_type->getRevisionDataTable()]; + } + + foreach ($tables_to_update as $table_name) { + // Fix the values of the 'content_translation_source' field. + if (isset($storage_definitions['content_translation_source'])) { + $database->update($table_name) + ->fields(['content_translation_source' => LanguageInterface::LANGCODE_NOT_SPECIFIED]) + ->isNull('content_translation_source') + ->execute(); + } + + // Fix the values of the 'content_translation_outdated' field. + if (isset($storage_definitions['content_translation_outdated'])) { + $database->update($table_name) + ->fields(['content_translation_outdated' => 0]) + ->isNull('content_translation_outdated') + ->execute(); + } + + // Fix the values of the 'content_translation_status' field. + if (isset($storage_definitions['content_translation_status'])) { + $database->update($table_name) + ->fields(['content_translation_status' => 1]) + ->isNull('content_translation_status') + ->execute(); + } + } + } + } +} diff --git a/core/modules/content_translation/src/ContentTranslationHandler.php b/core/modules/content_translation/src/ContentTranslationHandler.php index c1688b9..3f7baa7 100644 --- a/core/modules/content_translation/src/ContentTranslationHandler.php +++ b/core/modules/content_translation/src/ContentTranslationHandler.php @@ -117,14 +117,16 @@ public function getFieldDefinitions() { ->setDescription(t('The source language from which this translation was created.')) ->setDefaultValue(LanguageInterface::LANGCODE_NOT_SPECIFIED) ->setRevisionable(TRUE) - ->setTranslatable(TRUE); + ->setTranslatable(TRUE) + ->setInitialValue(LanguageInterface::LANGCODE_NOT_SPECIFIED); $definitions['content_translation_outdated'] = BaseFieldDefinition::create('boolean') ->setLabel(t('Translation outdated')) ->setDescription(t('A boolean indicating whether this translation needs to be updated.')) ->setDefaultValue(FALSE) ->setRevisionable(TRUE) - ->setTranslatable(TRUE); + ->setTranslatable(TRUE) + ->setInitialValue(0); if (!$this->hasAuthor()) { $definitions['content_translation_uid'] = BaseFieldDefinition::create('entity_reference') @@ -143,7 +145,8 @@ public function getFieldDefinitions() { ->setDescription(t('A boolean indicating whether the translation is visible to non-translators.')) ->setDefaultValue(TRUE) ->setRevisionable(TRUE) - ->setTranslatable(TRUE); + ->setTranslatable(TRUE) + ->setInitialValue(1); } if (!$this->hasCreatedTime()) { diff --git a/core/modules/content_translation/src/Tests/Update/ContentTranslationUpdateTest.php b/core/modules/content_translation/src/Tests/Update/ContentTranslationUpdateTest.php new file mode 100644 index 0000000..85b952c --- /dev/null +++ b/core/modules/content_translation/src/Tests/Update/ContentTranslationUpdateTest.php @@ -0,0 +1,100 @@ +database = \Drupal::database(); + $this->entityDefinitionUpdateManager = \Drupal::entityDefinitionUpdateManager(); + $this->entityManager = \Drupal::entityManager(); + $this->state = \Drupal::state(); + } + + /** + * {@inheritdoc} + */ + public function setDatabaseDumpFiles() { + $this->databaseDumpFiles = [ + __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.0.0-rc1-filled.standard.entity_test_update_mul.php.gz', + ]; + } + + /** + * Tests that initial values for metadata fields are populated correctly. + */ + public function testContentTranslationUpdate8400() { + $this->updateEntityTypeToTranslatable(); + + // The test database dump contains NULL values for + // 'content_translation_source', 'content_translation_outdated' and + // 'content_translation_status' for the first 50 test entities. + // @see _entity_test_update_create_test_entities() + $first_entity_record = $this->database->select('entity_test_update_data', 'etud') + ->fields('etud') + ->condition('etud.id', 1) + ->execute() + ->fetchAllAssoc('id'); + $this->assertNull($first_entity_record[1]->content_translation_source); + $this->assertNull($first_entity_record[1]->content_translation_outdated); + $this->assertNull($first_entity_record[1]->content_translation_status); + + $this->runUpdates(); + + // After running the updates, all those fields should be populated with + // their default values. + $first_entity_record = $this->database->select('entity_test_update_data', 'etud') + ->fields('etud') + ->condition('etud.id', 1) + ->execute() + ->fetchAllAssoc('id'); + $this->assertEqual(LanguageInterface::LANGCODE_NOT_SPECIFIED, $first_entity_record[1]->content_translation_source); + $this->assertEqual(0, $first_entity_record[1]->content_translation_outdated); + $this->assertEqual(1, $first_entity_record[1]->content_translation_status); + } + +} diff --git a/core/modules/taxonomy/src/Tests/Views/TaxonomyTermViewTest.php b/core/modules/taxonomy/src/Tests/Views/TaxonomyTermViewTest.php index bfd65cf..08ff643 100644 --- a/core/modules/taxonomy/src/Tests/Views/TaxonomyTermViewTest.php +++ b/core/modules/taxonomy/src/Tests/Views/TaxonomyTermViewTest.php @@ -5,6 +5,7 @@ use Drupal\Component\Utility\Unicode; use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\language\Entity\ConfigurableLanguage; +use Drupal\node\Entity\Node; use Drupal\user\Entity\Role; use Drupal\user\RoleInterface; use Drupal\views\Views; @@ -124,6 +125,11 @@ public function testTaxonomyTermView() { // query anymore. // @see \Drupal\views\Plugin\views\filter\LanguageFilter::query() $node->delete(); + // We also have to remove the nodes created by the parent ::setUp() method + // if we want to be able to uninstall the Content Translation module. + foreach (Node::loadMultiple() as $node) { + $node->delete(); + } \Drupal::service('module_installer')->uninstall(['content_translation', 'language']); $view = Views::getView('taxonomy_term');