Commit 46424a89 authored by alexpott's avatar alexpott

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
......@@ -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:
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",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment