Update core 8.3.0

This commit is contained in:
Rob Davies 2017-04-13 15:53:35 +01:00
parent da7a7918f8
commit cd7a898e66
6144 changed files with 132297 additions and 87747 deletions

View file

@ -0,0 +1,38 @@
<?php
/**
* @file
* Helper module for the Content Translation tests.
*/
use \Drupal\Core\Form\FormStateInterface;
/**
* Implements hook_form_BASE_FORM_ID_alter().
*
* Adds a textfield to node forms based on a request parameter.
*/
function content_translation_test_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
$langcode = $form_state->getFormObject()->getFormLangcode($form_state);
if (in_array($langcode, ['en', 'fr']) && \Drupal::request()->get('test_field_only_en_fr')) {
$form['test_field_only_en_fr'] = [
'#type' => 'textfield',
'#title' => 'Field only available on the english and french form',
];
foreach (array_keys($form['actions']) as $action) {
if ($action != 'preview' && isset($form['actions'][$action]['#type']) && $form['actions'][$action]['#type'] === 'submit') {
$form['actions'][$action]['#submit'][] = 'content_translation_test_form_node_form_submit';
}
}
}
}
/**
* Form submission handler for custom field added based on a request parameter.
*
* @see content_translation_test_form_node_article_form_alter()
*/
function content_translation_test_form_node_form_submit($form, FormStateInterface $form_state) {
\Drupal::state()->set('test_field_only_en_fr', $form_state->getValue('test_field_only_en_fr'));
}

View file

@ -10,6 +10,14 @@ use Drupal\entity_test\Entity\EntityTest;
* @ContentEntityType(
* id = "entity_test_translatable_no_skip",
* label = @Translation("Test entity - Translatable check UI"),
* handlers = {
* "form" = {
* "default" = "Drupal\entity_test\EntityTestForm",
* },
* "route_provider" = {
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
* },
* },
* base_table = "entity_test_mul",
* data_table = "entity_test_mul_property_data",
* entity_keys = {
@ -20,6 +28,10 @@ use Drupal\entity_test\Entity\EntityTest;
* "langcode" = "langcode",
* },
* translatable = TRUE,
* admin_permission = "administer entity_test content",
* links = {
* "edit-form" = "/entity_test_translatable_no_skip/{entity_test_translatable_no_skip}/edit",
* },
* )
*/
class EntityTestTranslatableNoUISkip extends EntityTest {

View file

@ -0,0 +1,51 @@
<?php
namespace Drupal\Tests\content_translation\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the content translation behaviours on entity bundle UI.
*
* @group content_translation
*/
class ContentTranslationEntityBundleUITest extends BrowserTestBase {
public static $modules = ['language', 'content_translation', 'node', 'comment', 'field_ui'];
protected function setUp() {
parent::setUp();
$user = $this->drupalCreateUser(['access administration pages', 'administer languages', 'administer content translation', 'administer content types']);
$this->drupalLogin($user);
}
/**
* Tests content types default translation behaviour.
*/
public function testContentTypeUI() {
// Create first content type.
$this->drupalCreateContentType(['type' => 'article']);
// Enable content translation.
$edit = ['language_configuration[content_translation]' => TRUE];
$this->drupalPostForm('admin/structure/types/manage/article', $edit, 'Save content type');
// Make sure add page does not inherit translation configuration from first
// content type.
$this->drupalGet('admin/structure/types/add');
$this->assertNoFieldChecked('edit-language-configuration-content-translation');
// Create second content type and set content translation.
$edit = [
'name' => 'Page',
'type' => 'page',
'language_configuration[content_translation]' => TRUE,
];
$this->drupalPostForm('admin/structure/types/add', $edit, 'Save and manage fields');
// Make sure the settings are saved when creating the content type.
$this->drupalGet('admin/structure/types/manage/page');
$this->assertFieldChecked('edit-language-configuration-content-translation');
}
}

View file

@ -0,0 +1,137 @@
<?php
namespace Drupal\Tests\content_translation\Functional;
use Drupal\Tests\BrowserTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\entity_test\Entity\EntityTestMul;
use Drupal\content_translation_test\Entity\EntityTestTranslatableNoUISkip;
/**
* Tests whether canonical link tags are present for content entities.
*
* @group content_translation
*/
class ContentTranslationLinkTagTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['entity_test', 'content_translation', 'content_translation_test', 'language'];
/**
* The added languages.
*
* @var string[]
*/
protected $langcodes;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Set up user.
$user = $this->drupalCreateUser([
'view test entity',
'view test entity translations',
'administer entity_test content',
]);
$this->drupalLogin($user);
// Add additional languages.
$this->langcodes = ['it', 'fr'];
foreach ($this->langcodes as $langcode) {
ConfigurableLanguage::createFromLangcode($langcode)->save();
}
// Rebuild the container so that the new languages are picked up by services
// that hold a list of languages.
$this->rebuildContainer();
}
/**
* Create a test entity with translations.
*
* @return \Drupal\Core\Entity\EntityInterface
* An entity with translations.
*/
protected function createTranslatableEntity() {
$entity = EntityTestMul::create(['label' => $this->randomString()]);
// Create translations for non default languages.
foreach ($this->langcodes as $langcode) {
$entity->addTranslation($langcode, ['label' => $this->randomString()]);
}
$entity->save();
return $entity;
}
/**
* Tests alternate link tag found for entity types with canonical links.
*/
public function testCanonicalAlternateTags() {
/** @var \Drupal\Core\Language\LanguageManagerInterface $languageManager */
$languageManager = $this->container->get('language_manager');
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager */
$entityTypeManager = $this->container->get('entity_type.manager');
$definition = $entityTypeManager->getDefinition('entity_test_mul');
$this->assertTrue($definition->hasLinkTemplate('canonical'), 'Canonical link template found for entity_test.');
$entity = $this->createTranslatableEntity();
$url_base = $entity->toUrl('canonical')
->setAbsolute();
$langcodes_all = $this->langcodes;
$langcodes_all[] = $languageManager
->getDefaultLanguage()
->getId();
/** @var \Drupal\Core\Url[] $urls */
$urls = array_map(
function ($langcode) use ($url_base, $languageManager) {
$url = clone $url_base;
return $url
->setOption('language', $languageManager->getLanguage($langcode));
},
array_combine($langcodes_all, $langcodes_all)
);
// Ensure link tags for all languages are found on each language variation
// page of an entity.
foreach ($urls as $langcode => $url) {
$this->drupalGet($url);
foreach ($urls as $langcode_alternate => $url_alternate) {
$args = [':href' => $url_alternate->toString(), ':hreflang' => $langcode_alternate];
$links = $this->xpath('head/link[@rel = "alternate" and @href = :href and @hreflang = :hreflang]', $args);
$message = sprintf('The "%s" translation has the correct alternate hreflang link for "%s": %s.', $langcode, $langcode_alternate, $url->toString());
$this->assertTrue(isset($links[0]), $message);
}
}
}
/**
* Tests alternate link tag missing for entity types without canonical links.
*/
public function testCanonicalAlternateTagsMissing() {
/** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager */
$entityTypeManager = $this->container->get('entity_type.manager');
$definition = $entityTypeManager->getDefinition('entity_test_translatable_no_skip');
// Ensure 'canonical' link template does not exist, in case it is added in
// the future.
$this->assertFalse($definition->hasLinkTemplate('canonical'), 'Canonical link template does not exist for entity_test_translatable_no_skip entity.');
$entity = EntityTestTranslatableNoUISkip::create();
$entity->save();
$this->drupalGet($entity->toUrl('edit-form'));
$this->assertSession()->statusCodeEquals(200);
$result = $this->xpath('//link[@rel="alternate" and @hreflang]');
$this->assertFalse($result, 'No alternate link tag found.');
}
}

View file

@ -0,0 +1,144 @@
<?php
namespace Drupal\Tests\content_translation\Functional;
/**
* Tests the Content Translation metadata fields handling.
*
* @group content_translation
*/
class ContentTranslationMetadataFieldsTest extends ContentTranslationTestBase {
/**
* The entity type being tested.
*
* @var string
*/
protected $entityTypeId = 'node';
/**
* The bundle being tested.
*
* @var string
*/
protected $bundle = 'article';
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['language', 'content_translation', 'node'];
/**
* The profile to install as a basis for testing.
*
* @var string
*/
protected $profile = 'standard';
/**
* Tests skipping setting non translatable metadata fields.
*/
public function testSkipUntranslatable() {
$this->drupalLogin($this->translator);
$entity_manager = \Drupal::entityManager();
$fields = $entity_manager->getFieldDefinitions($this->entityTypeId, $this->bundle);
// Turn off translatability for the metadata fields on the current bundle.
$metadata_fields = ['created', 'changed', 'uid', 'status'];
foreach ($metadata_fields as $field_name) {
$fields[$field_name]
->getConfig($this->bundle)
->setTranslatable(FALSE)
->save();
}
// Create a new test entity with original values in the default language.
$default_langcode = $this->langcodes[0];
$entity_id = $this->createEntity(['title' => $this->randomString()], $default_langcode);
$storage = $entity_manager->getStorage($this->entityTypeId);
$storage->resetCache();
$entity = $storage->load($entity_id);
// Add a content translation.
$langcode = 'it';
$values = $entity->toArray();
// Apply a default value for the metadata fields.
foreach ($metadata_fields as $field_name) {
unset($values[$field_name]);
}
$entity->addTranslation($langcode, $values);
$metadata_source_translation = $this->manager->getTranslationMetadata($entity->getTranslation($default_langcode));
$metadata_target_translation = $this->manager->getTranslationMetadata($entity->getTranslation($langcode));
$created_time = $metadata_source_translation->getCreatedTime();
$changed_time = $metadata_source_translation->getChangedTime();
$published = $metadata_source_translation->isPublished();
$author = $metadata_source_translation->getAuthor();
$this->assertEqual($created_time, $metadata_target_translation->getCreatedTime(), 'Metadata created field has the same value for both translations.');
$this->assertEqual($changed_time, $metadata_target_translation->getChangedTime(), 'Metadata changed field has the same value for both translations.');
$this->assertEqual($published, $metadata_target_translation->isPublished(), 'Metadata published field has the same value for both translations.');
$this->assertEqual($author->id(), $metadata_target_translation->getAuthor()->id(), 'Metadata author field has the same value for both translations.');
$metadata_target_translation->setCreatedTime(time() + 50);
$metadata_target_translation->setChangedTime(time() + 50);
$metadata_target_translation->setPublished(TRUE);
$metadata_target_translation->setAuthor($this->editor);
$this->assertEqual($created_time, $metadata_target_translation->getCreatedTime(), 'Metadata created field correctly not updated');
$this->assertEqual($changed_time, $metadata_target_translation->getChangedTime(), 'Metadata changed field correctly not updated');
$this->assertEqual($published, $metadata_target_translation->isPublished(), 'Metadata published field correctly not updated');
$this->assertEqual($author->id(), $metadata_target_translation->getAuthor()->id(), 'Metadata author field correctly not updated');
}
/**
* Tests setting translatable metadata fields.
*/
public function testSetTranslatable() {
$this->drupalLogin($this->translator);
$entity_manager = \Drupal::entityManager();
$fields = $entity_manager->getFieldDefinitions($this->entityTypeId, $this->bundle);
// Turn off translatability for the metadata fields on the current bundle.
$metadata_fields = ['created', 'changed', 'uid', 'status'];
foreach ($metadata_fields as $field_name) {
$fields[$field_name]
->getConfig($this->bundle)
->setTranslatable(TRUE)
->save();
}
// Create a new test entity with original values in the default language.
$default_langcode = $this->langcodes[0];
$entity_id = $this->createEntity(['title' => $this->randomString(), 'status' => FALSE], $default_langcode);
$storage = $entity_manager->getStorage($this->entityTypeId);
$storage->resetCache();
$entity = $storage->load($entity_id);
// Add a content translation.
$langcode = 'it';
$values = $entity->toArray();
// Apply a default value for the metadata fields.
foreach ($metadata_fields as $field_name) {
unset($values[$field_name]);
}
$entity->addTranslation($langcode, $values);
$metadata_source_translation = $this->manager->getTranslationMetadata($entity->getTranslation($default_langcode));
$metadata_target_translation = $this->manager->getTranslationMetadata($entity->getTranslation($langcode));
$metadata_target_translation->setCreatedTime(time() + 50);
$metadata_target_translation->setChangedTime(time() + 50);
$metadata_target_translation->setPublished(TRUE);
$metadata_target_translation->setAuthor($this->editor);
$this->assertNotEqual($metadata_source_translation->getCreatedTime(), $metadata_target_translation->getCreatedTime(), 'Metadata created field correctly different on both translations.');
$this->assertNotEqual($metadata_source_translation->getChangedTime(), $metadata_target_translation->getChangedTime(), 'Metadata changed field correctly different on both translations.');
$this->assertNotEqual($metadata_source_translation->isPublished(), $metadata_target_translation->isPublished(), 'Metadata published field correctly different on both translations.');
$this->assertNotEqual($metadata_source_translation->getAuthor()->id(), $metadata_target_translation->getAuthor()->id(), 'Metadata author field correctly different on both translations.');
}
}

View file

@ -0,0 +1,157 @@
<?php
namespace Drupal\Tests\content_translation\Functional;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Tests\NodeTestBase;
use Drupal\user\Entity\Role;
/**
* Tests the content translation operations available in the content listing.
*
* @group content_translation
*/
class ContentTranslationOperationsTest extends NodeTestBase {
/**
* A base user.
*
* @var \Drupal\user\Entity\User|false
*/
protected $baseUser1;
/**
* A base user.
*
* @var \Drupal\user\Entity\User|false
*/
protected $baseUser2;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['language', 'content_translation', 'node', 'views', 'block'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Enable additional languages.
$langcodes = ['es', 'ast'];
foreach ($langcodes as $langcode) {
ConfigurableLanguage::createFromLangcode($langcode)->save();
}
// Enable translation for the current entity type and ensure the change is
// picked up.
\Drupal::service('content_translation.manager')->setEnabled('node', 'article', TRUE);
drupal_static_reset();
\Drupal::entityManager()->clearCachedDefinitions();
\Drupal::service('router.builder')->rebuild();
\Drupal::service('entity.definition_update_manager')->applyUpdates();
$this->baseUser1 = $this->drupalCreateUser(['access content overview']);
$this->baseUser2 = $this->drupalCreateUser(['access content overview', 'create content translations', 'update content translations', 'delete content translations']);
}
/**
* Test that the operation "Translate" is displayed in the content listing.
*/
public function testOperationTranslateLink() {
$node = $this->drupalCreateNode(['type' => 'article', 'langcode' => 'es']);
// Verify no translation operation links are displayed for users without
// permission.
$this->drupalLogin($this->baseUser1);
$this->drupalGet('admin/content');
$this->assertNoLinkByHref('node/' . $node->id() . '/translations');
$this->drupalLogout();
// Verify there's a translation operation link for users with enough
// permissions.
$this->drupalLogin($this->baseUser2);
$this->drupalGet('admin/content');
$this->assertLinkByHref('node/' . $node->id() . '/translations');
// Ensure that an unintended misconfiguration of permissions does not open
// access to the translation form, see https://www.drupal.org/node/2558905.
$this->drupalLogout();
user_role_change_permissions(
Role::AUTHENTICATED_ID,
[
'create content translations' => TRUE,
'access content' => FALSE,
]
);
$this->drupalLogin($this->baseUser1);
$this->drupalGet($node->urlInfo('drupal:content-translation-overview'));
$this->assertResponse(403);
// Ensure that the translation overview is also not accessible when the user
// has 'access content', but the node is not published.
user_role_change_permissions(
Role::AUTHENTICATED_ID,
[
'create content translations' => TRUE,
'access content' => TRUE,
]
);
$node->setPublished(FALSE)->save();
$this->drupalGet($node->urlInfo('drupal:content-translation-overview'));
$this->assertResponse(403);
$this->drupalLogout();
// Ensure the 'Translate' local task does not show up anymore when disabling
// translations for a content type.
$node->setPublished(TRUE)->save();
user_role_change_permissions(
Role::AUTHENTICATED_ID,
[
'administer content translation' => TRUE,
'administer languages' => TRUE,
]
);
$this->drupalPlaceBlock('local_tasks_block');
$this->drupalLogin($this->baseUser2);
$this->drupalGet('node/' . $node->id());
$this->assertLinkByHref('node/' . $node->id() . '/translations');
$this->drupalPostForm('admin/config/regional/content-language', ['settings[node][article][translatable]' => FALSE], t('Save configuration'));
$this->drupalGet('node/' . $node->id());
$this->assertNoLinkByHref('node/' . $node->id() . '/translations');
}
/**
* Tests the access to the overview page for translations.
*
* @see content_translation_translate_access()
*/
public function testContentTranslationOverviewAccess() {
$access_control_handler = \Drupal::entityManager()->getAccessControlHandler('node');
$user = $this->createUser(['create content translations', 'access content']);
$this->drupalLogin($user);
$node = $this->drupalCreateNode(['status' => FALSE, 'type' => 'article']);
$this->assertFalse(content_translation_translate_access($node)->isAllowed());
$access_control_handler->resetCache();
$node->setPublished(TRUE);
$node->save();
$this->assertTrue(content_translation_translate_access($node)->isAllowed());
$access_control_handler->resetCache();
user_role_change_permissions(
Role::AUTHENTICATED_ID,
[
'access content' => FALSE,
]
);
$user = $this->createUser(['create content translations']);
$this->drupalLogin($user);
$this->assertFalse(content_translation_translate_access($node)->isAllowed());
$access_control_handler->resetCache();
}
}

View file

@ -0,0 +1,84 @@
<?php
namespace Drupal\Tests\content_translation\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the Content translation settings using the standard profile.
*
* @group content_translation
*/
class ContentTranslationStandardFieldsTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'language',
'content_translation',
'node',
'comment',
'field_ui',
'entity_test',
];
/**
* {@inheritdoc}
*/
protected $profile = 'standard';
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$admin_user = $this->drupalCreateUser([
'access administration pages',
'administer languages',
'administer content translation',
'administer content types',
'administer node fields',
'administer comment fields',
'administer comments',
'administer comment types',
]);
$this->drupalLogin($admin_user);
}
/**
* Tests that translatable fields are being rendered.
*/
public function testFieldTranslatableArticle() {
$path = 'admin/config/regional/content-language';
$this->drupalGet($path);
// Check content block fields.
$this->assertFieldByXPath("//input[@id='edit-settings-block-content-basic-fields-body' and @checked='checked']");
// Check comment fields.
$this->assertFieldByXPath("//input[@id='edit-settings-comment-comment-fields-comment-body' and @checked='checked']");
// Check node fields.
$this->assertFieldByXPath("//input[@id='edit-settings-node-article-fields-comment' and @checked='checked']");
$this->assertFieldByXPath("//input[@id='edit-settings-node-article-fields-field-image' and @checked='checked']");
$this->assertFieldByXPath("//input[@id='edit-settings-node-article-fields-field-tags' and @checked='checked']");
// Check user fields.
$this->assertFieldByXPath("//input[@id='edit-settings-user-user-fields-user-picture' and @checked='checked']");
}
/**
* Test that revision_log is not translatable.
*/
public function testRevisionLogNotTranslatable() {
$path = 'admin/config/regional/content-language';
$this->drupalGet($path);
$this->assertNoFieldByXPath("//input[@id='edit-settings-node-article-fields-revision-log']");
}
}

View file

@ -0,0 +1,239 @@
<?php
namespace Drupal\Tests\content_translation\Functional;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
use Drupal\field\Entity\FieldConfig;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\BrowserTestBase;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Base class for content translation tests.
*/
abstract class ContentTranslationTestBase extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['text'];
/**
* The entity type being tested.
*
* @var string
*/
protected $entityTypeId = 'entity_test_mul';
/**
* The bundle being tested.
*
* @var string
*/
protected $bundle;
/**
* The added languages.
*
* @var array
*/
protected $langcodes;
/**
* The account to be used to test translation operations.
*
* @var \Drupal\user\UserInterface
*/
protected $translator;
/**
* The account to be used to test multilingual entity editing.
*
* @var \Drupal\user\UserInterface
*/
protected $editor;
/**
* The account to be used to test access to both workflows.
*
* @var \Drupal\user\UserInterface
*/
protected $administrator;
/**
* The name of the field used to test translation.
*
* @var string
*/
protected $fieldName;
/**
* The translation controller for the current entity type.
*
* @var \Drupal\content_translation\ContentTranslationHandlerInterface
*/
protected $controller;
/**
* @var \Drupal\content_translation\ContentTranslationManagerInterface
*/
protected $manager;
protected function setUp() {
parent::setUp();
$this->setupLanguages();
$this->setupBundle();
$this->enableTranslation();
$this->setupUsers();
$this->setupTestFields();
$this->manager = $this->container->get('content_translation.manager');
$this->controller = $this->manager->getTranslationHandler($this->entityTypeId);
// Rebuild the container so that the new languages are picked up by services
// that hold a list of languages.
$this->rebuildContainer();
}
/**
* Adds additional languages.
*/
protected function setupLanguages() {
$this->langcodes = ['it', 'fr'];
foreach ($this->langcodes as $langcode) {
ConfigurableLanguage::createFromLangcode($langcode)->save();
}
array_unshift($this->langcodes, \Drupal::languageManager()->getDefaultLanguage()->getId());
}
/**
* Returns an array of permissions needed for the translator.
*/
protected function getTranslatorPermissions() {
return array_filter([$this->getTranslatePermission(), 'create content translations', 'update content translations', 'delete content translations']);
}
/**
* Returns the translate permissions for the current entity and bundle.
*/
protected function getTranslatePermission() {
$entity_type = \Drupal::entityManager()->getDefinition($this->entityTypeId);
if ($permission_granularity = $entity_type->getPermissionGranularity()) {
return $permission_granularity == 'bundle' ? "translate {$this->bundle} {$this->entityTypeId}" : "translate {$this->entityTypeId}";
}
}
/**
* Returns an array of permissions needed for the editor.
*/
protected function getEditorPermissions() {
// Every entity-type-specific test needs to define these.
return [];
}
/**
* Returns an array of permissions needed for the administrator.
*/
protected function getAdministratorPermissions() {
return array_merge($this->getEditorPermissions(), $this->getTranslatorPermissions(), ['administer content translation']);
}
/**
* Creates and activates translator, editor and admin users.
*/
protected function setupUsers() {
$this->translator = $this->drupalCreateUser($this->getTranslatorPermissions(), 'translator');
$this->editor = $this->drupalCreateUser($this->getEditorPermissions(), 'editor');
$this->administrator = $this->drupalCreateUser($this->getAdministratorPermissions(), 'administrator');
$this->drupalLogin($this->translator);
}
/**
* Creates or initializes the bundle date if needed.
*/
protected function setupBundle() {
if (empty($this->bundle)) {
$this->bundle = $this->entityTypeId;
}
}
/**
* Enables translation for the current entity type and bundle.
*/
protected function enableTranslation() {
// Enable translation for the current entity type and ensure the change is
// picked up.
\Drupal::service('content_translation.manager')->setEnabled($this->entityTypeId, $this->bundle, TRUE);
drupal_static_reset();
\Drupal::entityManager()->clearCachedDefinitions();
\Drupal::service('router.builder')->rebuild();
\Drupal::service('entity.definition_update_manager')->applyUpdates();
}
/**
* Creates the test fields.
*/
protected function setupTestFields() {
if (empty($this->fieldName)) {
$this->fieldName = 'field_test_et_ui_test';
}
FieldStorageConfig::create([
'field_name' => $this->fieldName,
'type' => 'string',
'entity_type' => $this->entityTypeId,
'cardinality' => 1,
])->save();
FieldConfig::create([
'entity_type' => $this->entityTypeId,
'field_name' => $this->fieldName,
'bundle' => $this->bundle,
'label' => 'Test translatable text-field',
])->save();
entity_get_form_display($this->entityTypeId, $this->bundle, 'default')
->setComponent($this->fieldName, [
'type' => 'string_textfield',
'weight' => 0,
])
->save();
}
/**
* Creates the entity to be translated.
*
* @param array $values
* An array of initial values for the entity.
* @param string $langcode
* The initial language code of the entity.
* @param string $bundle_name
* (optional) The entity bundle, if the entity uses bundles. Defaults to
* NULL. If left NULL, $this->bundle will be used.
*
* @return string
* The entity id.
*/
protected function createEntity($values, $langcode, $bundle_name = NULL) {
$entity_values = $values;
$entity_values['langcode'] = $langcode;
$entity_type = \Drupal::entityManager()->getDefinition($this->entityTypeId);
if ($bundle_key = $entity_type->getKey('bundle')) {
$entity_values[$bundle_key] = $bundle_name ?: $this->bundle;
}
$controller = $this->container->get('entity.manager')->getStorage($this->entityTypeId);
if (!($controller instanceof SqlContentEntityStorage)) {
foreach ($values as $property => $value) {
if (is_array($value)) {
$entity_values[$property] = [$langcode => $value];
}
}
}
$entity = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId)
->create($entity_values);
$entity->save();
return $entity->id();
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\content_translation\Functional;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the content translation UI check skip.
*
* @group content_translation
*/
class ContentTranslationUISkipTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['content_translation_test', 'user', 'node'];
/**
* Tests the content_translation_ui_skip key functionality.
*/
public function testUICheckSkip() {
$admin_user = $this->drupalCreateUser([
'translate any entity',
'administer content translation',
'administer languages'
]);
$this->drupalLogin($admin_user);
// Visit the content translation.
$this->drupalGet('admin/config/regional/content-language');
// Check the message regarding UI integration.
$this->assertText('Test entity - Translatable skip UI check');
$this->assertText('Test entity - Translatable check UI (Translation is not supported)');
}
}

View file

@ -0,0 +1,627 @@
<?php
namespace Drupal\Tests\content_translation\Functional;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\EntityChangedInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Tests the Content Translation UI.
*/
abstract class ContentTranslationUITestBase extends ContentTranslationTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* The id of the entity being translated.
*
* @var mixed
*/
protected $entityId;
/**
* Whether the behavior of the language selector should be tested.
*
* @var bool
*/
protected $testLanguageSelector = TRUE;
/**
* Flag that tells whether the HTML escaping of all languages works or not
* after SafeMarkup change.
*
* @var bool
*/
protected $testHTMLEscapeForAllLanguages = FALSE;
/**
* Default cache contexts expected on a non-translated entity.
*
* Cache contexts will not be checked if this list is empty.
*
* @var string[]
*/
protected $defaultCacheContexts = ['languages:language_interface', 'theme', 'url.query_args:_wrapper_format', 'user.permissions'];
/**
* Tests the basic translation UI.
*/
public function testTranslationUI() {
$this->doTestBasicTranslation();
$this->doTestTranslationOverview();
$this->doTestOutdatedStatus();
$this->doTestPublishedStatus();
$this->doTestAuthoringInfo();
$this->doTestTranslationEdit();
$this->doTestTranslationChanged();
$this->doTestChangedTimeAfterSaveWithoutChanges();
$this->doTestTranslationDeletion();
}
/**
* Tests the basic translation workflow.
*/
protected function doTestBasicTranslation() {
// Create a new test entity with original values in the default language.
$default_langcode = $this->langcodes[0];
$values[$default_langcode] = $this->getNewEntityValues($default_langcode);
// Create the entity with the editor as owner, so that afterwards a new
// translation is created by the translator and the translation author is
// tested.
$this->drupalLogin($this->editor);
$this->entityId = $this->createEntity($values[$default_langcode], $default_langcode);
$this->drupalLogin($this->translator);
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->assertTrue($entity, 'Entity found in the database.');
$this->drupalGet($entity->urlInfo());
$this->assertResponse(200, 'Entity URL is valid.');
// Ensure that the content language cache context is not yet added to the
// page.
$this->assertCacheContexts($this->defaultCacheContexts);
$this->drupalGet($entity->urlInfo('drupal:content-translation-overview'));
$this->assertNoText('Source language', 'Source language column correctly hidden.');
$translation = $this->getTranslation($entity, $default_langcode);
foreach ($values[$default_langcode] as $property => $value) {
$stored_value = $this->getValue($translation, $property, $default_langcode);
$value = is_array($value) ? $value[0]['value'] : $value;
$message = format_string('@property correctly stored in the default language.', ['@property' => $property]);
$this->assertEqual($stored_value, $value, $message);
}
// Add a content translation.
$langcode = 'it';
$language = ConfigurableLanguage::load($langcode);
$values[$langcode] = $this->getNewEntityValues($langcode);
$entity_type_id = $entity->getEntityTypeId();
$add_url = Url::fromRoute("entity.$entity_type_id.content_translation_add", [
$entity->getEntityTypeId() => $entity->id(),
'source' => $default_langcode,
'target' => $langcode
], ['language' => $language]);
$this->drupalPostForm($add_url, $this->getEditValues($values, $langcode), $this->getFormSubmitActionForNewTranslation($entity, $langcode));
// Assert that HTML is escaped in "all languages" in UI after SafeMarkup
// change.
if ($this->testHTMLEscapeForAllLanguages) {
$this->assertNoRaw('&lt;span class=&quot;translation-entity-all-languages&quot;&gt;(all languages)&lt;/span&gt;');
$this->assertRaw('<span class="translation-entity-all-languages">(all languages)</span>');
}
// Ensure that the content language cache context is not yet added to the
// page.
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->drupalGet($entity->urlInfo());
$this->assertCacheContexts(Cache::mergeContexts(['languages:language_content'], $this->defaultCacheContexts));
// Reset the cache of the entity, so that the new translation gets the
// updated values.
$metadata_source_translation = $this->manager->getTranslationMetadata($entity->getTranslation($default_langcode));
$metadata_target_translation = $this->manager->getTranslationMetadata($entity->getTranslation($langcode));
$author_field_name = $entity->hasField('content_translation_uid') ? 'content_translation_uid' : 'uid';
if ($entity->getFieldDefinition($author_field_name)->isTranslatable()) {
$this->assertEqual($metadata_target_translation->getAuthor()->id(), $this->translator->id(),
SafeMarkup::format('Author of the target translation @langcode correctly stored for translatable owner field.', ['@langcode' => $langcode]));
$this->assertNotEqual($metadata_target_translation->getAuthor()->id(), $metadata_source_translation->getAuthor()->id(),
SafeMarkup::format('Author of the target translation @target different from the author of the source translation @source for translatable owner field.',
['@target' => $langcode, '@source' => $default_langcode]));
}
else {
$this->assertEqual($metadata_target_translation->getAuthor()->id(), $this->editor->id(), 'Author of the entity remained untouched after translation for non translatable owner field.');
}
$created_field_name = $entity->hasField('content_translation_created') ? 'content_translation_created' : 'created';
if ($entity->getFieldDefinition($created_field_name)->isTranslatable()) {
$this->assertTrue($metadata_target_translation->getCreatedTime() > $metadata_source_translation->getCreatedTime(),
SafeMarkup::format('Translation creation timestamp of the target translation @target is newer than the creation timestamp of the source translation @source for translatable created field.',
['@target' => $langcode, '@source' => $default_langcode]));
}
else {
$this->assertEqual($metadata_target_translation->getCreatedTime(), $metadata_source_translation->getCreatedTime(), 'Creation timestamp of the entity remained untouched after translation for non translatable created field.');
}
if ($this->testLanguageSelector) {
$this->assertNoFieldByXPath('//select[@id="edit-langcode-0-value"]', NULL, 'Language selector correctly disabled on translations.');
}
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->drupalGet($entity->urlInfo('drupal:content-translation-overview'));
$this->assertNoText('Source language', 'Source language column correctly hidden.');
// Switch the source language.
$langcode = 'fr';
$language = ConfigurableLanguage::load($langcode);
$source_langcode = 'it';
$edit = ['source_langcode[source]' => $source_langcode];
$entity_type_id = $entity->getEntityTypeId();
$add_url = Url::fromRoute("entity.$entity_type_id.content_translation_add", [
$entity->getEntityTypeId() => $entity->id(),
'source' => $default_langcode,
'target' => $langcode
], ['language' => $language]);
// This does not save anything, it merely reloads the form and fills in the
// fields with the values from the different source language.
$this->drupalPostForm($add_url, $edit, t('Change'));
$this->assertFieldByXPath("//input[@name=\"{$this->fieldName}[0][value]\"]", $values[$source_langcode][$this->fieldName][0]['value'], 'Source language correctly switched.');
// Add another translation and mark the other ones as outdated.
$values[$langcode] = $this->getNewEntityValues($langcode);
$edit = $this->getEditValues($values, $langcode) + ['content_translation[retranslate]' => TRUE];
$entity_type_id = $entity->getEntityTypeId();
$add_url = Url::fromRoute("entity.$entity_type_id.content_translation_add", [
$entity->getEntityTypeId() => $entity->id(),
'source' => $source_langcode,
'target' => $langcode
], ['language' => $language]);
$this->drupalPostForm($add_url, $edit, $this->getFormSubmitActionForNewTranslation($entity, $langcode));
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->drupalGet($entity->urlInfo('drupal:content-translation-overview'));
$this->assertText('Source language', 'Source language column correctly shown.');
// Check that the entered values have been correctly stored.
foreach ($values as $langcode => $property_values) {
$translation = $this->getTranslation($entity, $langcode);
foreach ($property_values as $property => $value) {
$stored_value = $this->getValue($translation, $property, $langcode);
$value = is_array($value) ? $value[0]['value'] : $value;
$message = format_string('%property correctly stored with language %language.', ['%property' => $property, '%language' => $langcode]);
$this->assertEqual($stored_value, $value, $message);
}
}
}
/**
* Tests that the translation overview shows the correct values.
*/
protected function doTestTranslationOverview() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$translate_url = $entity->urlInfo('drupal:content-translation-overview');
$this->drupalGet($translate_url);
$translate_url->setAbsolute(FALSE);
foreach ($this->langcodes as $langcode) {
if ($entity->hasTranslation($langcode)) {
$language = new Language(['id' => $langcode]);
$view_url = $entity->url('canonical', ['language' => $language]);
$elements = $this->xpath('//table//a[@href=:href]', [':href' => $view_url]);
$this->assertEqual((string) $elements[0], $entity->getTranslation($langcode)->label(), format_string('Label correctly shown for %language translation.', ['%language' => $langcode]));
$edit_path = $entity->url('edit-form', ['language' => $language]);
$elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a[@href=:href]', [':href' => $edit_path]);
$this->assertEqual((string) $elements[0], t('Edit'), format_string('Edit link correct for %language translation.', ['%language' => $langcode]));
}
}
}
/**
* Tests up-to-date status tracking.
*/
protected function doTestOutdatedStatus() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$langcode = 'fr';
$languages = \Drupal::languageManager()->getLanguages();
// Mark translations as outdated.
$edit = ['content_translation[retranslate]' => TRUE];
$edit_path = $entity->urlInfo('edit-form', ['language' => $languages[$langcode]]);
$this->drupalPostForm($edit_path, $edit, $this->getFormSubmitAction($entity, $langcode));
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
// Check that every translation has the correct "outdated" status, and that
// the Translation fieldset is open if the translation is "outdated".
foreach ($this->langcodes as $added_langcode) {
$url = $entity->urlInfo('edit-form', ['language' => ConfigurableLanguage::load($added_langcode)]);
$this->drupalGet($url);
if ($added_langcode == $langcode) {
$this->assertFieldByXPath('//input[@name="content_translation[retranslate]"]', FALSE, 'The retranslate flag is not checked by default.');
$this->assertFalse($this->xpath('//details[@id="edit-content-translation" and @open="open"]'), 'The translation tab should be collapsed by default.');
}
else {
$this->assertFieldByXPath('//input[@name="content_translation[outdated]"]', TRUE, 'The translate flag is checked by default.');
$this->assertTrue($this->xpath('//details[@id="edit-content-translation" and @open="open"]'), 'The translation tab is correctly expanded when the translation is outdated.');
$edit = ['content_translation[outdated]' => FALSE];
$this->drupalPostForm($url, $edit, $this->getFormSubmitAction($entity, $added_langcode));
$this->drupalGet($url);
$this->assertFieldByXPath('//input[@name="content_translation[retranslate]"]', FALSE, 'The retranslate flag is now shown.');
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->assertFalse($this->manager->getTranslationMetadata($entity->getTranslation($added_langcode))->isOutdated(), 'The "outdated" status has been correctly stored.');
}
}
}
/**
* Tests the translation publishing status.
*/
protected function doTestPublishedStatus() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
// Unpublish translations.
foreach ($this->langcodes as $index => $langcode) {
if ($index > 0) {
$url = $entity->urlInfo('edit-form', ['language' => ConfigurableLanguage::load($langcode)]);
$edit = ['content_translation[status]' => FALSE];
$this->drupalPostForm($url, $edit, $this->getFormSubmitAction($entity, $langcode));
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->assertFalse($this->manager->getTranslationMetadata($entity->getTranslation($langcode))->isPublished(), 'The translation has been correctly unpublished.');
}
}
// Check that the last published translation cannot be unpublished.
$this->drupalGet($entity->urlInfo('edit-form'));
$this->assertFieldByXPath('//input[@name="content_translation[status]" and @disabled="disabled"]', TRUE, 'The last translation is published and cannot be unpublished.');
}
/**
* Tests the translation authoring information.
*/
protected function doTestAuthoringInfo() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$values = [];
// Post different authoring information for each translation.
foreach ($this->langcodes as $index => $langcode) {
$user = $this->drupalCreateUser();
$values[$langcode] = [
'uid' => $user->id(),
'created' => REQUEST_TIME - mt_rand(0, 1000),
];
$edit = [
'content_translation[uid]' => $user->getUsername(),
'content_translation[created]' => format_date($values[$langcode]['created'], 'custom', 'Y-m-d H:i:s O'),
];
$url = $entity->urlInfo('edit-form', ['language' => ConfigurableLanguage::load($langcode)]);
$this->drupalPostForm($url, $edit, $this->getFormSubmitAction($entity, $langcode));
}
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
foreach ($this->langcodes as $langcode) {
$metadata = $this->manager->getTranslationMetadata($entity->getTranslation($langcode));
$this->assertEqual($metadata->getAuthor()->id(), $values[$langcode]['uid'], 'Translation author correctly stored.');
$this->assertEqual($metadata->getCreatedTime(), $values[$langcode]['created'], 'Translation date correctly stored.');
}
// Try to post non valid values and check that they are rejected.
$langcode = 'en';
$edit = [
// User names have by default length 8.
'content_translation[uid]' => $this->randomMachineName(12),
'content_translation[created]' => '19/11/1978',
];
$this->drupalPostForm($entity->urlInfo('edit-form'), $edit, $this->getFormSubmitAction($entity, $langcode));
$this->assertTrue($this->xpath('//div[contains(@class, "error")]//ul'), 'Invalid values generate a list of form errors.');
$metadata = $this->manager->getTranslationMetadata($entity->getTranslation($langcode));
$this->assertEqual($metadata->getAuthor()->id(), $values[$langcode]['uid'], 'Translation author correctly kept.');
$this->assertEqual($metadata->getCreatedTime(), $values[$langcode]['created'], 'Translation date correctly kept.');
}
/**
* Tests translation deletion.
*/
protected function doTestTranslationDeletion() {
// Confirm and delete a translation.
$this->drupalLogin($this->translator);
$langcode = 'fr';
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$language = ConfigurableLanguage::load($langcode);
$url = $entity->urlInfo('edit-form', ['language' => $language]);
$this->drupalPostForm($url, [], t('Delete translation'));
$this->drupalPostForm(NULL, [], t('Delete @language translation', ['@language' => $language->getName()]));
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId, TRUE);
if ($this->assertTrue(is_object($entity), 'Entity found')) {
$translations = $entity->getTranslationLanguages();
$this->assertTrue(count($translations) == 2 && empty($translations[$langcode]), 'Translation successfully deleted.');
}
// Check that the translator cannot delete the original translation.
$args = [$this->entityTypeId => $entity->id(), 'language' => 'en'];
$this->drupalGet(Url::fromRoute("entity.$this->entityTypeId.content_translation_delete", $args));
$this->assertResponse(403);
}
/**
* Returns an array of entity field values to be tested.
*/
protected function getNewEntityValues($langcode) {
return [$this->fieldName => [['value' => $this->randomMachineName(16)]]];
}
/**
* Returns an edit array containing the values to be posted.
*/
protected function getEditValues($values, $langcode, $new = FALSE) {
$edit = $values[$langcode];
$langcode = $new ? LanguageInterface::LANGCODE_NOT_SPECIFIED : $langcode;
foreach ($values[$langcode] as $property => $value) {
if (is_array($value)) {
$edit["{$property}[0][value]"] = $value[0]['value'];
unset($edit[$property]);
}
}
return $edit;
}
/**
* Returns the form action value when submitting a new translation.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being tested.
* @param string $langcode
* Language code for the form.
*
* @return string
* Name of the button to hit.
*/
protected function getFormSubmitActionForNewTranslation(EntityInterface $entity, $langcode) {
$entity->addTranslation($langcode, $entity->toArray());
return $this->getFormSubmitAction($entity, $langcode);
}
/**
* Returns the form action value to be used to submit the entity form.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being tested.
* @param string $langcode
* Language code for the form.
*
* @return string
* Name of the button to hit.
*/
protected function getFormSubmitAction(EntityInterface $entity, $langcode) {
return t('Save') . $this->getFormSubmitSuffix($entity, $langcode);
}
/**
* Returns appropriate submit button suffix based on translatability.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being tested.
* @param string $langcode
* Language code for the form.
*
* @return string
* Submit button suffix based on translatability.
*/
protected function getFormSubmitSuffix(EntityInterface $entity, $langcode) {
return '';
}
/**
* Returns the translation object to use to retrieve the translated values.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being tested.
* @param string $langcode
* The language code identifying the translation to be retrieved.
*
* @return \Drupal\Core\TypedData\TranslatableInterface
* The translation object to act on.
*/
protected function getTranslation(EntityInterface $entity, $langcode) {
return $entity->getTranslation($langcode);
}
/**
* Returns the value for the specified property in the given language.
*
* @param \Drupal\Core\Entity\EntityInterface $translation
* The translation object the property value should be retrieved from.
* @param string $property
* The property name.
* @param string $langcode
* The property value.
*
* @return
* The property value.
*/
protected function getValue(EntityInterface $translation, $property, $langcode) {
$key = $property == 'user_id' ? 'target_id' : 'value';
return $translation->get($property)->{$key};
}
/**
* Returns the name of the field that implements the changed timestamp.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being tested.
*
* @return string
* The field name.
*/
protected function getChangedFieldName($entity) {
return $entity->hasField('content_translation_changed') ? 'content_translation_changed' : 'changed';
}
/**
* Tests edit content translation.
*/
protected function doTestTranslationEdit() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$languages = $this->container->get('language_manager')->getLanguages();
foreach ($this->langcodes as $langcode) {
// We only want to test the title for non-english translations.
if ($langcode != 'en') {
$options = ['language' => $languages[$langcode]];
$url = $entity->urlInfo('edit-form', $options);
$this->drupalGet($url);
$this->assertRaw($entity->getTranslation($langcode)->label());
}
}
}
/**
* Tests the basic translation workflow.
*/
protected function doTestTranslationChanged() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$changed_field_name = $this->getChangedFieldName($entity);
$definition = $entity->getFieldDefinition($changed_field_name);
$config = $definition->getConfig($entity->bundle());
foreach ([FALSE, TRUE] as $translatable_changed_field) {
if ($definition->isTranslatable()) {
// For entities defining a translatable changed field we want to test
// the correct behavior of that field even if the translatability is
// revoked. In that case the changed timestamp should be synchronized
// across all translations.
$config->setTranslatable($translatable_changed_field);
$config->save();
}
elseif ($translatable_changed_field) {
// For entities defining a non-translatable changed field we cannot
// declare the field as translatable on the fly by modifying its config
// because the schema doesn't support this.
break;
}
foreach ($entity->getTranslationLanguages() as $language) {
// Ensure different timestamps.
sleep(1);
$langcode = $language->getId();
$edit = [
$this->fieldName . '[0][value]' => $this->randomString(),
];
$edit_path = $entity->urlInfo('edit-form', ['language' => $language]);
$this->drupalPostForm($edit_path, $edit, $this->getFormSubmitAction($entity, $langcode));
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->assertEqual(
$entity->getChangedTimeAcrossTranslations(), $entity->getTranslation($langcode)->getChangedTime(),
format_string('Changed time for language %language is the latest change over all languages.', ['%language' => $language->getName()])
);
}
$timestamps = [];
foreach ($entity->getTranslationLanguages() as $language) {
$next_timestamp = $entity->getTranslation($language->getId())->getChangedTime();
if (!in_array($next_timestamp, $timestamps)) {
$timestamps[] = $next_timestamp;
}
}
if ($translatable_changed_field) {
$this->assertEqual(
count($timestamps), count($entity->getTranslationLanguages()),
'All timestamps from all languages are different.'
);
}
else {
$this->assertEqual(
count($timestamps), 1,
'All timestamps from all languages are identical.'
);
}
}
}
/**
* Test the changed time after API and FORM save without changes.
*/
public function doTestChangedTimeAfterSaveWithoutChanges() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
// Test only entities, which implement the EntityChangedInterface.
if ($entity instanceof EntityChangedInterface) {
$changed_timestamp = $entity->getChangedTime();
$entity->save();
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->assertEqual($changed_timestamp, $entity->getChangedTime(), 'The entity\'s changed time wasn\'t updated after API save without changes.');
// Ensure different save timestamps.
sleep(1);
// Save the entity on the regular edit form.
$language = $entity->language();
$edit_path = $entity->urlInfo('edit-form', ['language' => $language]);
$this->drupalPostForm($edit_path, [], $this->getFormSubmitAction($entity, $language->getId()));
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$this->assertNotEqual($changed_timestamp, $entity->getChangedTime(), 'The entity\'s changed time was updated after form save without changes.');
}
}
}

View file

@ -25,7 +25,7 @@ class ContentTranslationConfigImportTest extends KernelTestBase {
*
* @var array
*/
public static $modules = array('system', 'user', 'entity_test', 'language', 'content_translation');
public static $modules = ['system', 'user', 'entity_test', 'language', 'content_translation'];
/**
* {@inheritdoc}
@ -58,7 +58,7 @@ class ContentTranslationConfigImportTest extends KernelTestBase {
/**
* Tests config import updates.
*/
function testConfigImportUpdates() {
public function testConfigImportUpdates() {
$entity_type_id = 'entity_test_mul';
$config_id = $entity_type_id . '.' . $entity_type_id;
$config_name = 'language.content_settings.' . $config_id;
@ -69,22 +69,22 @@ class ContentTranslationConfigImportTest extends KernelTestBase {
$this->assertIdentical($storage->exists($config_name), FALSE, $config_name . ' not found.');
// Create new config entity.
$data = array(
$data = [
'uuid' => 'a019d89b-c4d9-4ed4-b859-894e4e2e93cf',
'langcode' => 'en',
'status' => TRUE,
'dependencies' => array(
'module' => array('content_translation')
),
'dependencies' => [
'module' => ['content_translation']
],
'id' => $config_id,
'target_entity_type_id' => 'entity_test_mul',
'target_bundle' => 'entity_test_mul',
'default_langcode' => 'site_default',
'language_alterable' => FALSE,
'third_party_settings' => array(
'content_translation' => array('enabled' => TRUE),
),
);
'third_party_settings' => [
'content_translation' => ['enabled' => TRUE],
],
];
$sync->write($config_name, $data);
$this->assertIdentical($sync->exists($config_name), TRUE, $config_name . ' found.');

View file

@ -16,7 +16,7 @@ class ContentTranslationSettingsApiTest extends KernelTestBase {
*
* @var array
*/
public static $modules = array('language', 'content_translation', 'user', 'entity_test');
public static $modules = ['language', 'content_translation', 'user', 'entity_test'];
/**
* {@inheritdoc}
@ -29,7 +29,7 @@ class ContentTranslationSettingsApiTest extends KernelTestBase {
/**
* Tests that enabling translation via the API triggers schema updates.
*/
function testSettingsApi() {
public function testSettingsApi() {
$this->container->get('content_translation.manager')->setEnabled('entity_test_mul', 'entity_test_mul', TRUE);
$result =
db_field_exists('entity_test_mul_property_data', 'content_translation_source') &&

View file

@ -54,17 +54,17 @@ class ContentTranslationSyncUnitTest extends KernelTestBase {
*/
protected $unchangedFieldValues;
public static $modules = array('language', 'content_translation');
public static $modules = ['language', 'content_translation'];
protected function setUp() {
parent::setUp();
$this->synchronizer = new FieldTranslationSynchronizer($this->container->get('entity.manager'));
$this->synchronized = array('sync1', 'sync2');
$this->columns = array_merge($this->synchronized, array('var1', 'var2'));
$this->langcodes = array('en', 'it', 'fr', 'de', 'es');
$this->synchronized = ['sync1', 'sync2'];
$this->columns = array_merge($this->synchronized, ['var1', 'var2']);
$this->langcodes = ['en', 'it', 'fr', 'de', 'es'];
$this->cardinality = 4;
$this->unchangedFieldValues = array();
$this->unchangedFieldValues = [];
// Set up an initial set of values in the correct state, that is with
// "synchronized" values being equal.
@ -88,7 +88,7 @@ class ContentTranslationSyncUnitTest extends KernelTestBase {
$sync_langcode = $this->langcodes[2];
$unchanged_items = $this->unchangedFieldValues[$sync_langcode];
$field_values = $this->unchangedFieldValues;
$item = array();
$item = [];
foreach ($this->columns as $column) {
$item[$column] = $this->randomMachineName();
}
@ -140,7 +140,7 @@ class ContentTranslationSyncUnitTest extends KernelTestBase {
$sync_langcode = $this->langcodes[3];
$unchanged_items = $this->unchangedFieldValues[$sync_langcode];
$field_values = $this->unchangedFieldValues;
$field_values[$sync_langcode] = array();
$field_values[$sync_langcode] = [];
// Scramble the items.
foreach ($unchanged_items as $delta => $item) {
$new_delta = ($delta + 1) % $this->cardinality;
@ -179,7 +179,7 @@ class ContentTranslationSyncUnitTest extends KernelTestBase {
// Determine whether the unchanged values should be altered depending on
// their delta.
$delta_callbacks = array(
$delta_callbacks = [
// Continuous field values: all values are equal.
function($delta) { return TRUE; },
// Alternated field values: only the even ones are equal.
@ -188,7 +188,7 @@ class ContentTranslationSyncUnitTest extends KernelTestBase {
function($delta) { return $delta === 1 || $delta === 2; },
// Sparse field values: only the "extreme" ones are equal.
function($delta) { return $delta === 0 || $delta === 3; },
);
];
foreach ($delta_callbacks as $delta_callback) {
$field_values = $this->unchangedFieldValues;

View file

@ -69,18 +69,18 @@ class ContentTranslationManageAccessCheckTest extends UnitTestCase {
$language_manager->expects($this->at(0))
->method('getLanguage')
->with($this->equalTo($source))
->will($this->returnValue(new Language(array('id' => 'en'))));
->will($this->returnValue(new Language(['id' => 'en'])));
$language_manager->expects($this->at(1))
->method('getLanguages')
->will($this->returnValue(array('en' => array(), 'it' => array())));
->will($this->returnValue(['en' => [], 'it' => []]));
$language_manager->expects($this->at(2))
->method('getLanguage')
->with($this->equalTo($source))
->will($this->returnValue(new Language(array('id' => 'en'))));
->will($this->returnValue(new Language(['id' => 'en'])));
$language_manager->expects($this->at(3))
->method('getLanguage')
->with($this->equalTo($target))
->will($this->returnValue(new Language(array('id' => 'it'))));
->will($this->returnValue(new Language(['id' => 'it'])));
// Set the mock entity. We need to use ContentEntityBase for mocking due to
// issues with phpunit and multiple interfaces.
@ -92,7 +92,7 @@ class ContentTranslationManageAccessCheckTest extends UnitTestCase {
$entity->expects($this->once())
->method('getTranslationLanguages')
->with()
->will($this->returnValue(array()));
->will($this->returnValue([]));
$entity->expects($this->once())
->method('getCacheContexts')
->willReturn([]);
@ -101,10 +101,10 @@ class ContentTranslationManageAccessCheckTest extends UnitTestCase {
->willReturn(Cache::PERMANENT);
$entity->expects($this->once())
->method('getCacheTags')
->will($this->returnValue(array('node:1337')));
->will($this->returnValue(['node:1337']));
$entity->expects($this->once())
->method('getCacheContexts')
->willReturn(array());
->willReturn([]);
// Set the route requirements.
$route = new Route('test_route');

View file

@ -12,25 +12,25 @@ use Drupal\Tests\Core\Menu\LocalTaskIntegrationTestBase;
class ContentTranslationLocalTasksTest extends LocalTaskIntegrationTestBase {
protected function setUp() {
$this->directoryList = array(
$this->directoryList = [
'content_translation' => 'core/modules/content_translation',
'node' => 'core/modules/node',
);
];
parent::setUp();
$entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
$entity_type->expects($this->any())
->method('getLinkTemplate')
->will($this->returnValueMap(array(
array('canonical', 'entity.node.canonical'),
array('drupal:content-translation-overview', 'entity.node.content_translation_overview'),
)));
->will($this->returnValueMap([
['canonical', 'entity.node.canonical'],
['drupal:content-translation-overview', 'entity.node.content_translation_overview'],
]));
$content_translation_manager = $this->getMock('Drupal\content_translation\ContentTranslationManagerInterface');
$content_translation_manager->expects($this->any())
->method('getSupportedEntityTypes')
->will($this->returnValue(array(
->will($this->returnValue([
'node' => $entity_type,
)));
]));
\Drupal::getContainer()->set('content_translation.manager', $content_translation_manager);
\Drupal::getContainer()->set('string_translation', $this->getStringTranslationStub());
}
@ -48,22 +48,22 @@ class ContentTranslationLocalTasksTest extends LocalTaskIntegrationTestBase {
* Provides a list of routes to test.
*/
public function providerTestBlockAdminDisplay() {
return array(
array('entity.node.canonical', array(array(
return [
['entity.node.canonical', [[
'content_translation.local_tasks:entity.node.content_translation_overview',
'entity.node.canonical',
'entity.node.edit_form',
'entity.node.delete_form',
'entity.node.version_history',
))),
array('entity.node.content_translation_overview', array(array(
]]],
['entity.node.content_translation_overview', [[
'content_translation.local_tasks:entity.node.content_translation_overview',
'entity.node.canonical',
'entity.node.edit_form',
'entity.node.delete_form',
'entity.node.version_history',
))),
);
]]],
];
}
}