Commit 6251c406 authored by Dries's avatar Dries

- Patch #135464 by Artusamak, Gábor Hojtsy, brantwynn, YesCT, z.stolar: add...

- Patch #135464 by Artusamak, Gábor Hojtsy, brantwynn, YesCT, z.stolar: add language options to block visibility.
parent 16e11713
......@@ -38,6 +38,8 @@ Drupal 8.0, xxxx-xx-xx (development version)
* Freely orderable language selector in forms.
* Made it possible to assign language to taxonomy terms, vocabularies
and files.
* Better language based configuration
* Added language options to block visibility.
* Much improved language APIs for developers:
* Added simple APIs and hooks to save/delete/update languages.
* Unified database schemas and APIs to make it easier to spot where
......
......@@ -400,6 +400,63 @@ function block_admin_configure($form, &$form_state, $module, $delta) {
);
}
// Configure the block visibility per language.
if (module_exists('language') && language_multilingual()) {
$configurable_language_types = language_types_get_configurable();
$existing_language_settings = db_query("SELECT type, langcode FROM {block_language} WHERE module = :module AND delta = :delta", array(
':module' => $form['module']['#value'],
':delta' => $form['delta']['#value'],
))->fetchAll();
$default_langcode_options = array();
$default_language_type = $configurable_language_types[0];
foreach ($existing_language_settings as $setting) {
$default_langcode_options[] = $setting->langcode;
// Overwrite default language type if we have it set. Although this
// theoretically would allow per language type association, our UI
// only allows language type association overall for a block, so we
// only need a single value.
$default_language_type = $setting->type;
}
// Fetch the enabled languages.
$enabled_languages = language_list(TRUE);
foreach ($enabled_languages as $language) {
// @TODO $language->name is not wrapped with t(), it should be replaced
// by CMI translation implementation.
$langcodes_options[$language->langcode] = $language->name;
}
$form['visibility']['language'] = array(
'#type' => 'fieldset',
'#title' => t('Languages'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'visibility',
'#weight' => 5,
);
// If there are multiple configurable language types, let the user pick
// which one should be applied to this visibility setting. This way users
// can limit blocks by interface language or content language for exmaple.
$language_types = language_types_info();
$language_type_options = array();
foreach ($configurable_language_types as $type_key) {
$language_type_options[$type_key] = $language_types[$type_key]['name'];
}
$form['visibility']['language']['language_type'] = array(
'#type' => 'radios',
'#title' => t('Language type'),
'#options' => $language_type_options,
'#default_value' => $default_language_type,
'#access' => count($language_type_options) > 1,
);
$form['visibility']['language']['langcodes'] = array(
'#type' => 'checkboxes',
'#title' => t('Show this block only for specific languages'),
'#default_value' => $default_langcode_options,
'#options' => $langcodes_options,
'#description' => t('Show this block only for the selected language(s). If you select no languages, the block will be visibile in all languages.'),
);
}
// Per-role visibility.
$default_role_options = db_query("SELECT rid FROM {block_role} WHERE module = :module AND delta = :delta", array(
':module' => $block->module,
......@@ -505,7 +562,7 @@ function block_admin_configure_submit($form, &$form_state) {
}
$query->execute();
// Store regions per theme for this block
// Store regions per theme for this block.
foreach ($form_state['values']['regions'] as $theme => $region) {
db_merge('block')
->key(array('theme' => $theme, 'delta' => $form_state['values']['delta'], 'module' => $form_state['values']['module']))
......@@ -517,6 +574,27 @@ function block_admin_configure_submit($form, &$form_state) {
->execute();
}
// Update the block visibility settings if we have settings to store
// for the existing languages.
if (module_exists('language') && isset($form_state['values']['langcodes'])) {
db_delete('block_language')
->condition('module', $form_state['values']['module'])
->condition('delta', $form_state['values']['delta'])
->execute();
$query = db_insert('block_language')->fields(array(
'type', 'langcode', 'module', 'delta'
));
foreach (array_filter($form_state['values']['langcodes']) as $langcode) {
$query->values(array(
'type' => $form_state['values']['language_type'],
'langcode' => $langcode,
'module' => $form_state['values']['module'],
'delta' => $form_state['values']['delta'],
));
}
$query->execute();
}
module_invoke($form_state['values']['module'], 'block_save', $form_state['values']['delta'], $form_state['values']);
}
catch (Exception $e) {
......@@ -604,7 +682,7 @@ function block_add_block_form_submit($form, &$form_state) {
}
$query->execute();
// Store regions per theme for this block
// Store regions per theme for this block.
foreach ($form_state['values']['regions'] as $theme => $region) {
db_merge('block')
->key(array('theme' => $theme, 'delta' => $delta, 'module' => $form_state['values']['module']))
......@@ -616,6 +694,23 @@ function block_add_block_form_submit($form, &$form_state) {
->execute();
}
// Update the block visibility settings if we have settings to store
// for the existing languages.
if (module_exists('language') && isset($form_state['values']['langcodes'])) {
$query = db_insert('block_language')->fields(array(
'type', 'langcode', 'module', 'delta'
));
foreach (array_filter($form_state['values']['langcodes']) as $langcode) {
$query->values(array(
'type' => $form_state['values']['language_type'],
'langcode' => $langcode,
'module' => $form_state['values']['module'],
'delta' => $form_state['values']['delta'],
));
}
$query->execute();
}
drupal_set_message(t('The block has been created.'));
cache_clear_all();
$form_state['redirect'] = 'admin/structure/block';
......@@ -659,6 +754,11 @@ function block_custom_block_delete_submit($form, &$form_state) {
->condition('module', 'block')
->condition('delta', $form_state['values']['bid'])
->execute();
db_delete('block_language')
->condition('module', 'block')
->condition('delta', $form_state['values']['bid'])
->execute();
drupal_set_message(t('The block %name has been removed.', array('%name' => $form_state['values']['info'])));
cache_clear_all();
$form_state['redirect'] = 'admin/structure/block';
......
......@@ -166,6 +166,37 @@ function block_schema() {
'primary key' => array('bid'),
);
$schema['block_language'] = array(
'description' => 'Sets up display criteria for blocks based on langcode',
'fields' => array(
'module' => array(
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'description' => "The block's origin module, from {block}.module.",
),
'delta' => array(
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'description' => "The block's unique delta within module, from {block}.delta.",
),
'type' => array(
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'description' => "Language type name. Applied to filter the block by that type.",
),
'langcode' => array(
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'description' => "The machine-readable name of this language from {language}.langcode.",
),
),
'primary key' => array('module', 'delta', 'type', 'langcode'),
);
$schema['cache_block'] = drupal_get_schema_unprocessed('system', 'cache');
$schema['cache_block']['description'] = 'Cache table for the Block module to store already built blocks, identified by module, delta, and various contexts which may change the block, such as theme, locale, and caching mode defined for the block.';
......@@ -198,6 +229,43 @@ function block_update_8000() {
variable_del('block_cache');
}
/**
* Creates table {block_language} for language visibility settings per block.
*/
function block_update_8001() {
$schema = array(
'description' => 'Sets up display criteria for blocks based on langcode.',
'fields' => array(
'module' => array(
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'description' => "The block's origin module, from {block}.module.",
),
'delta' => array(
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'description' => "The block's unique delta within module, from {block}.delta.",
),
'type' => array(
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'description' => "Language type name. Applied to filter the block by that type.",
),
'langcode' => array(
'type' => 'varchar',
'length' => 32,
'not null' => TRUE,
'description' => "The machine-readable name of this language from {language}.langcode.",
),
),
'primary key' => array('module', 'delta', 'type', 'langcode'),
);
db_create_table('block_language', $schema);
}
/**
* @} End of "addtogroup updates-7.x-to-8.x"
* The next series of updates should start at 9000.
......
......@@ -33,6 +33,18 @@ Drupal.behaviors.blockSettingsSummary = {
return vals.join(', ');
});
$context.find('fieldset#edit-language').drupalSetSummary(function (context) {
var vals = [];
$(context).find('input[type="checkbox"]:checked').each(function () {
vals.push($.trim($(this).next('label').text()));
});
if (!vals.length) {
vals.push(Drupal.t('Not restricted'));
}
return vals.join(', ');
});
$context.find('fieldset#edit-role').drupalSetSummary(function (context) {
var vals = [];
$(context).find('input[type="checkbox"]:checked').each(function () {
......
......@@ -785,6 +785,13 @@ function block_block_list_alter(&$blocks) {
$block_roles[$record->module][$record->delta][] = $record->rid;
}
// Build an array of langcodes allowed per block.
$result = db_query('SELECT module, delta, type, langcode FROM {block_language}');
$block_langcodes = array();
foreach ($result as $record) {
$block_langcodes[$record->module][$record->delta][$record->type][$record->langcode] = TRUE;
}
foreach ($blocks as $key => $block) {
if (!isset($block->theme) || !isset($block->status) || $block->theme != $theme_key || $block->status != 1) {
// This block was added by a contrib module, leave it in the list.
......@@ -854,7 +861,23 @@ function block_block_list_alter(&$blocks) {
}
if (!$page_match) {
unset($blocks[$key]);
continue;
}
// Language visibility settings.
// No language setting for this block, leave it in the list.
if (!isset($block_langcodes[$block->module][$block->delta])) {
continue;
}
foreach ($block_langcodes[$block->module][$block->delta] as $language_type => $langcodes) {
if (isset($langcodes[$GLOBALS[$language_type]->langcode])) {
// Found a language type - langcode combination in the configuration
// that is applicable to the current request.
continue 2;
}
}
// Had language configuration but none matched.
unset($blocks[$key]);
}
}
......@@ -1021,7 +1044,8 @@ function block_admin_paths() {
/**
* Implements hook_modules_uninstalled().
*
* Cleans up {block} and {block_role} tables from modules' blocks.
* Cleans up {block}, {block_role} and {block_language} tables
* from modules' blocks.
*/
function block_modules_uninstalled($modules) {
db_delete('block')
......@@ -1030,4 +1054,19 @@ function block_modules_uninstalled($modules) {
db_delete('block_role')
->condition('module', $modules, 'IN')
->execute();
db_delete('block_language')
->condition('module', $modules, 'IN')
->execute();
}
/**
* Implements hook_language_delete().
*
* Delete the potential block visibility settings of the deleted language.
*/
function block_language_delete($language) {
// Remove the block visibility settings for the deleted language.
db_delete('block_language')
->condition('langcode', $language->langcode)
->execute();
}
......@@ -266,3 +266,190 @@ class LanguageDependencyInjectionTest extends DrupalWebTestCase {
variable_del('language_default');
}
}
/**
* Functional tests for the language list configuration forms.
*/
class LanguageBlockVisibilityTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Language block visibility',
'description' => 'Tests if a block can be configure to be only visibile on a particular language.',
'group' => 'Language',
);
}
function setUp() {
parent::setUp('language', 'locale', 'block');
}
/**
* Tests the visibility settings for the blocks based on language.
*/
public function testLanguageBlockVisibility() {
// Create a new user, allow him to manage the blocks and the languages.
$admin_user = $this->drupalCreateUser(array(
'administer languages', 'administer blocks',
));
$this->drupalLogin($admin_user);
// Add predefined language.
$edit = array(
'predefined_langcode' => 'fr',
);
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
$this->assertText('French', t('Language added successfully.'));
// Check if the visibility setting is available.
$this->drupalGet('admin/structure/block/add');
$this->assertField('langcodes[en]', t('Language visibility field is visible.'));
// Create a new block.
$info_name = $this->randomString(10);
$body = '';
for ($i = 0; $i <= 100; $i++) {
$body .= chr(rand(97, 122));
}
$edit = array(
'regions[stark]' => 'sidebar_first',
'info' => $info_name,
'title' => 'test',
'body[value]' => $body,
);
$this->drupalPost('admin/structure/block/add', $edit, t('Save block'));
// Set visibility setting for one language.
$edit = array(
'langcodes[en]' => TRUE,
);
$this->drupalPost('admin/structure/block/manage/block/1/configure', $edit, t('Save block'));
// Change the default language.
$edit = array(
'site_default' => 'fr',
);
$this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
// Reset the static cache of the language list.
drupal_static_reset('language_list');
// Check that a page has a block
$this->drupalGet('', array('language' => language_load('en')));
$this->assertText($body, t('The body of the custom block appears on the page.'));
// Check that a page doesn't has a block for the current language anymore
$this->drupalGet('', array('language' => language_load('fr')));
$this->assertNoText($body, t('The body of the custom block does not appear on the page.'));
}
/**
* Tests if the visibility settings are removed if the language is deleted.
*/
public function testLanguageBlockVisibilityLanguageDelete() {
// Create a new user, allow him to manage the blocks and the languages.
$admin_user = $this->drupalCreateUser(array(
'administer languages', 'administer blocks',
));
$this->drupalLogin($admin_user);
// Add predefined language.
$edit = array(
'predefined_langcode' => 'fr',
);
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
$this->assertText('French', t('Language added successfully.'));
// Create a new block.
$info_name = $this->randomString(10);
$body = '';
for ($i = 0; $i <= 100; $i++) {
$body .= chr(rand(97, 122));
}
$edit = array(
'regions[stark]' => 'sidebar_first',
'info' => $info_name,
'title' => 'test',
'body[value]' => $body,
);
$this->drupalPost('admin/structure/block/add', $edit, t('Save block'));
// Set visibility setting for one language.
$edit = array(
'langcodes[fr]' => TRUE,
);
$this->drupalPost('admin/structure/block/manage/block/1/configure', $edit, t('Save block'));
// Check that we have an entry in the database after saving the setting.
$count = db_query('SELECT COUNT(langcode) FROM {block_language} WHERE module = :module AND delta = :delta', array(
':module' => 'block',
':delta' => '1'
))->fetchField();
$this->assertTrue($count == 1, t('The block language visibility has an entry in the database.'));
// Delete the language.
$this->drupalPost('admin/config/regional/language/delete/fr', array(), t('Delete'));
// Check that the setting related to this language has been deleted.
$count = db_query('SELECT COUNT(langcode) FROM {block_language} WHERE module = :module AND delta = :delta', array(
':module' => 'block',
':delta' => '1'
))->fetchField();
$this->assertTrue($count == 0, t('The block language visibility do not have an entry in the database.'));
}
/**
* Tests if the visibility settings are removed if the block is deleted.
*/
public function testLanguageBlockVisibilityBlockDelete() {
// Create a new user, allow him to manage the blocks and the languages.
$admin_user = $this->drupalCreateUser(array(
'administer languages', 'administer blocks',
));
$this->drupalLogin($admin_user);
// Add predefined language.
$edit = array(
'predefined_langcode' => 'fr',
);
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
$this->assertText('French', t('Language added successfully.'));
// Create a new block.
$info_name = $this->randomString(10);
$body = '';
for ($i = 0; $i <= 100; $i++) {
$body .= chr(rand(97, 122));
}
$edit = array(
'regions[stark]' => 'sidebar_first',
'info' => $info_name,
'title' => 'test',
'body[value]' => $body,
);
$this->drupalPost('admin/structure/block/add', $edit, t('Save block'));
// Set visibility setting for one language.
$edit = array(
'langcodes[fr]' => TRUE,
);
$this->drupalPost('admin/structure/block/manage/block/1/configure', $edit, t('Save block'));
// Check that we have an entry in the database after saving the setting.
$count = db_query('SELECT COUNT(langcode) FROM {block_language} WHERE module = :module AND delta = :delta', array(
':module' => 'block',
':delta' => '1'
))->fetchField();
$this->assertTrue($count == 1, t('The block language visibility has an entry in the database.'));
// Delete the custom block.
$this->drupalPost('admin/structure/block/manage/block/1/delete', array(), t('Delete'));
// Check that the setting related to this block has been deleted.
$count = db_query('SELECT COUNT(langcode) FROM {block_language} WHERE module = :module AND delta = :delta', array(
':module' => 'block',
':delta' => '1'
))->fetchField();
$this->assertTrue($count == 0, t('The block language visibility do not have an entry in the database.'));
}
}
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