Issue #1807776 by plach, Berdir, YesCT, Gábor Hojtsy, bforchhammer, Bojhan, webchick: Support both simple and editorial workflows for translating entities.
parent
afeed9ed44
commit
ae9f336ed3
|
@ -120,6 +120,11 @@ use Drupal\Core\Cache\CacheBackendInterface;
|
|||
* entity.
|
||||
* - menu_path_wildcard: (optional) A string identifying the menu loader in the
|
||||
* router path.
|
||||
* - permission_granularity: (optional) Specifies whether a module exposing
|
||||
* permissions for the current entity type should use entity-type level
|
||||
* granularity, bundle level granularity or just skip this entity. The allowed
|
||||
* values are respectively "entity_type", "bundle" or FALSE. Defaults to
|
||||
* "entity_type".
|
||||
*
|
||||
* The defaults for the plugin definition are provided in
|
||||
* \Drupal\Core\Entity\EntityManager::defaults.
|
||||
|
@ -159,6 +164,7 @@ class EntityManager extends PluginManagerBase {
|
|||
'access_controller_class' => 'Drupal\Core\Entity\EntityAccessController',
|
||||
'static_cache' => TRUE,
|
||||
'translation' => array(),
|
||||
'permission_granularity' => 'entity_type',
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,12 +9,29 @@
|
|||
namespace Drupal\comment;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\translation_entity\EntityTranslationController;
|
||||
use Drupal\translation_entity\EntityTranslationControllerNG;
|
||||
|
||||
/**
|
||||
* Defines the translation controller class for comments.
|
||||
*/
|
||||
class CommentTranslationController extends EntityTranslationController {
|
||||
class CommentTranslationController extends EntityTranslationControllerNG {
|
||||
|
||||
/**
|
||||
* Overrides EntityTranslationController::getAccess().
|
||||
*/
|
||||
public function getAccess(EntityInterface $entity, $op) {
|
||||
switch ($op) {
|
||||
case 'view':
|
||||
return user_access('access comments');
|
||||
case 'update':
|
||||
return comment_access('edit', $entity);
|
||||
case 'delete':
|
||||
return user_access('administer comments');
|
||||
case 'create':
|
||||
return user_access('post comments');
|
||||
}
|
||||
return parent::getAccess($entity, $op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides EntityTranslationController::entityFormTitle().
|
||||
|
|
|
@ -25,7 +25,7 @@ use Drupal\Core\Annotation\Translation;
|
|||
* form_controller_class = {
|
||||
* "default" = "Drupal\comment\CommentFormController"
|
||||
* },
|
||||
* translation_controller_class = "Drupal\translation_entity\EntityTranslationControllerNG",
|
||||
* translation_controller_class = "Drupal\comment\CommentTranslationController",
|
||||
* base_table = "comment",
|
||||
* uri_callback = "comment_uri",
|
||||
* fieldable = TRUE,
|
||||
|
|
|
@ -34,9 +34,6 @@ class CommentTranslationUITest extends EntityTranslationUITest {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\simpletest\WebTestBase::setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
$this->entityType = 'comment';
|
||||
$this->nodeBundle = 'article';
|
||||
|
@ -58,7 +55,7 @@ class CommentTranslationUITest extends EntityTranslationUITest {
|
|||
* Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
|
||||
*/
|
||||
function getTranslatorPermissions() {
|
||||
return array('post comments', 'administer comments', "translate $this->entityType entities", 'edit original values');
|
||||
return array_merge(parent::getTranslatorPermissions(), array('post comments', 'administer comments'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,7 +97,7 @@ class CommentTranslationUITest extends EntityTranslationUITest {
|
|||
*/
|
||||
function testTranslateLinkCommentAdminPage() {
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'page'));
|
||||
$this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer comments', 'translate any entity'));
|
||||
$this->admin_user = $this->drupalCreateUser(array_merge(parent::getTranslatorPermissions(), array('access administration pages', 'administer comments')));
|
||||
$this->drupalLogin($this->admin_user);
|
||||
|
||||
$cid_translatable = $this->createEntity(array(), $this->langcodes[0], $this->nodeBundle);
|
||||
|
|
|
@ -336,7 +336,7 @@ class NodeFormController extends EntityFormController {
|
|||
}
|
||||
|
||||
$element['preview'] = array(
|
||||
'#access' => $preview_mode != DRUPAL_DISABLED,
|
||||
'#access' => $preview_mode != DRUPAL_DISABLED && (node_access('create', $node) || node_access('update', $node)),
|
||||
'#value' => t('Preview'),
|
||||
'#weight' => 20,
|
||||
'#validate' => array(
|
||||
|
@ -429,6 +429,9 @@ class NodeFormController extends EntityFormController {
|
|||
* A reference to a keyed array containing the current state of the form.
|
||||
*/
|
||||
public function preview(array $form, array &$form_state) {
|
||||
// @todo Remove this: we should not have explicit includes in autoloaded
|
||||
// classes.
|
||||
module_load_include('inc', 'node', 'node.pages');
|
||||
drupal_set_title(t('Preview'), PASS_THROUGH);
|
||||
$form_state['node_preview'] = node_preview($this->getEntity($form_state));
|
||||
$form_state['rebuild'] = TRUE;
|
||||
|
|
|
@ -39,7 +39,8 @@ use Drupal\Core\Annotation\Translation;
|
|||
* },
|
||||
* bundle_keys = {
|
||||
* "bundle" = "type"
|
||||
* }
|
||||
* },
|
||||
* permission_granularity = "bundle"
|
||||
* )
|
||||
*/
|
||||
class Node extends Entity implements ContentEntityInterface {
|
||||
|
|
|
@ -34,9 +34,6 @@ class NodeTranslationUITest extends EntityTranslationUITest {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\simpletest\WebTestBase::setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
$this->entityType = 'node';
|
||||
$this->bundle = 'article';
|
||||
|
@ -56,7 +53,7 @@ class NodeTranslationUITest extends EntityTranslationUITest {
|
|||
* Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
|
||||
*/
|
||||
function getTranslatorPermissions() {
|
||||
return array("edit any $this->bundle content", "translate $this->entityType entities", 'edit original values');
|
||||
return array_merge(parent::getTranslatorPermissions(), array("edit any $this->bundle content"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,7 +77,7 @@ class NodeTranslationUITest extends EntityTranslationUITest {
|
|||
* Tests field translation form.
|
||||
*/
|
||||
function testFieldTranslationForm() {
|
||||
$admin_user = $this->drupalCreateUser(array('translate any entity', 'access administration pages', 'bypass node access', 'administer node fields'));
|
||||
$admin_user = $this->drupalCreateUser(array_merge($this->getTranslatorPermissions(), array('access administration pages', 'bypass node access', 'administer node fields')));
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
$article = $this->drupalCreateNode(array('type' => 'article', 'langcode' => 'en'));
|
||||
|
|
|
@ -462,12 +462,14 @@ abstract class WebTestBase extends TestBase {
|
|||
* @param array $permissions
|
||||
* Array of permission names to assign to user. Note that the user always
|
||||
* has the default permissions derived from the "authenticated users" role.
|
||||
* @param $name
|
||||
* The user name.
|
||||
*
|
||||
* @return object|false
|
||||
* A fully loaded user object with pass_raw property, or FALSE if account
|
||||
* creation fails.
|
||||
*/
|
||||
protected function drupalCreateUser(array $permissions = array()) {
|
||||
protected function drupalCreateUser(array $permissions = array(), $name = NULL) {
|
||||
// Create a role with the given permission set, if any.
|
||||
$rid = FALSE;
|
||||
if ($permissions) {
|
||||
|
@ -479,7 +481,7 @@ abstract class WebTestBase extends TestBase {
|
|||
|
||||
// Create a user assigned to that role.
|
||||
$edit = array();
|
||||
$edit['name'] = $this->randomName();
|
||||
$edit['name'] = !empty($name) ? $name : $this->randomName();
|
||||
$edit['mail'] = $edit['name'] . '@example.com';
|
||||
$edit['pass'] = user_password();
|
||||
$edit['status'] = 1;
|
||||
|
|
|
@ -68,12 +68,12 @@ class EntityAccessTest extends WebTestBase {
|
|||
'view' => TRUE,
|
||||
), $entity);
|
||||
|
||||
// The custom user is not allowed to view test entities.
|
||||
// The custom user is not allowed to perform any operation on test entities.
|
||||
$custom_user = $this->drupalCreateUser();
|
||||
$this->assertEntityAccess(array(
|
||||
'create' => TRUE,
|
||||
'update' => TRUE,
|
||||
'delete' => TRUE,
|
||||
'create' => FALSE,
|
||||
'update' => FALSE,
|
||||
'delete' => FALSE,
|
||||
'view' => FALSE,
|
||||
), $entity, $custom_user);
|
||||
}
|
||||
|
|
|
@ -30,21 +30,21 @@ class EntityTestAccessController implements EntityAccessControllerInterface {
|
|||
* Implements \Drupal\Core\Entity\EntityAccessControllerInterface::createAccess().
|
||||
*/
|
||||
public function createAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
|
||||
return TRUE;
|
||||
return user_access('administer entity_test content', $account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Entity\EntityAccessControllerInterface::updateAccess().
|
||||
*/
|
||||
public function updateAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
|
||||
return TRUE;
|
||||
return user_access('administer entity_test content', $account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\Core\Entity\EntityAccessControllerInterface::deleteAccess().
|
||||
*/
|
||||
public function deleteAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
|
||||
return TRUE;
|
||||
return user_access('administer entity_test content', $account);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ use Drupal\Core\Annotation\Translation;
|
|||
* bundle_keys = {
|
||||
* "bundle" = "vid"
|
||||
* },
|
||||
* menu_base_path = "taxonomy/term/%taxonomy_term"
|
||||
* menu_base_path = "taxonomy/term/%taxonomy_term",
|
||||
* permission_granularity = "bundle"
|
||||
* )
|
||||
*/
|
||||
class Term extends Entity implements ContentEntityInterface {
|
||||
|
|
|
@ -15,6 +15,20 @@ use Drupal\translation_entity\EntityTranslationController;
|
|||
*/
|
||||
class TermTranslationController extends EntityTranslationController {
|
||||
|
||||
/**
|
||||
* Overrides EntityTranslationController::getAccess().
|
||||
*/
|
||||
public function getAccess(EntityInterface $entity, $op) {
|
||||
switch ($op) {
|
||||
case 'create':
|
||||
case 'update':
|
||||
return taxonomy_term_access('edit', $entity);
|
||||
case 'delete':
|
||||
return taxonomy_term_access('delete', $entity);
|
||||
}
|
||||
return parent::getAccess($entity, $op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides EntityTranslationController::entityFormAlter().
|
||||
*/
|
||||
|
|
|
@ -41,9 +41,6 @@ class TermTranslationUITest extends EntityTranslationUITest {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\simpletest\WebTestBase::setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
$this->entityType = 'taxonomy_term';
|
||||
$this->bundle = 'tags';
|
||||
|
@ -73,7 +70,7 @@ class TermTranslationUITest extends EntityTranslationUITest {
|
|||
* Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
|
||||
*/
|
||||
function getTranslatorPermissions() {
|
||||
return array('administer taxonomy', "translate $this->entityType entities", 'edit original values');
|
||||
return array_merge(parent::getTranslatorPermissions(), array('administer taxonomy'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,7 +99,7 @@ class TermTranslationUITest extends EntityTranslationUITest {
|
|||
* Tests translate link on vocabulary term list.
|
||||
*/
|
||||
function testTranslateLinkVocabularyAdminPage() {
|
||||
$this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer taxonomy', 'translate any entity'));
|
||||
$this->admin_user = $this->drupalCreateUser(array_merge(parent::getTranslatorPermissions(), array('access administration pages', 'administer taxonomy')));
|
||||
$this->drupalLogin($this->admin_user);
|
||||
|
||||
$translatable_tid = $this->createEntity(array(), $this->langcodes[0], $this->vocabulary->id());
|
||||
|
|
|
@ -99,9 +99,17 @@ class EntityTranslationController implements EntityTranslationControllerInterfac
|
|||
/**
|
||||
* Implements EntityTranslationControllerInterface::getTranslationAccess().
|
||||
*/
|
||||
public function getTranslationAccess(EntityInterface $entity, $langcode) {
|
||||
$entity_type = $entity->entityType();
|
||||
return (user_access('translate any entity') || user_access("translate $entity_type entities")) && ($langcode != $entity->language()->langcode || user_access('edit original values'));
|
||||
public function getTranslationAccess(EntityInterface $entity, $op) {
|
||||
// @todo Move this logic into a translation access controller checking also
|
||||
// the translation language and the given account.
|
||||
$info = $entity->entityInfo();
|
||||
$translate_permission = TRUE;
|
||||
// If no permission granularity is defined this entity type does not need an
|
||||
// explicit translate permission.
|
||||
if (!user_access('translate any entity') && !empty($info['permission_granularity'])) {
|
||||
$translate_permission = user_access($info['permission_granularity'] == 'bundle' ? "translate {$entity->bundle()} {$entity->entityType()}" : "translate {$entity->entityType()}");
|
||||
}
|
||||
return $translate_permission && user_access("$op entity translations");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -203,6 +211,7 @@ class EntityTranslationController implements EntityTranslationControllerInterfac
|
|||
'#value' => t('Delete translation'),
|
||||
'#weight' => $weight,
|
||||
'#submit' => array(array($this, 'entityFormDeleteTranslation')),
|
||||
'#access' => $this->getTranslationAccess($entity, 'delete'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -220,7 +229,7 @@ class EntityTranslationController implements EntityTranslationControllerInterfac
|
|||
'#collapsed' => TRUE,
|
||||
'#tree' => TRUE,
|
||||
'#weight' => 10,
|
||||
'#access' => $this->getTranslationAccess($entity, $form_langcode),
|
||||
'#access' => $this->getTranslationAccess($entity, $source_langcode ? 'create' : 'update'),
|
||||
'#multilingual' => TRUE,
|
||||
);
|
||||
|
||||
|
@ -259,17 +268,11 @@ class EntityTranslationController implements EntityTranslationControllerInterfac
|
|||
}
|
||||
|
||||
/**
|
||||
* Process callback: Determines which elements get clue in the form.
|
||||
*
|
||||
* @param array $element
|
||||
* Form API element.
|
||||
*
|
||||
* @return array
|
||||
* A processed element with the shared elements marked with a clue.
|
||||
* Process callback: determines which elements get clue in the form.
|
||||
*
|
||||
* @see \Drupal\translation_entity\EntityTranslationController::entityFormAlter()
|
||||
*/
|
||||
public function entityFormSharedElements($element) {
|
||||
public function entityFormSharedElements($element, $form_state, $form) {
|
||||
static $ignored_types;
|
||||
|
||||
// @todo Find a more reliable way to determine if a form element concerns a
|
||||
|
@ -280,7 +283,7 @@ class EntityTranslationController implements EntityTranslationControllerInterfac
|
|||
|
||||
foreach (element_children($element) as $key) {
|
||||
if (!isset($element[$key]['#type'])) {
|
||||
$this->entityFormSharedElements($element[$key]);
|
||||
$this->entityFormSharedElements($element[$key], $form_state, $form);
|
||||
}
|
||||
else {
|
||||
// Ignore non-widget form elements.
|
||||
|
@ -289,7 +292,15 @@ class EntityTranslationController implements EntityTranslationControllerInterfac
|
|||
}
|
||||
// Elements are considered to be non multilingual by default.
|
||||
if (empty($element[$key]['#multilingual'])) {
|
||||
$this->addTranslatabilityClue($element[$key]);
|
||||
// If we are displaying a multilingual entity form we need to provide
|
||||
// translatability clues, otherwise the shared form elements should be
|
||||
// hidden.
|
||||
if (empty($form_state['translation_entity']['translation_form'])) {
|
||||
$this->addTranslatabilityClue($element[$key]);
|
||||
}
|
||||
else {
|
||||
$element[$key]['#access'] = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,17 +132,21 @@ interface EntityTranslationControllerInterface {
|
|||
public function getAccess(EntityInterface $entity, $op);
|
||||
|
||||
/**
|
||||
* Checks if a user is allowed to edit the given translation.
|
||||
* Checks if the user can perform the given operation on translations of the
|
||||
* wrapped entity.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity whose translation has to be accessed.
|
||||
* @param string $langcode
|
||||
* The language code identifying the translation to be accessed.
|
||||
* @param $op
|
||||
* The operation to be performed on the translation. Possible values are:
|
||||
* - "create"
|
||||
* - "update"
|
||||
* - "delete"
|
||||
*
|
||||
* @return boolean
|
||||
* TRUE if the operation may be performed, FALSE otherwise.
|
||||
*/
|
||||
public function getTranslationAccess(EntityInterface $entity, $langcode);
|
||||
public function getTranslationAccess(EntityInterface $entity, $op);
|
||||
|
||||
/**
|
||||
* Retrieves the source language for the translation being created.
|
||||
|
|
|
@ -15,7 +15,14 @@ use Drupal\Core\Entity\EntityInterface;
|
|||
class EntityTranslationControllerNG extends EntityTranslationController {
|
||||
|
||||
/**
|
||||
* Overrides EntityTranslationController::removeTranslation().
|
||||
* Overrides \Drupal\translation_entity\EntityTranslationController::getAccess().
|
||||
*/
|
||||
public function getAccess(EntityInterface $entity, $op) {
|
||||
return $entity->access($op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\translation_entity\EntityTranslationControllerInterface::removeTranslation().
|
||||
*/
|
||||
public function removeTranslation(EntityInterface $entity, $langcode) {
|
||||
$translation = $entity->getTranslation($langcode);
|
||||
|
@ -23,4 +30,5 @@ class EntityTranslationControllerNG extends EntityTranslationController {
|
|||
$translation->$property_name = array();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,21 +29,11 @@ class ConfigTestTranslationUITest extends EntityTranslationUITest {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\simpletest\WebTestBase::setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
$this->entityType = 'config_test';
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
|
||||
*/
|
||||
function getTranslatorPermissions() {
|
||||
return array("translate $this->entityType entities", 'edit original values');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getNewEntityValues().
|
||||
*/
|
||||
|
|
|
@ -21,7 +21,7 @@ class EntityTestTranslationUITest extends EntityTranslationUITest {
|
|||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity Test Translation UI',
|
||||
'name' => 'Entity Test translation UI',
|
||||
'description' => 'Tests the test entity translation UI with the test entity.',
|
||||
'group' => 'Entity Translation UI',
|
||||
);
|
||||
|
@ -40,7 +40,7 @@ class EntityTestTranslationUITest extends EntityTranslationUITest {
|
|||
* Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
|
||||
*/
|
||||
function getTranslatorPermissions() {
|
||||
return array('administer entity_test content', "translate $this->entityType entities", 'edit original values');
|
||||
return array_merge(parent::getTranslatorPermissions(), array('administer entity_test content'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\entity\Tests\EntityTranslationTestBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\translation_entity\Tests;
|
||||
|
||||
use Drupal\Core\Entity\DatabaseStorageControllerNG;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests entity translation workflows.
|
||||
*/
|
||||
abstract class EntityTranslationTestBase extends WebTestBase {
|
||||
|
||||
/**
|
||||
* The entity type being tested.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityType = 'entity_test_mul';
|
||||
|
||||
/**
|
||||
* The bundle being tested.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $bundle;
|
||||
|
||||
/**
|
||||
* The enabled languages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $langcodes;
|
||||
|
||||
/**
|
||||
* The account to be used to test translation operations.
|
||||
*
|
||||
* @var \Drupal\user\Plugin\Core\Entity\User
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
/**
|
||||
* The account to be used to test multilingual entity editing.
|
||||
*
|
||||
* @var \Drupal\user\Plugin\Core\Entity\User
|
||||
*/
|
||||
protected $editor;
|
||||
|
||||
/**
|
||||
* The account to be used to test access to both workflows.
|
||||
*
|
||||
* @var \Drupal\user\Plugin\Core\Entity\User
|
||||
*/
|
||||
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\translation_entity\EntityTranslationControllerInterface
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->setupLanguages();
|
||||
$this->setupBundle();
|
||||
$this->enableTranslation();
|
||||
$this->setupUsers();
|
||||
$this->setupTestFields();
|
||||
|
||||
$this->controller = translation_entity_controller($this->entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables additional languages.
|
||||
*/
|
||||
protected function setupLanguages() {
|
||||
$this->langcodes = array('it', 'fr');
|
||||
foreach ($this->langcodes as $langcode) {
|
||||
language_save(new Language(array('langcode' => $langcode)));
|
||||
}
|
||||
array_unshift($this->langcodes, language_default()->langcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of permissions needed for the translator.
|
||||
*/
|
||||
protected function getTranslatorPermissions() {
|
||||
return array_filter(array($this->getTranslatePermission(), 'create entity translations', 'update entity translations', 'delete entity translations'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the translate permissions for the current entity and bundle.
|
||||
*/
|
||||
protected function getTranslatePermission() {
|
||||
$info = entity_get_info($this->entityType);
|
||||
if (!empty($info['permission_granularity'])) {
|
||||
return $info['permission_granularity'] == 'bundle' ? "translate {$this->bundle} {$this->entityType}" : "translate {$this->entityType}";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of permissions needed for the editor.
|
||||
*/
|
||||
protected function getEditorPermissions() {
|
||||
// Every entity-type-specific test needs to define these.
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(array_merge($this->getEditorPermissions(), $this->getTranslatorPermissions()), 'administrator');
|
||||
$this->drupalLogin($this->translator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or initializes the bundle date if needed.
|
||||
*/
|
||||
protected function setupBundle() {
|
||||
if (empty($this->bundle)) {
|
||||
$this->bundle = $this->entityType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
translation_entity_set_config($this->entityType, $this->bundle, 'enabled', TRUE);
|
||||
drupal_static_reset();
|
||||
entity_info_cache_clear();
|
||||
menu_router_rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the test fields.
|
||||
*/
|
||||
protected function setupTestFields() {
|
||||
$this->fieldName = 'field_test_et_ui_test';
|
||||
|
||||
$field = array(
|
||||
'field_name' => $this->fieldName,
|
||||
'type' => 'text',
|
||||
'cardinality' => 1,
|
||||
'translatable' => TRUE,
|
||||
);
|
||||
field_create_field($field);
|
||||
|
||||
$instance = array(
|
||||
'entity_type' => $this->entityType,
|
||||
'field_name' => $this->fieldName,
|
||||
'bundle' => $this->bundle,
|
||||
'label' => 'Test translatable text-field',
|
||||
'widget' => array(
|
||||
'type' => 'text_textfield',
|
||||
'weight' => 0,
|
||||
),
|
||||
);
|
||||
field_create_instance($instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* The entity id.
|
||||
*/
|
||||
protected function createEntity($values, $langcode, $bundle_name = NULL) {
|
||||
$entity_values = $values;
|
||||
$entity_values['langcode'] = $langcode;
|
||||
$info = entity_get_info($this->entityType);
|
||||
if (!empty($info['entity_keys']['bundle'])) {
|
||||
$entity_values[$info['entity_keys']['bundle']] = $bundle_name ?: $this->bundle;
|
||||
}
|
||||
$controller = $this->container->get('plugin.manager.entity')->getStorageController($this->entityType);
|
||||
if (!($controller instanceof DatabaseStorageControllerNG)) {
|
||||
foreach ($values as $property => $value) {
|
||||
if (is_array($value)) {
|
||||
$entity_values[$property] = array($langcode => $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
$entity = entity_create($this->entityType, $entity_values);
|
||||
$entity->save();
|
||||
return $entity->id();
|
||||
}
|
||||
|
||||
}
|
|
@ -7,45 +7,14 @@
|
|||
|
||||
namespace Drupal\translation_entity\Tests;
|
||||
|
||||
use Drupal\Core\Entity\DatabaseStorageControllerNG;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityNG;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the Entity Translation UI.
|
||||
*/
|
||||
abstract class EntityTranslationUITest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* The enabled languages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $langcodes;
|
||||
|
||||
/**
|
||||
* The entity type being tested.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The bundle being tested.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $bundle;
|
||||
|
||||
/**
|
||||
* The name of the field used to test translation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fieldName;
|
||||
abstract class EntityTranslationUITest extends EntityTranslationTestBase {
|
||||
|
||||
/**
|
||||
* Whether the behavior of the language selector should be tested.
|
||||
|
@ -54,92 +23,6 @@ abstract class EntityTranslationUITest extends WebTestBase {
|
|||
*/
|
||||
protected $testLanguageSelector = TRUE;
|
||||
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\simpletest\WebTestBase::setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->setupLanguages();
|
||||
$this->setupBundle();
|
||||
$this->enableTranslation();
|
||||
$this->setupTranslator();
|
||||
$this->setupTestFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables additional languages.
|
||||
*/
|
||||
protected function setupLanguages() {
|
||||
$this->langcodes = array('it', 'fr');
|
||||
foreach ($this->langcodes as $langcode) {
|
||||
language_save(new Language(array('langcode' => $langcode)));
|
||||
}
|
||||
array_unshift($this->langcodes, language_default()->langcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or initializes the bundle date if needed.
|
||||
*/
|
||||
protected function setupBundle() {
|
||||
if (empty($this->bundle)) {
|
||||
$this->bundle = $this->entityType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
translation_entity_set_config($this->entityType, $this->bundle, 'enabled', TRUE);
|
||||
drupal_static_reset();
|
||||
entity_info_cache_clear();
|
||||
menu_router_rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of permissions needed for the translator.
|
||||
*/
|
||||
abstract function getTranslatorPermissions();
|
||||
|
||||
/**
|
||||
* Creates and activates a translator user.
|
||||
*/
|
||||
protected function setupTranslator() {
|
||||
$translator = $this->drupalCreateUser($this->getTranslatorPermissions());
|
||||
$this->drupalLogin($translator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the test fields.
|
||||
*/
|
||||
protected function setupTestFields() {
|
||||
$this->fieldName = 'field_test_et_ui_test';
|
||||
|
||||
$field = array(
|
||||
'field_name' => $this->fieldName,
|
||||
'type' => 'text',
|
||||
'cardinality' => 1,
|
||||
'translatable' => TRUE,
|
||||
);
|
||||
field_create_field($field);
|
||||
|
||||
$instance = array(
|
||||
'entity_type' => $this->entityType,
|
||||
'field_name' => $this->fieldName,
|
||||
'bundle' => $this->bundle,
|
||||
'label' => 'Test translatable text-field',
|
||||
'widget' => array(
|
||||
'type' => 'text_textfield',
|
||||
'weight' => 0,
|
||||
),
|
||||
);
|
||||
field_create_instance($instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the basic translation UI.
|
||||
*/
|
||||
|
@ -163,8 +46,7 @@ abstract class EntityTranslationUITest extends WebTestBase {
|
|||
$langcode = 'it';
|
||||
$values[$langcode] = $this->getNewEntityValues($langcode);
|
||||
|
||||
$controller = translation_entity_controller($this->entityType);
|
||||
$base_path = $controller->getBasePath($entity);
|
||||
$base_path = $this->controller->getBasePath($entity);
|
||||
$path = $langcode . '/' . $base_path . '/translations/add/' . $default_langcode . '/' . $langcode;
|
||||
$this->drupalPost($path, $this->getEditValues($values, $langcode), t('Save'));
|
||||
if ($this->testLanguageSelector) {
|
||||
|
@ -200,7 +82,7 @@ abstract class EntityTranslationUITest extends WebTestBase {
|
|||
// Check that every translation has the correct "outdated" status.
|
||||
foreach ($this->langcodes as $enabled_langcode) {
|
||||
$prefix = $enabled_langcode != $default_langcode ? $enabled_langcode . '/' : '';
|
||||
$path = $prefix . $controller->getEditPath($entity);
|
||||
$path = $prefix . $this->controller->getEditPath($entity);
|
||||
$this->drupalGet($path);
|
||||
if ($enabled_langcode == $langcode) {
|
||||
$this->assertFieldByXPath('//input[@name="translation[retranslate]"]', FALSE, 'The retranslate flag is not checked by default.');
|
||||
|
@ -226,40 +108,6 @@ abstract class EntityTranslationUITest extends WebTestBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* The entity id.
|
||||
*/
|
||||
protected function createEntity($values, $langcode, $bundle_name = NULL) {
|
||||
$entity_values = $values;
|
||||
$entity_values['langcode'] = $langcode;
|
||||
$info = entity_get_info($this->entityType);
|
||||
if (!empty($info['entity_keys']['bundle'])) {
|
||||
$entity_values[$info['entity_keys']['bundle']] = $bundle_name ?: $this->bundle;
|
||||
}
|
||||
$controller = $this->container->get('plugin.manager.entity')->getStorageController($this->entityType);
|
||||
if (!($controller instanceof DatabaseStorageControllerNG)) {
|
||||
foreach ($values as $property => $value) {
|
||||
if (is_array($value)) {
|
||||
$entity_values[$property] = array($langcode => $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
$entity = entity_create($this->entityType, $entity_values);
|
||||
$entity->save();
|
||||
return $entity->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of entity field values to be tested.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\entity\Tests\EntityTranslationWorkflowsTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\translation_entity\Tests;
|
||||
|
||||
use Drupal\user\Plugin\Core\Entity\User;
|
||||
|
||||
/**
|
||||
* Tests entity translation workflows.
|
||||
*/
|
||||
class EntityTranslationWorkflowsTest extends EntityTranslationTestBase {
|
||||
|
||||
/**
|
||||
* The entity used for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('language', 'translation_entity', 'entity_test');
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity Test translation workflows',
|
||||
'description' => 'Tests the entity translation workflows for the test entity.',
|
||||
'group' => 'Entity Translation UI',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->setupEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\translation_entity\Tests\EntityTranslationTestBase::getEditorPermissions().
|
||||
*/
|
||||
protected function getEditorPermissions() {
|
||||
return array('administer entity_test content');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test entity and translate it.
|
||||
*/
|
||||
protected function setupEntity() {
|
||||
$default_langcode = $this->langcodes[0];
|
||||
|
||||
// Create a test entity.
|
||||
$values = array(
|
||||
'name' => $this->randomName(),
|
||||
'user_id' => mt_rand(1, 128),
|
||||
$this->fieldName => array(array('value' => $this->randomName(16))),
|
||||
);
|
||||
$id = $this->createEntity($values, $default_langcode);
|
||||
$this->entity = entity_load($this->entityType, $id, TRUE);
|
||||
|
||||
// Create a translation.
|
||||
$this->drupalLogin($this->translator);
|
||||
$add_translation_path = $this->controller->getBasePath($this->entity) . "/translations/add/$default_langcode/{$this->langcodes[2]}";
|
||||
$this->drupalPost($add_translation_path, array(), t('Save'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test simple and editorial translation workflows.
|
||||
*/
|
||||
function testWorkflows() {
|
||||
// Test workflows for the editor.
|
||||
$expected_status = array('edit' => 200, 'overview' => 403, 'add_translation' => 403, 'edit_translation' => 403);
|
||||
$this->assertWorkflows($this->editor, $expected_status);
|
||||
|
||||
// Test workflows for the translator.
|
||||
$expected_status = array('edit' => 403, 'overview' => 200, 'add_translation' => 200, 'edit_translation' => 200);
|
||||
$this->assertWorkflows($this->translator, $expected_status);
|
||||
|
||||
// Test workflows for the admin.
|
||||
$expected_status = array('edit' => 200, 'overview' => 200, 'add_translation' => 200, 'edit_translation' => 200);
|
||||
$this->assertWorkflows($this->administrator, $expected_status);
|
||||
|
||||
// Check that translation permissions governate the associated operations.
|
||||
$ops = array('create' => t('add'), 'update' => t('edit'), 'delete' => t('delete'));
|
||||
$translations_path = $this->controller->getBasePath($this->entity) . "/translations";
|
||||
foreach ($ops as $current_op => $label) {
|
||||
$user = $this->drupalCreateUser(array($this->getTranslatePermission(), "$current_op entity translations"));
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet($translations_path);
|
||||
|
||||
foreach ($ops as $op => $label) {
|
||||
if ($op != $current_op) {
|
||||
$this->assertNoLink($label, format_string('No %op link found.', array('%op' => $label)));
|
||||
}
|
||||
else {
|
||||
$this->assertLink($label, 0, format_string('%op link found.', array('%op' => $label)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that workflows have the expected behaviors for the given user.
|
||||
*
|
||||
* @param \Drupal\user\Plugin\Core\Entity\User $user
|
||||
* The user to test the workflow behavior against.
|
||||
* @param array $expected_status
|
||||
* The an associative array with the operation name as key and the expected
|
||||
* status as value.
|
||||
*/
|
||||
protected function assertWorkflows(User $user, $expected_status) {
|
||||
$default_langcode = $this->langcodes[0];
|
||||
$languages = language_list();
|
||||
$args = array('@user_label' => $user->name);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Check whether the user is allowed to access the entity form in edit mode.
|
||||
$edit_path = $this->controller->getEditPath($this->entity);
|
||||
$options = array('language' => $languages[$default_langcode]);
|
||||
$this->drupalGet($edit_path, $options);
|
||||
$this->assertResponse($expected_status['edit'], format_string('The @user_label has the expected edit access.', $args));
|
||||
|
||||
// Check whether the user is allowed to access the translation overview.
|
||||
$langcode = $this->langcodes[1];
|
||||
$translations_path = $this->controller->getBasePath($this->entity) . "/translations";
|
||||
$options = array('language' => $languages[$langcode]);
|
||||
$this->drupalGet($translations_path, $options);
|
||||
$this->assertResponse($expected_status['overview'], format_string('The @user_label has the expected translation overview access.', $args));
|
||||
|
||||
// Check whether the user is allowed to create a translation.
|
||||
$add_translation_path = $translations_path . "/add/$default_langcode/$langcode";
|
||||
if ($expected_status['add_translation'] == 200) {
|
||||
$this->clickLink('add');
|
||||
$this->assertUrl($add_translation_path, $options, 'The translation overview points to the translation form when creating translations.');
|
||||
// Check that the translation form does not contain shared elements for
|
||||
// translators.
|
||||
if ($expected_status['edit'] == 403) {
|
||||
$this->assertNoSharedElements();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->drupalGet($add_translation_path, $options);
|
||||
}
|
||||
$this->assertResponse($expected_status['add_translation'], format_string('The @user_label has the expected translation creation access.', $args));
|
||||
|
||||
// Check whether the user is allowed to edit a translation.
|
||||
$langcode = $this->langcodes[2];
|
||||
$edit_translation_path = $translations_path . "/edit/$langcode";
|
||||
$options = array('language' => $languages[$langcode]);
|
||||
if ($expected_status['edit_translation'] == 200) {
|
||||
$this->drupalGet($translations_path, $options);
|
||||
$editor = $expected_status['edit'] == 200;
|
||||
$this->clickLink('edit', intval($editor));
|
||||
|
||||
if ($editor) {
|
||||
// An editor should be pointed to the entity form in multilingual mode.
|
||||
$this->assertUrl($edit_path, $options, 'The translation overview points to the edit form for editors when editing translations.');
|
||||
}
|
||||
else {
|
||||
// While a translator should be pointed to the translation form.
|
||||
$this->assertUrl($edit_translation_path, $options, 'The translation overview points to the translation form for translators when editing translations.');
|
||||
// Check that the translation form does not contain shared elements.
|
||||
$this->assertNoSharedElements();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->drupalGet($edit_translation_path, $options);
|
||||
}
|
||||
$this->assertResponse($expected_status['edit_translation'], format_string('The @user_label has the expected translation creation access.', $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the current page does not contain shared form elements.
|
||||
*/
|
||||
protected function assertNoSharedElements() {
|
||||
$language_none = LANGUAGE_NOT_SPECIFIED;
|
||||
return $this->assertNoFieldByXPath("//input[@name='field_test_text[$language_none][0][value]']", NULL, 'Shared elements are not available on the translation form.');
|
||||
}
|
||||
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
namespace Drupal\translation_entity\Tests\Views;
|
||||
|
||||
use Drupal\views\Tests\ViewTestBase;
|
||||
use Drupal\translation_entity\Tests\EntityTranslationUITest;
|
||||
use Drupal\translation_entity\Tests\EntityTranslationTestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
||||
/**
|
||||
|
@ -16,7 +16,7 @@ use Drupal\views\Tests\ViewTestData;
|
|||
*
|
||||
* @see \Drupal\translation_entity\Plugin\views\field\TranslationLink
|
||||
*/
|
||||
class TranslationLinkTest extends EntityTranslationUITest {
|
||||
class TranslationLinkTest extends EntityTranslationTestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
|
@ -49,13 +49,6 @@ class TranslationLinkTest extends EntityTranslationUITest {
|
|||
ViewTestData::importTestViews(get_class($this), array('translation_entity_test_views'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
|
||||
*/
|
||||
function getTranslatorPermissions() {
|
||||
return array("translate $this->entityType entities", 'edit original values');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Entity translation overview link field handler.
|
||||
*/
|
||||
|
@ -65,12 +58,4 @@ class TranslationLinkTest extends EntityTranslationUITest {
|
|||
$this->assertNoLinkByHref('user/2/translations', 'The translations link is not present when translation_entity_translate_access() is FALSE.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::testTranslationUI().
|
||||
*/
|
||||
public function testTranslationUI() {
|
||||
// @todo \Drupal\translation_entity\Tests\EntityTranslationUITest contains
|
||||
// essential helper methods that should be seprarated from test methods.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -155,18 +155,37 @@ function translation_entity_menu() {
|
|||
'weight' => 2,
|
||||
) + $item;
|
||||
|
||||
$items["$path/translations/overview"] = array(
|
||||
'title' => 'Overview',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'weight' => 0,
|
||||
);
|
||||
|
||||
// Add translation callback.
|
||||
// @todo Add the access callback instead of replacing it as soon as the
|
||||
// routing system supports multiple callbacks.
|
||||
$add_path = "$path/translations/add/%language/%language";
|
||||
$language_position = $entity_position + 3;
|
||||
$args = array($entity_position, $language_position, $language_position + 1);
|
||||
$items[$add_path] = array(
|
||||
$items["$path/translations/add/%language/%language"] = array(
|
||||
'title' => 'Add',
|
||||
'page callback' => 'translation_entity_add_page',
|
||||
'page arguments' => $args,
|
||||
'access callback' => 'translation_entity_add_access',
|
||||
'access arguments' => $args,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 1,
|
||||
) + $item;
|
||||
|
||||
// Edit translation callback.
|
||||
$args = array($entity_position, $language_position);
|
||||
$items["$path/translations/edit/%language"] = array(
|
||||
'title' => 'Edit',
|
||||
'page callback' => 'translation_entity_edit_page',
|
||||
'page arguments' => $args,
|
||||
'access callback' => 'translation_entity_edit_access',
|
||||
'access arguments' => $args,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 1,
|
||||
) + $item;
|
||||
|
||||
// Delete translation callback.
|
||||
|
@ -174,6 +193,8 @@ function translation_entity_menu() {
|
|||
'title' => 'Delete',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('translation_entity_delete_confirm', $entity_position, $language_position),
|
||||
'access callback' => 'translation_entity_delete_access',
|
||||
'access arguments' => $args,
|
||||
) + $item;
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +278,10 @@ function _translation_entity_menu_strip_loaders($path) {
|
|||
*/
|
||||
function translation_entity_translate_access(EntityInterface $entity) {
|
||||
$entity_type = $entity->entityType();
|
||||
return empty($entity->language()->locked) && language_multilingual() && translation_entity_enabled($entity_type, $entity->bundle()) && (user_access('translate any entity') || user_access("translate $entity_type entities"));
|
||||
return empty($entity->language()->locked) &&
|
||||
language_multilingual() &&
|
||||
translation_entity_enabled($entity_type, $entity->bundle()) &&
|
||||
(user_access('create entity translations') || user_access('update entity translations') || user_access('delete entity translations'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -266,16 +290,50 @@ function translation_entity_translate_access(EntityInterface $entity) {
|
|||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity being translated.
|
||||
* @param \Drupal\Core\Language\Language $source
|
||||
* The language of the values being translated.
|
||||
* (optional) The language of the values being translated. Defaults to the
|
||||
* entity language.
|
||||
* @param \Drupal\Core\Language\Language $target
|
||||
* The language of the translated values.
|
||||
* (optional) The language of the translated values. Defaults to the current
|
||||
* content language.
|
||||
*/
|
||||
function translation_entity_add_access(EntityInterface $entity, Language $source = NULL, Language $target = NULL) {
|
||||
$source = !empty($source) ? $source : $entity->language();
|
||||
$target = !empty($target) ? $target : language(LANGUAGE_TYPE_CONTENT);
|
||||
$translations = $entity->getTranslationLanguages();
|
||||
$languages = language_list();
|
||||
return $source->langcode != $target->langcode && isset($languages[$source->langcode]) && isset($languages[$target->langcode]) && !isset($translations[$target->langcode]) && translation_entity_access($entity, $target->langcode);
|
||||
return $source->langcode != $target->langcode && isset($languages[$source->langcode]) && isset($languages[$target->langcode]) && !isset($translations[$target->langcode]) && translation_entity_access($entity, 'create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Access callback for the translation edit page.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity being translated.
|
||||
* @param \Drupal\Core\Language\Language $language
|
||||
* (optional) The language of the translated values. Defaults to the current
|
||||
* content language.
|
||||
*/
|
||||
function translation_entity_edit_access(EntityInterface $entity, Language $language = NULL) {
|
||||
$language = !empty($language) ? $language : language(LANGUAGE_TYPE_CONTENT);
|
||||
$translations = $entity->getTranslationLanguages();
|
||||
$languages = language_list();
|
||||
return isset($languages[$language->langcode]) && $language->langcode != $entity->language()->langcode && isset($translations[$language->langcode]) && translation_entity_access($entity, 'update');
|
||||
}
|
||||
|
||||
/**
|
||||
* Access callback for the translation delete page.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity being translated.
|
||||
* @param \Drupal\Core\Language\Language $language
|
||||
* (optional) The language of the translated values. Defaults to the current
|
||||
* content language.
|
||||
*/
|
||||
function translation_entity_delete_access(EntityInterface $entity, Language $language = NULL) {
|
||||
$language = !empty($language) ? $language : language(LANGUAGE_TYPE_CONTENT);
|
||||
$translations = $entity->getTranslationLanguages();
|
||||
$languages = language_list();
|
||||
return isset($languages[$language->langcode]) && $language->langcode != $entity->language()->langcode && isset($translations[$language->langcode]) && translation_entity_access($entity, 'delete');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -454,14 +512,18 @@ function translation_entity_form_controller(array $form_state) {
|
|||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity to be accessed.
|
||||
* @param string $langcode
|
||||
* The language of the translation to be accessed.
|
||||
* @param $op
|
||||
* The operation to be performed on the translation. Possible values are:
|
||||
* - "view"
|
||||
* - "update"
|
||||
* - "delete"
|
||||
* - "create"
|
||||
*
|
||||
* @return
|
||||
* TRUE if the current user is allowed to view the translation.
|
||||
*/
|
||||
function translation_entity_access(EntityInterface $entity, $langcode) {
|
||||
return translation_entity_controller($entity->entityType())->getTranslationAccess($entity, $langcode) ;
|
||||
function translation_entity_access(EntityInterface $entity, $op) {
|
||||
return translation_entity_controller($entity->entityType())->getTranslationAccess($entity, $op) ;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -469,27 +531,50 @@ function translation_entity_access(EntityInterface $entity, $langcode) {
|
|||
*/
|
||||
function translation_entity_permission() {
|
||||
$permission = array(
|
||||
'edit original values' => array(
|
||||
'title' => t('Edit original values'),
|
||||
'description' => t('Access the entity form in the original language.'),
|
||||
),
|
||||
'administer entity translation' => array(
|
||||
'title' => t('Administer entity translation'),
|
||||
'title' => t('Administer translation settings'),
|
||||
'description' => t('Configure translatability of entities and fields.'),
|
||||
),
|
||||
'create entity translations' => array(
|
||||
'title' => t('Create translations'),
|
||||
),
|
||||
'update entity translations' => array(
|
||||
'title' => t('Edit translations'),
|
||||
),
|
||||
'delete entity translations' => array(
|
||||
'title' => t('Delete translations'),
|
||||
),
|
||||
'translate any entity' => array(
|
||||
'title' => t('Translate any entity'),
|
||||
'description' => t('Translate field content for any fieldable entity.'),
|
||||
),
|
||||
);
|
||||
|
||||
// Create a translate permission for each enabled entity type and (optionally)
|
||||
// bundle.
|
||||
foreach (entity_get_info() as $entity_type => $info) {
|
||||
if (translation_entity_enabled($entity_type)) {
|
||||
$label = !empty($info['label']) ? t($info['label']) : $entity_type;
|
||||
$permission["translate $entity_type entities"] = array(
|
||||
'title' => t('Translate entities of type @type', array('@type' => $label)),
|
||||
'description' => t('Translate field content for entities of type @type.', array('@type' => $label)),
|
||||
);
|
||||
if (!empty($info['permission_granularity'])) {
|
||||
$t_args = array('@entity_label' => drupal_strtolower(t($info['label'])));
|
||||
|
||||
switch ($info['permission_granularity']) {
|
||||
case 'bundle':
|
||||
foreach (entity_get_bundles($entity_type) as $bundle => $bundle_info) {
|
||||
if (translation_entity_enabled($entity_type, $bundle)) {
|
||||
$t_args['%bundle_label'] = isset($info['bundles'][$bundle]['label']) ? $info['bundles'][$bundle]['label'] : $bundle;
|
||||
$permission["translate $bundle $entity_type"] = array(
|
||||
'title' => t('Translate %bundle_label @entity_label', $t_args),
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'entity_type':
|
||||
if (translation_entity_enabled($entity_type)) {
|
||||
$permission["translate $entity_type"] = array(
|
||||
'title' => t('Translate @entity_label', $t_args),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,11 +51,13 @@ function translation_entity_overview(EntityInterface $entity) {
|
|||
$language_name = $language->name;
|
||||
$langcode = $language->langcode;
|
||||
$add_path = $base_path . '/translations/add/' . $original . '/' . $langcode;
|
||||
$translate_path = $base_path . '/translations/edit/' . $langcode;
|
||||
$delete_path = $base_path . '/translations/delete/' . $langcode;
|
||||
|
||||
if ($base_path) {
|
||||
$add_links = _translation_entity_get_switch_links($add_path);
|
||||
$edit_links = _translation_entity_get_switch_links($edit_path);
|
||||
$translate_links = _translation_entity_get_switch_links($translate_path);
|
||||
$delete_links = _translation_entity_get_switch_links($delete_path);
|
||||
}
|
||||
|
||||
|
@ -80,8 +82,17 @@ function translation_entity_overview(EntityInterface $entity) {
|
|||
$row_title = $is_original ? $label : t('n/a');
|
||||
}
|
||||
|
||||
if ($edit_path && $controller->getAccess($entity, 'update') && $controller->getTranslationAccess($entity, $langcode)) {
|
||||
// If the user is allowed to edit the entity we point the edit link to
|
||||
// the entity form, otherwise if we are not dealing with the original
|
||||
// language we point the link to the translation form.
|
||||
if ($edit_path && $controller->getAccess($entity, 'update')) {
|
||||
$links['edit'] = isset($edit_links->links[$langcode]['href']) ? $edit_links->links[$langcode] : array('href' => $edit_path, 'language' => $language);
|
||||
}
|
||||
elseif (!$is_original && $controller->getTranslationAccess($entity, 'update')) {
|
||||
$links['edit'] = isset($translate_links->links[$langcode]['href']) ? $translate_links->links[$langcode] : array('href' => $translate_path, 'language' => $language);
|
||||
}
|
||||
|
||||
if (isset($links['edit'])) {
|
||||
$links['edit']['title'] = t('edit');
|
||||
}
|
||||
|
||||
|
@ -98,8 +109,10 @@ function translation_entity_overview(EntityInterface $entity) {
|
|||
}
|
||||
else {
|
||||
$source_name = isset($languages[$source]) ? $languages[$source]->name : t('n/a');
|
||||
$links['delete'] = isset($delete_links->links[$langcode]['href']) ? $delete_links->links[$langcode] : array('href' => $delete_links, 'language' => $language);
|
||||
$links['delete']['title'] = t('delete');
|
||||
if ($controller->getTranslationAccess($entity, 'delete')) {
|
||||
$links['delete'] = isset($delete_links->links[$langcode]['href']) ? $delete_links->links[$langcode] : array('href' => $delete_links, 'language' => $language);
|
||||
$links['delete']['title'] = t('delete');
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -107,7 +120,7 @@ function translation_entity_overview(EntityInterface $entity) {
|
|||
$row_title = $source_name = t('n/a');
|
||||
$source = $entity->language()->langcode;
|
||||
|
||||
if ($source != $langcode && $controller->getAccess($entity, 'update')) {
|
||||
if ($source != $langcode && $controller->getTranslationAccess($entity, 'create')) {
|
||||
if ($translatable) {
|
||||
$links['add'] = isset($add_links->links[$langcode]['href']) ? $add_links->links[$langcode] : array('href' => $add_path, 'language' => $language);
|
||||
$links['add']['title'] = t('add');
|
||||
|
@ -188,6 +201,30 @@ function translation_entity_add_page(EntityInterface $entity, Language $source =
|
|||
$form_state = entity_form_state_defaults($entity, $operation, $target->langcode);
|
||||
$form_state['translation_entity']['source'] = $source;
|
||||
$form_state['translation_entity']['target'] = $target;
|
||||
$controller = translation_entity_controller($entity->entityType());
|
||||
$form_state['translation_entity']['translation_form'] = !$controller->getAccess($entity, 'update');
|
||||
$form_id = entity_form_id($entity);
|
||||
return drupal_build_form($form_id, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback for the translation edit page.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity being translated.
|
||||
* @param \Drupal\Core\Language\Language $language
|
||||
* (optional) The language of the translated values. Defaults to the current
|
||||
* content language.
|
||||
*
|
||||
* @return array
|
||||
* A processed form array ready to be rendered.
|
||||
*/
|
||||
function translation_entity_edit_page(EntityInterface $entity, Language $language = NULL) {
|
||||
$language = !empty($language) ? $language : language(LANGUAGE_TYPE_CONTENT);
|
||||
$info = $entity->entityInfo();
|
||||
$operation = isset($info['default_operation']) ? $info['default_operation'] : 'default';
|
||||
$form_state = entity_form_state_defaults($entity, $operation, $language->langcode);
|
||||
$form_state['translation_entity']['translation_form'] = TRUE;
|
||||
$form_id = entity_form_id($entity);
|
||||
return drupal_build_form($form_id, $form_state);
|
||||
}
|
||||
|
@ -256,7 +293,8 @@ function translation_entity_delete_confirm_submit(array $form, array &$form_stat
|
|||
|
||||
// Remove any existing path alias for the removed translation.
|
||||
if (module_exists('path')) {
|
||||
path_delete(array('source' => $controller->getViewPath($entity), 'langcode' => $language->langcode));
|
||||
$conditions = array('source' => $controller->getViewPath($entity), 'langcode' => $language->langcode);
|
||||
drupal_container()->get('path.crud')->delete($conditions);
|
||||
}
|
||||
|
||||
$form_state['redirect'] = $controller->getBasePath($entity) . '/translations';
|
||||
|
|
|
@ -34,9 +34,6 @@ class UserTranslationUITest extends EntityTranslationUITest {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\simpletest\WebTestBase::setUp().
|
||||
*/
|
||||
function setUp() {
|
||||
$this->entityType = 'user';
|
||||
$this->testLanguageSelector = FALSE;
|
||||
|
@ -48,7 +45,7 @@ class UserTranslationUITest extends EntityTranslationUITest {
|
|||
* Overrides \Drupal\translation_entity\Tests\EntityTranslationUITest::getTranslatorPermission().
|
||||
*/
|
||||
function getTranslatorPermissions() {
|
||||
return array('administer users', "translate $this->entityType entities", 'edit original values');
|
||||
return array_merge(parent::getTranslatorPermissions(), array('administer users'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +60,7 @@ class UserTranslationUITest extends EntityTranslationUITest {
|
|||
* Tests translate link on user admin list.
|
||||
*/
|
||||
function testTranslateLinkUserAdminPage() {
|
||||
$this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer users', 'translate any entity'));
|
||||
$this->admin_user = $this->drupalCreateUser(array_merge(parent::getTranslatorPermissions(), array('access administration pages', 'administer users')));
|
||||
$this->drupalLogin($this->admin_user);
|
||||
|
||||
$uid = $this->createEntity(array('name' => $this->randomName()), $this->langcodes[0]);
|
||||
|
|
Loading…
Reference in New Issue