View source
<?php
namespace Drupal\tmgmt_extension_suit\Form;
use Drupal;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Render\Markup;
use Drupal\Core\Url;
use Drupal\tmgmt\JobInterface;
use Drupal\tmgmt\JobItemInterface;
use Drupal\tmgmt\TMGMTException;
use Drupal\tmgmt\TranslatorManager;
use Drupal\tmgmt_extension_suit\ExtendedTranslatorPluginInterface;
use Drupal\user\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;
class RequestTranslationApproveForm extends FormBase {
private $tempStore;
private $translatorManager;
public static function create(ContainerInterface $container) {
return new static($container
->get('user.private_tempstore'), $container
->get('plugin.manager.tmgmt.translator'));
}
public function __construct(PrivateTempStoreFactory $temp_store_factory, TranslatorManager $translator_manager) {
$this->tempStore = $temp_store_factory
->get('tmgmt_extension_suit');
$this->translatorManager = $translator_manager;
}
public function getFormId() {
return 'tmgmt_extension_suit_request_translation_approve_form';
}
private function refreshServices() {
if (empty($this->tempStore)) {
$this->tempStore = Drupal::service('user.private_tempstore')
->get('tmgmt_extension_suit');
}
if (empty($this->translatorManager)) {
$this->translatorManager = Drupal::service('plugin.manager.tmgmt.translator');
}
}
protected function getConflictingItem(array $data, $target_language) {
return Drupal::entityQuery('tmgmt_job_item')
->condition('state', [
JobItemInterface::STATE_ACTIVE,
JobItemInterface::STATE_REVIEW,
], 'IN')
->condition('plugin', $data['plugin'])
->condition('item_type', $data['item_type'])
->condition('item_id', $data['item'])
->condition('tjid.entity.source_language', $data['source_language'])
->condition('tjid.entity.target_language', $target_language)
->execute();
}
private function getConflictMessage(array $conflicting_items) {
$list_render_array = [
'#theme' => 'item_list',
'#items' => $conflicting_items,
'#type' => 'ul',
'#attributes' => [
'class' => 'dropped-job-item-list',
],
];
$rendered_list = Drupal::service('renderer')
->render($list_render_array);
$message = Drupal::translation()
->formatPlural(count($conflicting_items), '1 item conflicted with pending item and was skipped. Existing job item: @rendered_list', '@count items conflicted with pending items and were skipped. Existing job items: @rendered_list', [
'@rendered_list' => $rendered_list,
]);
return Markup::create($message);
}
public function buildForm(array $form, FormStateInterface $form_state) {
$this
->refreshServices();
$data = $this->tempStore
->get('request_translation_batch');
if (empty($data)) {
return $form;
}
$form['translator_wrapper'] = [
'#type' => 'details',
'#title' => t('Configure provider'),
'#weight' => 20,
'#prefix' => '<div id="tmgmt-ui-translator-wrapper">',
'#suffix' => '</div>',
'#open' => TRUE,
];
if (!($translators = tmgmt_translator_labels_flagged())) {
drupal_set_message(t('There are no providers available. Before you can checkout you need to @configure at least one provider.', [
'@configure' => Link::fromTextAndUrl(t('configure'), Url::fromRoute('entity.tmgmt_translator.collection'))
->toString(),
]), 'warning');
}
$job = tmgmt_job_create('en', 'fr', Drupal::currentUser()
->id());
$preselected_translator = $form_state
->getValue('translator') ?: key($translators);
$job->translator = $preselected_translator;
$form_state
->set('job', $job);
$form['translator_wrapper']['translator'] = [
'#type' => 'select',
'#title' => t('Provider'),
'#description' => t('The configured provider that will process the translation.'),
'#options' => $translators,
'#access' => !empty($translators),
'#default_value' => $preselected_translator,
'#required' => TRUE,
'#ajax' => [
'callback' => [
$this,
'ajaxTranslatorSelect',
],
'wrapper' => 'tmgmt-ui-translator-wrapper',
],
];
try {
$settings = $this
->checkoutSettingsForm($form_state, $job);
} catch (TMGMTException $e) {
watchdog_exception('tmgmt_extension_suit', $e);
$settings = [];
}
if (!is_array($settings)) {
$settings = [];
}
$form['translator_wrapper']['settings'] = [
'#type' => 'details',
'#title' => t('Checkout settings'),
'#prefix' => '<div id="tmgmt-ui-translator-settings">',
'#suffix' => '</div>',
'#tree' => TRUE,
'#open' => TRUE,
] + $settings;
$available_languages = tmgmt_available_languages();
unset($available_languages[$data['source_language']]);
$form['target_language'] = [
'#title' => t('Target language'),
'#type' => 'checkboxes',
'#options' => $available_languages,
'#default_value' => array_filter($data['default_target_languages']),
'#prefix' => '<div id="edit-clone-lang-options">',
'#suffix' => '<div class="check-controls"><span class="check-all">' . t('Check All') . '</span><span class="uncheck-all">' . t('Uncheck All') . '</span></div></div>',
'#required' => TRUE,
];
$form['request_translation'] = [
'#weight' => 20,
'#type' => 'submit',
'#button_type' => 'primary',
'#value' => $this
->t('Request translation'),
];
$form['#attached']['library'][] = 'tmgmt_extension_suit/check_uncheck_all';
return $form;
}
public function ajaxTranslatorSelect(array $form, FormStateInterface $form_state) {
return $form['translator_wrapper'];
}
private function checkoutSettingsForm(FormStateInterface $form_state, JobInterface $job) {
$form = [];
if (!$job
->hasTranslator()) {
return $form;
}
$translator = $job
->getTranslator();
$result = $translator
->checkAvailable();
if (!$result
->getSuccess()) {
$form['#description'] = $result
->getReason();
return $form;
}
$result = $translator
->checkTranslatable($job);
if ($job
->getTargetLangcode() && !$result
->getSuccess()) {
$form['#description'] = $result
->getReason();
return $form;
}
$plugin_ui = $this->translatorManager
->createUIInstance($translator
->getPluginId());
$form = $plugin_ui
->checkoutSettingsForm($form, $form_state, $job);
return $form;
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$this
->refreshServices();
$data = $this->tempStore
->get('request_translation_batch');
$data['target_language'] = array_filter($form_state
->getValue('target_language'));
$data['translator'] = $form_state
->getValue('translator');
$data['settings'] = $form_state
->getValue('settings');
$conflicting_items = [];
$operations = [];
foreach ($data['items'] as $item) {
$operation_data = $data;
$operation_data['item'] = $item;
unset($operation_data['items']);
foreach ($operation_data['target_language'] as $language) {
$operation_data['target_language'] = $language;
$result = $this
->getConflictingItem($operation_data, $language);
if (!empty($result)) {
$job_item_id = key($result);
$conflicting_items[$job_item_id] = $this
->t('@job_item_link with source language = "@source_language" and target language = "@target_language" for entity "@entity_type" with id = "@id".', [
'@job_item_link' => Link::fromTextAndUrl(t('Job item'), Url::fromRoute('entity.tmgmt_job_item.canonical', [
'tmgmt_job_item' => $job_item_id,
], [
'attributes' => [
'target' => '_blank',
],
]))
->toString(),
'@entity_type' => $operation_data['item_type'],
'@id' => $operation_data['item'],
'@source_language' => $operation_data['source_language'],
'@target_language' => $language,
]);
}
else {
$operations[] = [
[
get_class($this),
'processBatch',
],
[
$operation_data,
],
];
}
}
}
if (!empty($conflicting_items)) {
drupal_set_message($this
->getConflictMessage($conflicting_items), 'warning');
}
$this->tempStore
->set('request_translation_batch', []);
if (!empty($operations)) {
$batch = [
'title' => t('Requesting translations...'),
'operations' => $operations,
'finished' => [
get_class($this),
'finishBatch',
],
];
batch_set($batch);
}
else {
drupal_set_message(Link::fromTextAndUrl(t('Return to "Sources" page'), Url::fromRoute('tmgmt.source_overview_default'))
->toString());
}
}
public function validateForm(array &$form, FormStateInterface $form_state) {
$job = $form_state
->get('job');
try {
if (!$job
->hasTranslator()) {
$form_state
->setError($form, t('Error. Please contact site administrator.'));
}
$translator = $job
->getTranslator();
$result = $translator
->checkAvailable();
if (!$result
->getSuccess()) {
$form_state
->setError($form['translator_wrapper']['translator'], $result
->getReason());
}
} catch (TMGMTException $e) {
watchdog_exception('tmgmt_extension_suit', $e);
$form_state
->setError($form, t('Error. Please contact site administrator.'));
}
}
public static function processBatch($data, &$context) {
$message = 'Requesting translations...';
$source_language = 'en';
switch ($data['plugin']) {
case 'content':
$entity_manager = Drupal::entityTypeManager();
$entity = $entity_manager
->getStorage($data['item_type'])
->load($data['item']);
$source_language = $entity
->language()
->getId();
break;
case 'config':
$config_factory = Drupal::configFactory()
->get($data['item']);
$source_language = $config_factory
->get('langcode');
break;
}
$job = tmgmt_job_create($source_language, $data['target_language'], Drupal::currentUser()
->id(), [
'settings' => $data['settings'],
]);
$job
->addItem($data['plugin'], $data['item_type'], $data['item']);
$job->translator = $data['translator'];
$job
->setState(JobInterface::STATE_ACTIVE);
Drupal::service('tmgmt_extension_suit.utils.queue_unique_item')
->addItem('tmgmt_extension_suit_upload', [
'id' => (int) $job
->id(),
]);
$translator_plugin = $job
->getTranslatorPlugin();
if ($translator_plugin instanceof ExtendedTranslatorPluginInterface) {
Drupal::getContainer()
->get('logger.channel.tmgmt_extension_suit')
->info(t('File upload queued (request translation in a batch). Job id: @job_id, file name: @name.', [
'@name' => $translator_plugin
->getFileName($job),
'@job_id' => $job
->id(),
]));
}
$context['message'] = $message;
$context['results'][] = $job
->id();
}
public static function finishBatch($success, $results, $operations) {
$type = 'status';
if ($success) {
$message = Drupal::translation()
->formatPlural(count($results), 'Translation request queued for one job. @return.', 'Translation request queued for @count jobs. @return.', [
'@return' => Link::fromTextAndUrl(t('Return to "Sources" page'), Url::fromRoute('tmgmt.source_overview_default'))
->toString(),
]);
}
else {
$type = 'error';
$message = t('Finished with an error. @return', [
'@return' => Link::fromTextAndUrl(t('Return to "Sources" page'), Url::fromRoute('tmgmt.source_overview_default'))
->toString(),
]);
}
drupal_set_message($message, $type);
}
}