Commit 5b026c38 authored by catch's avatar catch

Issue #2004626 by plach, kfritsche, vijaycs85, Pancho, penyaskito: Make...

Issue #2004626 by plach, kfritsche, vijaycs85, Pancho, penyaskito: Make non-configurable field translation settings available in the content language settings.
parent 9afeeb28
...@@ -489,13 +489,23 @@ public function getFieldDefinitions($entity_type, $bundle = NULL) { ...@@ -489,13 +489,23 @@ public function getFieldDefinitions($entity_type, $bundle = NULL) {
$hooks = array('entity_field_info', $entity_type . '_field_info'); $hooks = array('entity_field_info', $entity_type . '_field_info');
$this->moduleHandler->alter($hooks, $this->entityFieldInfo[$entity_type], $entity_type); $this->moduleHandler->alter($hooks, $this->entityFieldInfo[$entity_type], $entity_type);
// Enforce fields to be multiple by default. // Enforce fields to be multiple and untranslatable by default.
foreach ($this->entityFieldInfo[$entity_type]['definitions'] as &$definition) { $entity_info = $this->getDefinition($entity_type);
$definition['list'] = TRUE; $keys = array_intersect_key(array_filter($entity_info['entity_keys']), array_flip(array('id', 'revision', 'uuid', 'bundle')));
} $untranslatable_fields = array_flip(array('langcode') + $keys);
foreach ($this->entityFieldInfo[$entity_type]['optional'] as &$definition) { foreach (array('definitions', 'optional') as $key) {
$definition['list'] = TRUE; foreach ($this->entityFieldInfo[$entity_type][$key] as $name => &$definition) {
$definition['list'] = TRUE;
// Ensure ids and langcode fields are never made translatable.
if (isset($untranslatable_fields[$name]) && !empty($definition['translatable'])) {
throw new \LogicException(format_string('The @field field cannot be translatable.', array('@field' => $definition['label'])));
}
if (!isset($definition['translatable'])) {
$definition['translatable'] = FALSE;
}
}
} }
$this->cache->set($cid, $this->entityFieldInfo[$entity_type], CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE, 'entity_field_info' => TRUE)); $this->cache->set($cid, $this->entityFieldInfo[$entity_type], CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE, 'entity_field_info' => TRUE));
} }
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Field\FieldDefinitionInterface; use Drupal\Core\Entity\Field\FieldDefinitionInterface;
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
use Drupal\field\Field as FieldService;
/** /**
* Returns a form element to configure field synchronization. * Returns a form element to configure field synchronization.
...@@ -73,6 +74,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$ ...@@ -73,6 +74,7 @@ function _content_translation_form_language_content_settings_form_alter(array &$
$form['#attached']['js'][] = array('data' => drupal_get_path('module', 'content_translation') . '/content_translation.admin.js', 'type' => 'file'); $form['#attached']['js'][] = array('data' => drupal_get_path('module', 'content_translation') . '/content_translation.admin.js', 'type' => 'file');
$dependent_options_settings = array(); $dependent_options_settings = array();
$entity_manager = Drupal::entityManager();
foreach ($form['#labels'] as $entity_type => $label) { foreach ($form['#labels'] as $entity_type => $label) {
$entity_info = entity_get_info($entity_type); $entity_info = entity_get_info($entity_type);
foreach (entity_get_bundles($entity_type) as $bundle => $bundle_info) { foreach (entity_get_bundles($entity_type) as $bundle => $bundle_info) {
...@@ -84,31 +86,51 @@ function _content_translation_form_language_content_settings_form_alter(array &$ ...@@ -84,31 +86,51 @@ function _content_translation_form_language_content_settings_form_alter(array &$
// Only show the checkbox to enable translation if the bundles in the // Only show the checkbox to enable translation if the bundles in the
// entity might have fields and if there are fields to translate. // entity might have fields and if there are fields to translate.
if (!empty($entity_info['fieldable'])) { if (!empty($entity_info['fieldable'])) {
$instances = field_info_instances($entity_type, $bundle); $fields = $entity_manager->getFieldDefinitions($entity_type, $bundle);
if ($instances) { if ($fields) {
$form['settings'][$entity_type][$bundle]['translatable'] = array( $form['settings'][$entity_type][$bundle]['translatable'] = array(
'#type' => 'checkbox', '#type' => 'checkbox',
'#title' => $bundle, '#title' => $bundle,
'#default_value' => content_translation_enabled($entity_type, $bundle), '#default_value' => content_translation_enabled($entity_type, $bundle),
); );
// @todo Exploit field definitions once all core entities and field $field_settings = content_translation_get_config($entity_type, $bundle, 'fields');
// types are migrated to the Entity Field API. foreach ($fields as $field_name => $definition) {
foreach ($instances as $field_name => $instance) { $translatable = !empty($field_settings[$field_name]);
$form['settings'][$entity_type][$bundle]['fields'][$field_name] = array(
'#label' => $instance->getFieldLabel(), // We special case Field API fields as they always natively support
'#type' => 'checkbox', // translation.
'#title' => $instance->getFieldLabel(), // @todo Remove this special casing as soon as configurable and
'#default_value' => $instance->isFieldTranslatable(), // base field definitions are "unified".
); if (!empty($definition['configurable']) && ($field = FieldService::fieldInfo()->getField($entity_type, $field_name))) {
$column_element = content_translation_field_sync_widget($instance); $instance = FieldService::fieldInfo()->getInstance($entity_type, $bundle, $field_name);
if ($column_element) { $form['settings'][$entity_type][$bundle]['fields'][$field_name] = array(
$form['settings'][$entity_type][$bundle]['columns'][$field_name] = $column_element; '#label' => $instance->getFieldLabel(),
'#type' => 'checkbox',
if (isset($column_element['#options']['file'])) { '#title' => $instance->getFieldLabel(),
$dependent_options_settings["settings[{$entity_type}][{$bundle}][columns][{$field_name}]"] = array('file'); '#default_value' => $translatable,
);
$column_element = content_translation_field_sync_widget($instance);
if ($column_element) {
$form['settings'][$entity_type][$bundle]['columns'][$field_name] = $column_element;
// @todo This should not concern only files.
if (isset($column_element['#options']['file'])) {
$dependent_options_settings["settings[{$entity_type}][{$bundle}][columns][{$field_name}]"] = array('file');
}
} }
} }
// Instead we need to rely on field definitions to determine whether
// fields support translation. Whether they are actually enabled is
// determined through our settings. As a consequence only fields
// that support translation can be enabled or disabled.
elseif (isset($field_settings[$field_name]) || !empty($definition['translatable'])) {
$form['settings'][$entity_type][$bundle]['fields'][$field_name] = array(
'#label' => $definition['label'],
'#type' => 'checkbox',
'#default_value' => $translatable,
);
}
} }
} }
} }
...@@ -326,11 +348,11 @@ function _content_translation_update_field_translatability($settings) { ...@@ -326,11 +348,11 @@ function _content_translation_update_field_translatability($settings) {
foreach ($bundle_settings['fields'] as $field_name => $translatable) { foreach ($bundle_settings['fields'] as $field_name => $translatable) {
// If a field is enabled for translation for at least one instance we // If a field is enabled for translation for at least one instance we
// need to mark it as translatable. // need to mark it as translatable.
$fields[$entity_type][$field_name] = $translatable || !empty($fields[$entity_type][$field_name]); if (FieldService::fieldInfo()->getField($entity_type, $field_name)) {
$fields[$entity_type][$field_name] = $translatable || !empty($fields[$entity_type][$field_name]);
}
} }
} }
// @todo Store non-configurable field settings to be able to alter their
// definition afterwards.
} }
} }
......
...@@ -126,6 +126,33 @@ function content_translation_entity_bundle_info_alter(&$bundles) { ...@@ -126,6 +126,33 @@ function content_translation_entity_bundle_info_alter(&$bundles) {
} }
} }
/**
* Implements hook_entity_field_info_alter().
*/
function content_translation_entity_field_info_alter(&$info, $entity_type) {
$translation_settings = config('content_translation.settings')->get($entity_type);
if ($translation_settings) {
// Currently field translatability is defined per-field but we may want to
// make it per-instance instead, so leaving the possibility open for further
// easier refactoring.
$fields = array();
foreach ($translation_settings as $bundle => $settings) {
$fields += !empty($settings['content_translation']['fields']) ? $settings['content_translation']['fields'] : array();
}
$keys = array('definitions', 'optional');
foreach ($fields as $name => $translatable) {
foreach ($keys as $key) {
if (isset($info[$key][$name])) {
$info[$key][$name]['translatable'] = (bool) $translatable;
break;
}
}
}
}
}
/** /**
* Implements hook_menu(). * Implements hook_menu().
*/ */
...@@ -987,6 +1014,11 @@ function content_translation_save_settings($settings) { ...@@ -987,6 +1014,11 @@ function content_translation_save_settings($settings) {
// Store whether a bundle has translation enabled or not. // Store whether a bundle has translation enabled or not.
content_translation_set_config($entity_type, $bundle, 'enabled', $bundle_settings['translatable']); content_translation_set_config($entity_type, $bundle, 'enabled', $bundle_settings['translatable']);
// Store whether fields are translatable or not.
if (!empty($bundle_settings['fields'])) {
content_translation_set_config($entity_type, $bundle, 'fields', $bundle_settings['fields']);
}
// Store whether fields have translation enabled or not. // Store whether fields have translation enabled or not.
if (!empty($bundle_settings['columns'])) { if (!empty($bundle_settings['columns'])) {
foreach ($bundle_settings['columns'] as $field_name => $column_settings) { foreach ($bundle_settings['columns'] as $field_name => $column_settings) {
......
...@@ -20,7 +20,7 @@ class ContentTranslationSettingsTest extends WebTestBase { ...@@ -20,7 +20,7 @@ class ContentTranslationSettingsTest extends WebTestBase {
* *
* @var array * @var array
*/ */
public static $modules = array('language', 'content_translation', 'comment', 'field_ui'); public static $modules = array('language', 'content_translation', 'node', 'comment', 'field_ui');
public static function getInfo() { public static function getInfo() {
return array( return array(
...@@ -114,6 +114,17 @@ function testSettingsUI() { ...@@ -114,6 +114,17 @@ function testSettingsUI() {
$this->drupalPostForm('admin/structure/types/manage/article', $edit, t('Save content type')); $this->drupalPostForm('admin/structure/types/manage/article', $edit, t('Save content type'));
$this->drupalGet('admin/structure/types/manage/article'); $this->drupalGet('admin/structure/types/manage/article');
$this->assertFieldChecked('edit-language-configuration-content-translation'); $this->assertFieldChecked('edit-language-configuration-content-translation');
// Test that the title field of nodes is available in the settings form.
$edit = array(
'entity_types[node]' => TRUE,
'settings[node][article][settings][language][langcode]' => 'current_interface',
'settings[node][article][settings][language][language_show]' => TRUE,
'settings[node][article][translatable]' => TRUE,
'settings[node][article][fields][title]' => TRUE
);
$this->assertSettings('node', NULL, TRUE, $edit);
} }
/** /**
......
...@@ -108,10 +108,13 @@ function testImageFieldSync() { ...@@ -108,10 +108,13 @@ function testImageFieldSync() {
$this->assertNoFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt'); $this->assertNoFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt');
$this->assertNoFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title'); $this->assertNoFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title');
$edit = array( $edit = array(
'settings[entity_test_mul][entity_test_mul][fields][field_test_et_ui_image]' => TRUE,
'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][alt]' => TRUE, 'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][alt]' => TRUE,
'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][title]' => TRUE, 'settings[entity_test_mul][entity_test_mul][columns][field_test_et_ui_image][title]' => TRUE,
); );
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save')); $this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save'));
$errors = $this->xpath('//div[contains(@class, "messages--error")]');
$this->assertFalse($errors, 'Settings correctly stored.');
$this->assertFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt'); $this->assertFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-alt');
$this->assertFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title'); $this->assertFieldChecked('edit-settings-entity-test-mul-entity-test-mul-columns-field-test-et-ui-image-title');
$this->drupalLogin($this->translator); $this->drupalLogin($this->translator);
......
...@@ -359,6 +359,7 @@ public static function baseFieldDefinitions($entity_type) { ...@@ -359,6 +359,7 @@ public static function baseFieldDefinitions($entity_type) {
'property_constraints' => array( 'property_constraints' => array(
'value' => array('Length' => array('max' => 255)), 'value' => array('Length' => array('max' => 255)),
), ),
'translatable' => TRUE,
); );
$properties['uid'] = array( $properties['uid'] = array(
'label' => t('User ID'), 'label' => t('User ID'),
......
...@@ -15,11 +15,6 @@ ...@@ -15,11 +15,6 @@
*/ */
class NodeTranslationUITest extends ContentTranslationUITest { class NodeTranslationUITest extends ContentTranslationUITest {
/**
* The title of the test node.
*/
protected $title;
/** /**
* Modules to enable. * Modules to enable.
* *
...@@ -38,7 +33,6 @@ public static function getInfo() { ...@@ -38,7 +33,6 @@ public static function getInfo() {
function setUp() { function setUp() {
$this->entityType = 'node'; $this->entityType = 'node';
$this->bundle = 'article'; $this->bundle = 'article';
$this->title = $this->randomName();
parent::setUp(); parent::setUp();
$this->drupalPlaceBlock('system_help_block', array('region' => 'content')); $this->drupalPlaceBlock('system_help_block', array('region' => 'content'));
} }
...@@ -62,8 +56,7 @@ protected function getTranslatorPermissions() { ...@@ -62,8 +56,7 @@ protected function getTranslatorPermissions() {
* Overrides \Drupal\content_translation\Tests\ContentTranslationUITest::getNewEntityValues(). * Overrides \Drupal\content_translation\Tests\ContentTranslationUITest::getNewEntityValues().
*/ */
protected function getNewEntityValues($langcode) { protected function getNewEntityValues($langcode) {
// Node title is not translatable yet, hence we use a fixed value. return array('title' => $this->randomName()) + parent::getNewEntityValues($langcode);
return array('title' => $this->title) + parent::getNewEntityValues($langcode);
} }
/** /**
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
use Drupal\Core\TypedData\TranslatableInterface; use Drupal\Core\TypedData\TranslatableInterface;
use Drupal\entity_test\Entity\EntityTestMulRev;
/** /**
* Tests entity translation. * Tests entity translation.
...@@ -492,4 +493,42 @@ function testEntityTranslationAPI() { ...@@ -492,4 +493,42 @@ function testEntityTranslationAPI() {
$this->assertEqual($field->getLangcode(), $langcode2, 'Field object has the expected langcode.'); $this->assertEqual($field->getLangcode(), $langcode2, 'Field object has the expected langcode.');
} }
/**
* Check that field translatability is handled properly.
*/
function testFieldDefinitions() {
// Check that field translatability can be altered to be enabled or disabled
// in field definitions.
$entity_type = 'entity_test_mulrev';
$this->state->set('entity_test.field_definitions.translatable', array('name' => FALSE));
$this->entityManager->clearCachedFieldDefinitions();
$definitions = $this->entityManager->getFieldDefinitions($entity_type);
$this->assertFalse($definitions['name']['translatable'], 'Field translatability can be disabled programmatically.');
$this->state->set('entity_test.field_definitions.translatable', array('name' => TRUE));
$this->entityManager->clearCachedFieldDefinitions();
$definitions = $this->entityManager->getFieldDefinitions($entity_type);
$this->assertTrue($definitions['name']['translatable'], 'Field translatability can be enabled programmatically.');
// Check that field translatability is disabled by default.
$base_field_definitions = EntityTestMulRev::baseFieldDefinitions($entity_type);
$this->assertTrue(!isset($base_field_definitions['id']['translatable']), 'Translatability for the <em>id</em> field is not defined.');
$this->assertFalse($definitions['id']['translatable'], 'Field translatability is disabled by default.');
// Check that entity ids and langcode fields cannot be translatable.
foreach (array('id', 'uuid', 'revision_id', 'type', 'langcode') as $name) {
$this->state->set('entity_test.field_definitions.translatable', array($name => TRUE));
$this->entityManager->clearCachedFieldDefinitions();
$message = format_string('Field %field cannot be translatable.', array('%field' => $name));
try {
$definitions = $this->entityManager->getFieldDefinitions($entity_type);
$this->fail($message);
}
catch (\LogicException $e) {
$this->pass($message);
}
}
}
} }
...@@ -72,6 +72,17 @@ function entity_test_entity_info_alter(&$info) { ...@@ -72,6 +72,17 @@ function entity_test_entity_info_alter(&$info) {
} }
} }
/**
* Implements hook_entity_field_info_alter().
*/
function entity_test_entity_field_info_alter(&$info, $entity_type) {
if ($entity_type == 'entity_test_mulrev' && ($names = \Drupal::state()->get('entity_test.field_definitions.translatable'))) {
foreach ($names as $name => $value) {
$info['definitions'][$name]['translatable'] = $value;
}
}
}
/** /**
* Creates a new bundle for entity_test entities. * Creates a new bundle for entity_test entities.
* *
......
...@@ -90,9 +90,9 @@ public function testTranslationUI() { ...@@ -90,9 +90,9 @@ public function testTranslationUI() {
// Make sure that no row was inserted for taxonomy vocabularies, which do // Make sure that no row was inserted for taxonomy vocabularies, which do
// not have translations enabled. // not have translations enabled.
$rows = db_query('SELECT * FROM {content_translation}')->fetchAll(); $rows = db_query('SELECT * FROM {content_translation}')->fetchAll();
$this->assertEqual(2, count($rows)); foreach ($rows as $row) {
$this->assertEqual('taxonomy_term', $rows[0]->entity_type); $this->assertEqual('taxonomy_term', $row->entity_type);
$this->assertEqual('taxonomy_term', $rows[1]->entity_type); }
} }
/** /**
......
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