Commit 77c666c3 authored by alexpott's avatar alexpott
Browse files

Issue #1987882 by disasm, vijaycs85, penyaskito, kim.pepper, likin, YesCT,...

Issue #1987882 by disasm, vijaycs85, penyaskito, kim.pepper, likin, YesCT, InternetDevels, dawehner, wamilton, Letharion, katbailey, googletorp, tim.plunkett, acrollet, neetu morwani: Convert content_translation routes to a new style controller.
parent f485925f
<?php
/**
* @file
* The content translation user interface.
*/
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\ContentEntityInterface;
/**
* Translations overview page callback.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity whose translation overview should be displayed.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal\content_translation\Controller\ContentTranslationController::overview().
*/
function content_translation_overview(EntityInterface $entity) {
$controller = content_translation_controller($entity->getEntityTypeId());
$languages = \Drupal::languageManager()->getLanguages();
$original = $entity->getUntranslated()->language()->id;
$translations = $entity->getTranslationLanguages();
$administrator = \Drupal::currentUser()->hasPermission('administer languages');
$rel = array();
foreach (array('canonical', 'edit-form', 'drupal:content-translation-overview') as $name) {
$rel[$name] = $entity->getSystemPath($name);
}
$rows = array();
$show_source_column = FALSE;
if (\Drupal::languageManager()->isMultilingual()) {
// Determine whether the current entity is translatable.
$translatable = FALSE;
foreach (\Drupal::entityManager()->getFieldDefinitions($entity->getEntityTypeId(), $entity->bundle()) as $field_definition) {
if ($field_definition->isTranslatable()) {
$translatable = TRUE;
break;
}
}
// Show source-language column if there are non-original source langcodes.
$additional_source_langcodes = array_filter($entity->translation, function ($translation) use ($original) {
return !empty($translation['source']) && $translation['source'] != $original;
});
$show_source_column = !empty($additional_source_langcodes);
foreach ($languages as $language) {
$language_name = $language->name;
$langcode = $language->id;
$add_path = $rel['drupal:content-translation-overview'] . '/add/' . $original . '/' . $langcode;
$translate_path = $rel['drupal:content-translation-overview'] . '/edit/' . $langcode;
$add_links = _content_translation_get_switch_links($add_path);
$edit_links = _content_translation_get_switch_links($rel['edit-form']);
$translate_links = _content_translation_get_switch_links($translate_path);
$delete_links = _content_translation_get_switch_links($rel['drupal:content-translation-overview'] . '/delete/' . $langcode);
$operations = array(
'data' => array(
'#type' => 'operations',
'#links' => array(),
),
);
$links = &$operations['data']['#links'];
if (isset($translations[$langcode])) {
// Existing translation in the translation set: display status.
$source = isset($entity->translation[$langcode]['source']) ? $entity->translation[$langcode]['source'] : '';
$is_original = $langcode == $original;
$label = $entity->getTranslation($langcode)->label();
$link = isset($links->links[$langcode]['href']) ? $links->links[$langcode] : array('href' => $rel['canonical'], 'language' => $language);
$row_title = l($label, $link['href'], $link);
if (empty($link['href'])) {
$row_title = $is_original ? $label : t('n/a');
}
// 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 ($entity->access('update')) {
$links['edit'] = isset($edit_links->links[$langcode]['href']) ? $edit_links->links[$langcode] : array('href' => $rel['edit-form'], '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');
}
$translation = $entity->translation[$langcode];
$status = !empty($translation['status']) ? t('Published') : t('Not published');
// @todo Add a theming function here.
$status = '<span class="status">' . $status . '</span>' . (!empty($translation['outdated']) ? ' <span class="marker">' . t('outdated') . '</span>' : '');
if ($is_original) {
$language_name = t('<strong>@language_name (Original language)</strong>', array('@language_name' => $language_name));
$source_name = t('n/a');
}
else {
$source_name = isset($languages[$source]) ? $languages[$source]->name : t('n/a');
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 {
// No such translation in the set yet: help user to create it.
$row_title = $source_name = t('n/a');
$source = $entity->language()->id;
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');
}
elseif ($administrator) {
$links['nofields'] = array('title' => t('No translatable fields'), 'route_name' => 'language.content_settings_page', 'language' => $language);
}
}
$status = t('Not translated');
}
if ($show_source_column) {
$rows[] = array($language_name, $row_title, $source_name, $status, $operations);
}
else {
$rows[] = array($language_name, $row_title, $status, $operations);
}
}
}
$build['#title'] = t('Translations of %label', array('%label' => $entity->label()));
// Add metadata to the build render array to let other modules know about
// which entity this is.
$build['#entity'] = $entity;
if ($show_source_column) {
$header = array(t('Language'), t('Translation'), t('Source language'), t('Status'), t('Operations'));
}
else {
$header = array(t('Language'), t('Translation'), t('Status'), t('Operations'));
}
$build['content_translation_overview'] = array(
'#type' => 'table',
'#header' => $header,
'#rows' => $rows,
);
return $build;
}
/**
* Returns the localized links for the given path.
*
* @param string $path
* The path for which language switch links should be provided.
*
* @returns
* A renderable array of language switch links.
*/
function _content_translation_get_switch_links($path) {
$links = \Drupal::languageManager()->getLanguageSwitchLinks(LanguageInterface::TYPE_CONTENT, $path);
if (empty($links)) {
// If content language is set up to fall back to the interface language,
// then there will be no switch links for LanguageInterface::TYPE_CONTENT,
// ergo we also need to use interface switch links.
$links = \Drupal::languageManager()->getLanguageSwitchLinks(LanguageInterface::TYPE_INTERFACE, $path);
}
return $links;
}
/**
* Page callback for the translation addition page.
*
* @param EntityInterface $entity
* The entity being translated.
* @param \Drupal\Core\Language\LanguageInterface $source
* (optional) The language of the values being translated. Defaults to the
* entity language.
* @param \Drupal\Core\Language\LanguageInterface $target
* (optional) The language of the translated values. Defaults to the current
* content language.
*
* @return array
* A processed form array ready to be rendered.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal\content_translation\Controller\ContentTranslationController::add().
*/
function content_translation_add_page(EntityInterface $entity, LanguageInterface $source = NULL, LanguageInterface $target = NULL) {
$source = !empty($source) ? $source : $entity->language();
$target = !empty($target) ? $target : \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
// @todo Exploit the upcoming hook_entity_prepare() when available.
content_translation_prepare_translation($entity, $source, $target);
$form_state['langcode'] = $target->id;
$form_state['content_translation']['source'] = $source;
$form_state['content_translation']['target'] = $target;
$form_state['content_translation']['translation_form'] = !$entity->access('update');
return \Drupal::service('entity.form_builder')->getForm($entity, 'default', $form_state);
}
/**
* Page callback for the translation edit page.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity being translated.
* @param \Drupal\Core\Language\LanguageInterface $language
* (optional) The language of the translated values. Defaults to the current
* content language.
*
* @return array
* A processed form array ready to be rendered.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal\content_translation\Controller\ContentTranslationController::edit().
*/
function content_translation_edit_page(EntityInterface $entity, LanguageInterface $language = NULL) {
$language = !empty($language) ? $language : \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
$form_state['langcode'] = $language->id;
$form_state['content_translation']['translation_form'] = TRUE;
return \Drupal::service('entity.form_builder')->getForm($entity, 'default', $form_state);
}
/**
* Populates target values with the source values.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entitiy being translated.
* @param \Drupal\Core\Language\LanguageInterface $source
* The language to be used as source.
* @param \Drupal\Core\Language\LanguageInterface $target
* The language to be used as target.
*/
function content_translation_prepare_translation(EntityInterface $entity, LanguageInterface $source, LanguageInterface $target) {
if ($entity instanceof ContentEntityInterface) {
$source_translation = $entity->getTranslation($source->id);
$entity->addTranslation($target->id, $source_translation->toArray());
}
}
......@@ -17,7 +17,7 @@ services:
content_translation.manage_access:
class: Drupal\content_translation\Access\ContentTranslationManageAccessCheck
arguments: ['@entity.manager']
arguments: ['@entity.manager', '@language_manager']
tags:
- { name: access_check, applies_to: _access_content_translation_manage }
......
......@@ -9,10 +9,11 @@
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/**
* Access check for entity translation CRUD operation.
......@@ -26,14 +27,24 @@ class ContentTranslationManageAccessCheck implements AccessInterface {
*/
protected $entityManager;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* Constructs a ContentTranslationManageAccessCheck object.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $manager
* The entity type manager.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
public function __construct(EntityManagerInterface $manager) {
public function __construct(EntityManagerInterface $manager, LanguageManagerInterface $language_manager) {
$this->entityManager = $manager;
$this->languageManager = $language_manager;
}
/**
......@@ -52,39 +63,43 @@ public function __construct(EntityManagerInterface $manager) {
* @param string $language
* (optional) For an update or delete operation, the language code of the
* translation being updated or deleted.
* @param string $entity_type_id
* (optional) The entity type ID.
*
* @return string
* A \Drupal\Core\Access\AccessInterface constant value.
*/
public function access(Route $route, Request $request, AccountInterface $account, $source = NULL, $target = NULL, $language = NULL) {
$entity_type = $request->attributes->get('_entity_type_id');
/** @var $entity \Drupal\Core\Entity\EntityInterface */
if ($entity = $request->attributes->get($entity_type)) {
public function access(Route $route, Request $request, AccountInterface $account, $source = NULL, $target = NULL, $language = NULL, $entity_type_id = NULL) {
/* @var \Drupal\Core\Entity\ContentEntityInterface $entity */
if ($entity = $request->attributes->get($entity_type_id)) {
$operation = $route->getRequirement('_access_content_translation_manage');
$controller = content_translation_controller($entity_type, $account);
/* @var \Drupal\content_translation\ContentTranslationHandlerInterface $handler */
$handler = $this->entityManager->getController($entity->getEntityTypeId(), 'translation');
// Load translation.
$translations = $entity->getTranslationLanguages();
$languages = language_list();
$languages = $this->languageManager->getLanguages();
switch ($operation) {
case 'create':
$source = language_load($source) ?: $entity->language();
$target = language_load($target) ?: \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
return ($source->id != $target->id
&& isset($languages[$source->id])
&& isset($languages[$target->id])
&& !isset($translations[$target->id])
&& $controller->getTranslationAccess($entity, $operation))
$source_language = $this->languageManager->getLanguage($source) ?: $entity->language();
$target_language = $this->languageManager->getLanguage($target) ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
return ($source_language->getId() != $target_language->getId()
&& isset($languages[$source_language->getId()])
&& isset($languages[$target_language->getId()])
&& !isset($translations[$target_language->getId()])
&& $handler->getTranslationAccess($entity, $operation))
? static::ALLOW : static::DENY;
case 'update':
case 'delete':
$language = language_load($language) ?: \Drupal::languageManager()->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
return isset($languages[$language->id])
&& $language->id != $entity->getUntranslated()->language()->id
&& isset($translations[$language->id])
&& $controller->getTranslationAccess($entity, $operation)
$language = $this->languageManager->getLanguage($language) ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_CONTENT);
return isset($languages[$language->getId()])
&& $language->getId() != $entity->getUntranslated()->language()->getId()
&& isset($translations[$language->getId()])
&& $handler->getTranslationAccess($entity, $operation)
? static::ALLOW : static::DENY;
}
}
......
......@@ -46,7 +46,7 @@ public function __construct(EntityManagerInterface $manager) {
* A \Drupal\Core\Access\AccessInterface constant value.
*/
public function access(Request $request, AccountInterface $account) {
$entity_type = $request->attributes->get('_entity_type_id');
$entity_type = $request->attributes->get('entity_type_id');
if ($entity = $request->attributes->get($entity_type)) {
// Get entity base info.
$bundle = $entity->bundle();
......
......@@ -201,8 +201,12 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, En
// A new translation is not available in the translation metadata, hence
// it should count as one more.
$published = $new_translation;
foreach ($entity->translation as $translation) {
$published += $translation['status'];
// When creating a brand new translation, $entity->translation is not
// set.
if (!$new_translation) {
foreach ($entity->translation as $translation) {
$published += $translation['status'];
}
}
$enabled = $published > 1;
}
......@@ -467,7 +471,7 @@ function entityFormDeleteTranslation($form, FormStateInterface $form_state) {
$form_controller = content_translation_form_controller($form_state);
$entity = $form_controller->getEntity();
$entity_type_id = $entity->getEntityTypeId();
$form_state->setRedirect('content_translation.delete_' . $entity_type_id, array(
$form_state->setRedirect('content_translation.translation_delete_' . $entity_type_id, array(
$entity_type_id => $entity->id(),
'language' => $form_controller->getFormLangcode($form_state),
));
......
......@@ -7,41 +7,288 @@
namespace Drupal\content_translation\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\Request;
/**
* Base class for entity translation controllers.
*/
class ContentTranslationController {
class ContentTranslationController extends ControllerBase {
/**
* @todo Remove content_translation_overview().
* Populates target values with the source values.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* The entity being translated.
* @param \Drupal\Core\Language\LanguageInterface $source
* The language to be used as source.
* @param \Drupal\Core\Language\LanguageInterface $target
* The language to be used as target.
*/
public function overview(Request $request) {
$entity = $request->attributes->get($request->attributes->get('_entity_type_id'));
module_load_include('pages.inc', 'content_translation');
return content_translation_overview($entity);
public function prepareTranslation(ContentEntityInterface $entity, LanguageInterface $source, LanguageInterface $target) {
/* @var \Drupal\Core\Entity\ContentEntityInterface $source_translation */
$source_translation = $entity->getTranslation($source->getId());
$entity->addTranslation($target->getId(), $source_translation->toArray());
}
/**
* @todo Remove content_translation_add_page().
* Builds the translations overview page.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The request object from which to extract the entity type.
* @param string $entity_type_id
* (optional) The entity type ID.
*
* @return array
* Array of page elements to render.
*/
public function add(Request $request, $source, $target) {
$entity = $request->attributes->get($request->attributes->get('_entity_type_id'));
module_load_include('pages.inc', 'content_translation');
$source = language_load($source);
$target = language_load($target);
return content_translation_add_page($entity, $source, $target);
public function overview(Request $request, $entity_type_id = NULL) {
$entity = $request->attributes->get($entity_type_id);
$account = $this->currentUser();
$handler = $this->entityManager()->getController($entity_type_id, 'translation');
$languages = $this->languageManager()->getLanguages();
$original = $entity->getUntranslated()->language()->getId();
$translations = $entity->getTranslationLanguages();
$field_ui = $this->moduleHandler()->moduleExists('field_ui') && $account->hasPermission('administer ' . $entity_type_id . ' fields');
$rows = array();
$show_source_column = FALSE;
if ($this->languageManager()->isMultilingual()) {
// Determine whether the current entity is translatable.
$translatable = FALSE;
foreach ($this->entityManager->getFieldDefinitions($entity_type_id, $entity->bundle()) as $instance) {
if ($instance->isTranslatable()) {
$translatable = TRUE;
break;
}
}
// Show source-language column if there are non-original source langcodes.
$additional_source_langcodes = array_filter($entity->translation, function ($translation) use ($original) {
return !empty($translation['source']) && $translation['source'] != $original;
});
$show_source_column = !empty($additional_source_langcodes);
foreach ($languages as $language) {
$language_name = $language->name;
$langcode = $language->getId();
$add_url = new Url(
'content_translation.translation_add_' . $entity_type_id,
array(
'source' => $original,
'target' => $language->getId(),
$entity_type_id => $entity->id(),
)
);
$edit_url = new Url(
'content_translation.translation_edit_' . $entity_type_id,
array(
'language' => $language->getId(),
$entity_type_id => $entity->id(),
)
);
$delete_url = new Url(
'content_translation.translation_delete_' . $entity_type_id,
array(
'language' => $language->getId(),
$entity_type_id => $entity->id(),
)
);
$operations = array(
'data' => array(
'#type' => 'operations',
'#links' => array(),
),
);
$links = &$operations['data']['#links'];
if (array_key_exists($langcode, $translations)) {
// Existing translation in the translation set: display status.
$source = isset($entity->translation[$langcode]['source']) ? $entity->translation[$langcode]['source'] : '';
$is_original = $langcode == $original;
$label = $entity->getTranslation($langcode)->label();
$link = isset($links->links[$langcode]['href']) ? $links->links[$langcode] : array('href' => $entity->getSystemPath());
$row_title = l($label, $link['href'], $link);
if (empty($link['href'])) {
$row_title = $is_original ? $label : $this->t('n/a');
}
// 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 ($entity->access('update')) {
$links['edit'] = array(
'href' => $entity->getSystemPath('edit-form'),
);
}
elseif (!$is_original && $handler->getTranslationAccess($entity, 'update')) {
$links['edit'] = $edit_url->toArray();
}
if (isset($links['edit'])) {
$links['edit']['title'] = $this->t('Edit');
}
$translation = $entity->translation[$langcode];
$status = !empty($translation['status']) ? $this->t('Published') : $this->t('Not published');
// @todo Remove as part of https://drupal.org/node/2250841.
$status = '<span class="status">' . $status . '</span>' . (!empty($translation['outdated']) ? ' <span class="marker">' . $this->t('outdated') . '</span>' : '');
if ($is_original) {
$language_name = $this->t('<strong>@language_name (Original language)</strong>', array('@language_name' => $language_name));
$source_name = $this->t('n/a');
}
else {
$source_name = isset($languages[$source]) ? $languages[$source]->name : $this->t('n/a');
if ($handler->getTranslationAccess($entity, 'delete')) {
$links['delete'] = array(
'title' => $this->t('Delete'),
) + $delete_url->toArray();
}
}
}
else {
// No such translation in the set yet: help user to create it.
$row_title = $source_name = $this->t('n/a');
$source = $entity->language()->getId();
if ($source != $langcode && $handler->getTranslationAccess($entity, 'create')) {