Commit c53879f0 authored by alexpott's avatar alexpott

Issue #1978924 by tim.plunkett, ParisLiakos, disasm, Luxian, vijaycs85, YesCT,...

Issue #1978924 by tim.plunkett, ParisLiakos, disasm, Luxian, vijaycs85, YesCT, vaibhavjain, Pancho: Convert locale_translate_export_form to a Controller.
parent 29b519c5
......@@ -603,10 +603,14 @@ public function processForm($form_id, &$form, &$form_state) {
// Set a flag to indicate the the form has been processed and executed.
$form_state['executed'] = TRUE;
// Redirect the form based on values in $form_state.
$redirect = $this->redirectForm($form_state);
if (is_object($redirect)) {
return $redirect;
// If no response has been set, process the form redirect.
if (!isset($form_state['response']) && $redirect = $this->redirectForm($form_state)) {
$form_state['response'] = $redirect;
}
// If there is a response was set, return it instead of continuing.
if (isset($form_state['response']) && $form_state['response'] instanceof Response) {
return $form_state['response'];
}
}
......
......@@ -104,6 +104,12 @@ public function getForm($form_arg);
* already set $form_state['rebuild'] to cause the form processing to
* bypass submit handlers and rebuild the form instead, even if there are
* no validation errors.
* - response: Used when a form needs to return some kind of a
* \Symfony\Component\HttpFoundation\Response object, e.g., a
* \Symfony\Component\HttpFoundation\BinaryFileResponse when triggering a
* file download. If you use the $form_state['redirect'] key, it will be
* used to build a \Symfony\Component\HttpFoundation\RedirectResponse and
* will populate this key.
* - redirect: Used to redirect the form on submission. It may either be a
* string containing the destination URL, or an array of arguments
* compatible with url(). See url() for complete information.
......
<?php
/**
* @file
* Contains \Drupal\locale\Form\ExportForm.
*/
namespace Drupal\locale\Form;
use Drupal\Component\Gettext\PoStreamWriter;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\locale\PoDatabaseReader;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
/**
* Form for the Gettext translation files export form.
*/
class ExportForm extends FormBase {
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* Constructs a new ExportForm.
*
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
*/
public function __construct(LanguageManagerInterface $language_manager) {
$this->languageManager = $language_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('language_manager')
);
}
/**
* {@inheritdoc}
*/
public function getFormID() {
return 'locale_translate_export_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, array &$form_state) {
$languages = $this->languageManager->getLanguages();
$language_options = array();
foreach ($languages as $langcode => $language) {
if ($langcode != 'en' || locale_translate_english()) {
$language_options[$langcode] = $language->name;
}
}
$language_default = $this->languageManager->getDefaultLanguage();
if (empty($language_options)) {
$form['langcode'] = array(
'#type' => 'value',
'#value' => Language::LANGCODE_SYSTEM,
);
$form['langcode_text'] = array(
'#type' => 'item',
'#title' => $this->t('Language'),
'#markup' => $this->t('No language available. The export will only contain source strings.'),
);
}
else {
$form['langcode'] = array(
'#type' => 'select',
'#title' => $this->t('Language'),
'#options' => $language_options,
'#default_value' => $language_default->id,
'#empty_option' => $this->t('Source text only, no translations'),
'#empty_value' => Language::LANGCODE_SYSTEM,
);
$form['content_options'] = array(
'#type' => 'details',
'#title' => $this->t('Export options'),
'#collapsed' => TRUE,
'#tree' => TRUE,
'#states' => array(
'invisible' => array(
':input[name="langcode"]' => array('value' => Language::LANGCODE_SYSTEM),
),
),
);
$form['content_options']['not_customized'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Include non-customized translations'),
'#default_value' => TRUE,
);
$form['content_options']['customized'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Include customized translations'),
'#default_value' => TRUE,
);
$form['content_options']['not_translated'] = array(
'#type' => 'checkbox',
'#title' => $this->t('Include untranslated text'),
'#default_value' => TRUE,
);
}
$form['actions'] = array(
'#type' => 'actions'
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Export')
);
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, array &$form_state) {
// If template is required, language code is not given.
if ($form_state['values']['langcode'] != Language::LANGCODE_SYSTEM) {
$language = $this->languageManager->getLanguage($form_state['values']['langcode']);
}
else {
$language = NULL;
}
$content_options = isset($form_state['values']['content_options']) ? $form_state['values']['content_options'] : array();
$reader = new PoDatabaseReader();
$languageName = '';
if ($language != NULL) {
$reader->setLangcode($language->id);
$reader->setOptions($content_options);
$languages = $this->languageManager->getLanguages();
$languageName = isset($languages[$language->id]) ? $languages[$language->id]->name : '';
$filename = $language->id .'.po';
}
else {
// Template required.
$filename = 'drupal.pot';
}
$item = $reader->readItem();
if (!empty($item)) {
$uri = tempnam('temporary://', 'po_');
$header = $reader->getHeader();
$header->setProjectName($this->config('system.site')->get('name'));
$header->setLanguageName($languageName);
$writer = new PoStreamWriter;
$writer->setUri($uri);
$writer->setHeader($header);
$writer->open();
$writer->writeItem($item);
$writer->writeItems($reader);
$writer->close();
$response = new BinaryFileResponse($uri);
$response->setContentDisposition('attachment', $filename);
$form_state['response'] = $response;
}
else {
drupal_set_message($this->t('Nothing to export.'));
}
}
}
......@@ -21,16 +21,6 @@ public function import() {
return drupal_get_form('locale_translate_import_form');
}
/**
* Wraps locale_translate_export_form().
*
* @todo Remove locale_translate_export_form().
*/
public function export() {
module_load_include('bulk.inc', 'locale');
return drupal_get_form('locale_translate_export_form');
}
/**
* Wraps locale_translation_status_form().
*
......
......@@ -5,11 +5,8 @@
* Mass import-export and batch import functionality for Gettext .po files.
*/
use Drupal\Component\Gettext\PoStreamWriter;
use Drupal\locale\Gettext;
use Drupal\locale\PoDatabaseReader;
use Drupal\Core\Language\Language;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Drupal\file\FileInterface;
/**
......@@ -148,135 +145,6 @@ function locale_translate_import_form_submit($form, &$form_state) {
return;
}
/**
* Form constructor for the Gettext translation files export form.
*
* @see locale_translate_export_form_submit()
* @ingroup forms
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal\locale\Form\LocaleForm::export().
*/
function locale_translate_export_form($form, &$form_state) {
$languages = language_list();
$language_options = array();
foreach ($languages as $langcode => $language) {
if ($langcode != 'en' || locale_translate_english()) {
$language_options[$langcode] = $language->name;
}
}
$language_default = language_default();
if (empty($language_options)) {
$form['langcode'] = array(
'#type' => 'value',
'#value' => Language::LANGCODE_SYSTEM,
);
$form['langcode_text'] = array(
'#type' => 'item',
'#title' => t('Language'),
'#markup' => t('No language available. The export will only contain source strings.'),
);
}
else {
$form['langcode'] = array(
'#type' => 'select',
'#title' => t('Language'),
'#options' => $language_options,
'#default_value' => $language_default->id,
'#empty_option' => t('Source text only, no translations'),
'#empty_value' => Language::LANGCODE_SYSTEM,
);
$form['content_options'] = array(
'#type' => 'details',
'#title' => t('Export options'),
'#tree' => TRUE,
'#states' => array(
'invisible' => array(
':input[name="langcode"]' => array('value' => Language::LANGCODE_SYSTEM),
),
),
);
$form['content_options']['not_customized'] = array(
'#type' => 'checkbox',
'#title' => t('Include non-customized translations'),
'#default_value' => TRUE,
);
$form['content_options']['customized'] = array(
'#type' => 'checkbox',
'#title' => t('Include customized translations'),
'#default_value' => TRUE,
);
$form['content_options']['not_translated'] = array(
'#type' => 'checkbox',
'#title' => t('Include untranslated text'),
'#default_value' => TRUE,
);
}
$form['actions'] = array(
'#type' => 'actions'
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Export')
);
return $form;
}
/**
* Form submission handler for locale_translate_export_form().
*/
function locale_translate_export_form_submit($form, &$form_state) {
// If template is required, language code is not given.
if ($form_state['values']['langcode'] != Language::LANGCODE_SYSTEM) {
$language = language_load($form_state['values']['langcode']);
}
else {
$language = NULL;
}
$content_options = isset($form_state['values']['content_options']) ? $form_state['values']['content_options'] : array();
$reader = new PoDatabaseReader();
$languageName = '';
if ($language != NULL) {
$reader->setLangcode($language->id);
$reader->setOptions($content_options);
$languages = language_list();
$languageName = isset($languages[$language->id]) ? $languages[$language->id]->name : '';
$filename = $language->id .'.po';
}
else {
// Template required.
$filename = 'drupal.pot';
}
$item = $reader->readItem();
if (!empty($item)) {
$uri = tempnam('temporary://', 'po_');
$header = $reader->getHeader();
$header->setProjectName(\Drupal::config('system.site')->get('name'));
$header->setLanguageName($languageName);
$writer = new PoStreamWriter;
$writer->setUri($uri);
$writer->setHeader($header);
$writer->open();
$writer->writeItem($item);
$writer->writeItems($reader);
$writer->close();
$response = new BinaryFileResponse($uri);
$response->setContentDisposition('attachment', $filename);
// @todo remove lines below once converted to new routing system.
$response->prepare(\Drupal::request())
->send();
}
else {
drupal_set_message('Nothing to export.');
}
}
/**
* Prepare a batch to import all translations.
*
......
......@@ -32,7 +32,7 @@ locale.translate_import:
locale.translate_export:
path: '/admin/config/regional/translate/export'
defaults:
_content: '\Drupal\locale\Form\LocaleForm::export'
_form: '\Drupal\locale\Form\ExportForm'
_title: 'Export'
requirements:
_permission: 'translate interface'
......
......@@ -124,6 +124,100 @@ public function testGetFormIdWithBaseForm() {
$this->assertSame($base_form_id, $form_state['build_info']['base_form_id']);
}
/**
* Tests the handling of $form_state['response'].
*
* @dataProvider formStateResponseProvider
*/
public function testHandleFormStateResponse($class, $form_state_key) {
$form_id = 'test_form_id';
$expected_form = $form_id();
$response = $this->getMockBuilder($class)
->disableOriginalConstructor()
->getMock();
$response->expects($this->any())
->method('prepare')
->will($this->returnValue($response));
$form_arg = $this->getMockForm($form_id, $expected_form);
$form_arg->expects($this->any())
->method('submitForm')
->will($this->returnCallback(function ($form, &$form_state) use ($response, $form_state_key) {
$form_state[$form_state_key] = $response;
}));
$form_state = array();
$this->formBuilder->getFormId($form_arg, $form_state);
try {
$form_state['values'] = array();
$form_state['input']['form_id'] = $form_id;
$this->simulateFormSubmission($form_id, $form_arg, $form_state, FALSE);
$this->fail('TestFormBuilder::sendResponse() was not triggered.');
}
catch (\Exception $e) {
$this->assertSame('exit', $e->getMessage());
}
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $form_state['response']);
}
/**
* Provides test data for testHandleFormStateResponse().
*/
public function formStateResponseProvider() {
return array(
array('Symfony\Component\HttpFoundation\Response', 'response'),
array('Symfony\Component\HttpFoundation\RedirectResponse', 'redirect'),
);
}
/**
* Tests the handling of a redirect when $form_state['response'] exists.
*/
public function testHandleRedirectWithResponse() {
$form_id = 'test_form_id';
$expected_form = $form_id();
// Set up a response that will be used.
$response = $this->getMockBuilder('Symfony\Component\HttpFoundation\Response')
->disableOriginalConstructor()
->getMock();
$response->expects($this->once())
->method('prepare')
->will($this->returnValue($response));
// Set up a redirect that will not be called.
$redirect = $this->getMockBuilder('Symfony\Component\HttpFoundation\RedirectResponse')
->disableOriginalConstructor()
->getMock();
$redirect->expects($this->never())
->method('prepare');
$form_arg = $this->getMockForm($form_id, $expected_form);
$form_arg->expects($this->any())
->method('submitForm')
->will($this->returnCallback(function ($form, &$form_state) use ($response, $redirect) {
// Set both the response and the redirect.
$form_state['response'] = $response;
$form_state['redirect'] = $redirect;
}));
$form_state = array();
$this->formBuilder->getFormId($form_arg, $form_state);
try {
$form_state['values'] = array();
$form_state['input']['form_id'] = $form_id;
$this->simulateFormSubmission($form_id, $form_arg, $form_state, FALSE);
$this->fail('TestFormBuilder::sendResponse() was not triggered.');
}
catch (\Exception $e) {
$this->assertSame('exit', $e->getMessage());
}
$this->assertSame($response, $form_state['response']);
}
/**
* Tests the redirectForm() method when a redirect is expected.
*
......
......@@ -189,15 +189,19 @@ protected function getMockForm($form_id, $expected_form = NULL, $count = 1) {
* The form object.
* @param array $form_state
* An associative array containing the current state of the form.
* @param bool $programmed
* Whether $form_state['programmed'] should be set to TRUE or not. If it is
* not set to TRUE, you must provide additional data in $form_state for the
* submission to take place.
*
* @return array
* The built form.
*/
protected function simulateFormSubmission($form_id, FormInterface $form_arg, array &$form_state) {
protected function simulateFormSubmission($form_id, FormInterface $form_arg, array &$form_state, $programmed = TRUE) {
$form_state['build_info']['callback_object'] = $form_arg;
$form_state['build_info']['args'] = array();
$form_state['input']['op'] = 'Submit';
$form_state['programmed'] = TRUE;
$form_state['programmed'] = $programmed;
$form_state['submitted'] = TRUE;
return $this->formBuilder->buildForm($form_id, $form_state);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment