Skip to content
Snippets Groups Projects
Unverified Commit 46424a89 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2599228 by tstoeckler, Taran2L, poornachandran, catch, vacho, johan.s,...

Issue #2599228 by tstoeckler, Taran2L, poornachandran, catch, vacho, johan.s, Berdir, hchonov, osman, tim.plunkett, GoZ, Voidtek, neetu morwani, psf_, alexpott, dxvargas, nkoporec, plach, andy@andyhawks.com, joey-santiago: Programmatically created translatable content type returns SQL error on content creation
parent cbef6823
No related branches found
No related tags found
No related merge requests found
Showing
with 183 additions and 90 deletions
......@@ -16,6 +16,7 @@
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\language\ContentLanguageSettingsInterface;
/**
* Implements hook_help().
......@@ -172,27 +173,72 @@ function content_translation_entity_type_alter(array &$entity_types) {
/**
* Implements hook_ENTITY_TYPE_insert().
*
* Clear the bundle information cache so that the bundle's translatability will
* be set properly.
* Installs Content Translation's field storage definitions for the target
* entity type, if required.
*
* Also clears the bundle information cache so that the bundle's translatability
* will be set properly.
*
* @see content_translation_entity_bundle_info_alter()
* @see \Drupal\content_translation\ContentTranslationManager::isEnabled()
*/
function content_translation_language_content_settings_insert(EntityInterface $entity) {
function content_translation_language_content_settings_insert(ContentLanguageSettingsInterface $settings) {
if ($settings->getThirdPartySetting('content_translation', 'enabled', FALSE)) {
_content_translation_install_field_storage_definitions($settings->getTargetEntityTypeId());
}
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
}
/**
* Implements hook_ENTITY_TYPE_update().
*
* Clear the bundle information cache so that the bundle's translatability will
* be changed properly.
* Installs Content Translation's field storage definitions for the target
* entity type, if required.
*
* Also clears the bundle information cache so that the bundle's translatability
* will be changed properly.
*
* @see content_translation_entity_bundle_info_alter()
* @see \Drupal\content_translation\ContentTranslationManager::isEnabled()
*/
function content_translation_language_content_settings_update(EntityInterface $entity) {
function content_translation_language_content_settings_update(ContentLanguageSettingsInterface $settings) {
$original_settings = $settings->original;
if ($settings->getThirdPartySetting('content_translation', 'enabled', FALSE)
&& !$original_settings->getThirdPartySetting('content_translation', 'enabled', FALSE)
) {
_content_translation_install_field_storage_definitions($settings->getTargetEntityTypeId());
}
\Drupal::service('entity_type.bundle.info')->clearCachedBundles();
}
/**
* Installs Content Translation's fields for a given entity type.
*
* @param string $entity_type_id
* The entity type ID.
*
* @todo Generalize this code in https://www.drupal.org/node/2346013.
*/
function _content_translation_install_field_storage_definitions($entity_type_id) {
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
$field_manager = \Drupal::service('entity_field.manager');
/** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $schema_repository */
$schema_repository = \Drupal::service('entity.last_installed_schema.repository');
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$field_manager->useCaches(FALSE);
$storage_definitions = $field_manager->getFieldStorageDefinitions($entity_type_id);
$field_manager->useCaches(TRUE);
$installed_storage_definitions = $schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id);
foreach (array_diff_key($storage_definitions, $installed_storage_definitions) as $storage_definition) {
/** @var \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition */
if ($storage_definition->getProvider() == 'content_translation') {
$definition_update_manager->installFieldStorageDefinition($storage_definition->getName(), $entity_type_id, 'content_translation', $storage_definition);
}
}
}
/**
* Implements hook_entity_bundle_info_alter().
*/
......
......@@ -29,10 +29,9 @@ services:
content_translation.manager:
class: Drupal\content_translation\ContentTranslationManager
arguments: ['@entity_type.manager', '@content_translation.updates_manager', '@entity_type.bundle.info']
arguments: ['@entity_type.manager', '@entity_type.bundle.info']
content_translation.updates_manager:
class: Drupal\content_translation\ContentTranslationUpdatesManager
arguments: ['@entity_type.manager', '@entity.definition_update_manager', '@entity_field.manager', '@entity.last_installed_schema.repository']
tags:
- { name: event_subscriber }
deprecated: The "%service_id%" service is deprecated. Definitions are updated automatically now so no replacement is needed. See https://www.drupal.org/node/2973222.
......@@ -25,11 +25,6 @@ process:
third_party_settings/content_translation/bundle_settings/untranslatable_fields_hide: untranslatable_fields_hide
destination:
plugin: entity:language_content_settings
content_translation_update_definitions:
- comment
- node
- taxonomy_term
- user
migration_dependencies:
optional:
- d7_comment_type
......
......@@ -33,8 +33,6 @@ process:
destination:
plugin: entity:node
translations: true
content_translation_update_definitions:
- node
destination_module: content_translation
migration_dependencies:
required:
......
......@@ -17,7 +17,10 @@ class ContentTranslationManager implements ContentTranslationManagerInterface, B
/**
* {@inheritdoc}
*/
protected $deprecatedProperties = ['entityManager' => 'entity.manager'];
protected $deprecatedProperties = [
'entityManager' => 'entity.manager',
'updatesManager' => 'content_translation.updates_manager',
];
/**
* The entity type bundle info provider.
......@@ -33,28 +36,19 @@ class ContentTranslationManager implements ContentTranslationManagerInterface, B
*/
protected $entityTypeManager;
/**
* The updates manager.
*
* @var \Drupal\content_translation\ContentTranslationUpdatesManager
*/
protected $updatesManager;
/**
* Constructs a ContentTranslationManageAccessCheck object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\content_translation\ContentTranslationUpdatesManager $updates_manager
* The updates manager.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
* The entity type bundle info provider.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, ContentTranslationUpdatesManager $updates_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL) {
public function __construct(EntityTypeManagerInterface $entity_type_manager, $entity_type_bundle_info) {
$this->entityTypeManager = $entity_type_manager;
$this->updatesManager = $updates_manager;
if (!$entity_type_bundle_info) {
@trigger_error('The entity_type.bundle.info service must be passed to ContentTranslationManager::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
if (!($entity_type_bundle_info instanceof EntityTypeBundleInfoInterface)) {
@trigger_error('The entity_type.bundle.info service should be passed to ContentTranslationManager::__construct() instead of the content_translation.updates_manager service since 8.7.0. This will be required in Drupal 9.0.0. See https://www.drupal.org/node/2549139 and https://www.drupal.org/node/2973222.', E_USER_DEPRECATED);
$entity_type_bundle_info = \Drupal::service('entity_type.bundle.info');
}
$this->entityTypeBundleInfo = $entity_type_bundle_info;
......@@ -104,8 +98,6 @@ public function getSupportedEntityTypes() {
public function setEnabled($entity_type_id, $bundle, $value) {
$config = $this->loadContentLanguageSettings($entity_type_id, $bundle);
$config->setThirdPartySetting('content_translation', 'enabled', $value)->save();
$entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
$this->updatesManager->updateDefinitions([$entity_type_id => $entity_type]);
}
/**
......
......@@ -2,28 +2,22 @@
namespace Drupal\content_translation;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Config\ConfigEvents;
use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
use Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\migrate\Event\MigrateEvents;
use Drupal\migrate\Event\MigrateImportEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@trigger_error('\Drupal\content_translation\ContentTranslationUpdatesManager is scheduled for removal in Drupal 9.0.0. Definitions are updated automatically now so no replacement is needed. See https://www.drupal.org/node/2973222.', E_USER_DEPRECATED);
/**
* Provides the logic needed to update field storage definitions when needed.
*
* @deprecated in Drupal 8.7.x, to be removed before Drupal 9.0.0.
* Definitions are updated automatically now so no replacement is needed.
*
* @see https://www.drupal.org/node/2973222
*/
class ContentTranslationUpdatesManager implements EventSubscriberInterface {
use DeprecatedServicePropertyTrait;
/**
* {@inheritdoc}
*/
protected $deprecatedProperties = ['entityManager' => 'entity.manager'];
class ContentTranslationUpdatesManager {
/**
* The entity field manager.
......@@ -69,12 +63,10 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Ent
$this->entityTypeManager = $entity_type_manager;
$this->updateManager = $update_manager;
if (!$entity_field_manager) {
@trigger_error('The entity_field.manager service must be passed to ContentTranslationUpdatesManager::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
$entity_field_manager = \Drupal::service('entity_field.manager');
}
$this->entityFieldManager = $entity_field_manager;
if (!$entity_last_installed_schema_repository) {
@trigger_error('The entity.last_installed_schema.repository service must be passed to ContentTranslationUpdatesManager::__construct(), it is required before Drupal 9.0.0. See https://www.drupal.org/node/2549139.', E_USER_DEPRECATED);
$entity_last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
}
$this->entityLastInstalledSchemaRepository = $entity_last_installed_schema_repository;
......@@ -88,8 +80,6 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Ent
*/
public function updateDefinitions(array $entity_types) {
// Handle field storage definition creation, if needed.
// @todo Generalize this code in https://www.drupal.org/node/2346013.
// @todo Handle initial values in https://www.drupal.org/node/2346019.
if ($this->updateManager->needsUpdates()) {
foreach ($entity_types as $entity_type_id => $entity_type) {
$storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type_id);
......@@ -104,38 +94,4 @@ public function updateDefinitions(array $entity_types) {
}
}
/**
* Listener for the ConfigImporter import event.
*/
public function onConfigImporterImport() {
$entity_types = array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
return $entity_type->isTranslatable();
});
$this->updateDefinitions($entity_types);
}
/**
* Listener for migration imports.
*/
public function onMigrateImport(MigrateImportEvent $event) {
$migration = $event->getMigration();
$configuration = $migration->getDestinationConfiguration();
$entity_types = NestedArray::getValue($configuration, ['content_translation_update_definitions']);
if ($entity_types) {
$entity_types = array_intersect_key($this->entityTypeManager->getDefinitions(), array_flip($entity_types));
$this->updateDefinitions($entity_types);
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events[ConfigEvents::IMPORT][] = ['onConfigImporterImport', 60];
if (class_exists('\Drupal\migrate\Event\MigrateEvents')) {
$events[MigrateEvents::POST_IMPORT][] = ['onMigrateImport'];
}
return $events;
}
}
langcode: en
status: true
dependencies: { }
id: test
label: null
description: null
langcode: en
status: true
dependencies:
config:
- entity_test.entity_test_bundle.test
module:
- content_translation
third_party_settings:
content_translation:
enabled: true
bundle_settings:
untranslatable_fields_hide: '0'
id: entity_test_with_bundle.test
target_entity_type_id: entity_test_with_bundle
target_bundle: test
default_langcode: site_default
language_alterable: true
<?php
namespace Drupal\Tests\content_translation\Kernel;
use Drupal\entity_test\Entity\EntityTestWithBundle;
use Drupal\KernelTests\KernelTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
/**
* Tests content translation for modules that provide translatable bundles.
*
* @group content_translation
*/
class ContentTranslationModuleInstallTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'content_translation',
'content_translation_test',
'entity_test',
'language',
'user',
];
/**
* The content translation manager.
*
* @var \Drupal\content_translation\ContentTranslationManagerInterface
*/
protected $contentTranslationManager;
/**
* The language code of the source language for this test.
*
* @var string
*/
protected $sourceLangcode = 'en';
/**
* The language code of the translation language for this test.
*
* @var string
*/
protected $translationLangcode = 'af';
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test_with_bundle');
ConfigurableLanguage::createFromLangcode($this->translationLangcode)->save();
$this->contentTranslationManager = $this->container->get('content_translation.manager');
}
/**
* Test that content translation fields are created upon module installation.
*/
public function testFieldUpdates() {
// The module ships a translatable bundle of the 'entity_test_with_bundle'
// entity type.
$this->installConfig(['content_translation_test']);
$entity = EntityTestWithBundle::create([
'type' => 'test',
'langcode' => $this->sourceLangcode,
]);
$entity->save();
// Add a translation with some translation metadata.
$translation = $entity->addTranslation($this->translationLangcode);
$translation_metadata = $this->contentTranslationManager->getTranslationMetadata($translation);
$translation_metadata->setSource($this->sourceLangcode)->setOutdated(TRUE);
$translation->save();
// Make sure the translation metadata has been saved correctly.
$entity = EntityTestWithBundle::load($entity->id());
$translation = $entity->getTranslation($this->translationLangcode);
$translation_metadata = $this->contentTranslationManager->getTranslationMetadata($translation);
$this->assertSame($this->sourceLangcode, $translation_metadata->getSource());
$this->assertSame(TRUE, $translation_metadata->isOutdated());
}
}
......@@ -40,8 +40,6 @@ process:
2: true
destination:
plugin: entity:language_content_settings
content_translation_update_definitions:
- node
migration_dependencies:
required:
- d6_node_type
......@@ -46,8 +46,6 @@ process:
source: language
destination:
plugin: entity:language_content_settings
content_translation_update_definitions:
- taxonomy_term
migration_dependencies:
required:
- d6_taxonomy_vocabulary
......@@ -43,8 +43,6 @@ process:
4: true
destination:
plugin: entity:language_content_settings
content_translation_update_definitions:
- node
migration_dependencies:
required:
- d7_node_type
......@@ -25,8 +25,10 @@
* },
* },
* base_table = "entity_test_with_bundle",
* data_table = "entity_test_with_bundle_field_data",
* admin_permission = "administer entity_test_with_bundle content",
* persistent_cache = FALSE,
* translatable = TRUE,
* entity_keys = {
* "id" = "id",
* "uuid" = "uuid",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment