i18n_select.module in Internationalization 7
Multilingual content selection module.
Alters content queries to add language conditions.
Queries tagged with 'i18n_select' or that already have a language condition will not be altered.
File
i18n_select/i18n_select.moduleView source
<?php
/**
* @file
* Multilingual content selection module.
*
* Alters content queries to add language conditions.
*
* Queries tagged with 'i18n_select' or that already have a language condition will not be altered.
*/
// No language selection
define('I18N_SELECT_NONE', 0);
// Content with current language and undefined language
define('I18N_SELECT_NORMAL', 1);
// Select default language when current language is missing
define('I18N_SELECT_MISSING', 2);
/**
* Enable on every page except the listed pages.
*/
define('I18N_SELECT_PAGE_NOTLISTED', 0);
/**
* Enable on only the listed pages.
*/
define('I18N_SELECT_PAGE_LISTED', 1);
/**
* Enable if the associated PHP code returns TRUE.
*/
define('I18N_SELECT_PAGE_PHP', 2);
/**
* Implements hook_init().
*/
function i18n_select_init() {
// Determine selection mode for this page
i18n_select(i18n_select_page());
}
/**
* Implements hook_block_list_alter().
*
* Dirty trick to enable selection for blocks though it may be disabled for the current page.
*/
function i18n_select_block_list_alter(&$blocks) {
// Still, skip for form submission. There are pages like the ones produced
// by overlay that render the blocks before the page.
// See overlay_init(), overlay_overlay_child_initialize()
if (empty($_POST) && !isset($_GET['token']) && variable_get('i18n_select_page_block', TRUE)) {
i18n_select(TRUE);
}
}
/**
* Implements hook_menu().
*/
function i18n_select_menu() {
$items['admin/config/regional/i18n/select'] = array(
'title' => 'Selection',
'description' => 'Configure extended options for multilingual content and translations.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'i18n_select_admin_settings',
),
'access arguments' => array(
'administer site configuration',
),
'file' => 'i18n_select.admin.inc',
'type' => MENU_LOCAL_TASK,
);
return $items;
}
/**
* Get current mode for i18n selection
*
* @param $type
* Selection type: 'nodes', 'taxonomy', etc..
*/
function i18n_select_mode($type = NULL) {
if (i18n_select() && (!$type || variable_get('i18n_select_' . $type, TRUE))) {
return I18N_SELECT_NORMAL;
}
else {
return I18N_SELECT_NONE;
}
}
/**
* Check current path to enable selection.
*
* This works pretty much like block visibility.
*
* @return bool
* TRUE if content selection should be enabled for this page.
*/
function i18n_select_page() {
static $mode;
if (!isset($mode)) {
$mode =& drupal_static(__FUNCTION__);
$visibility = variable_get('i18n_select_page_mode', I18N_SELECT_PAGE_NOTLISTED);
if ($pages = variable_get('i18n_select_page_list', 'admin/*')) {
// Convert path to lowercase. This allows comparison of the same path
// with different case. Ex: /Page, /page, /PAGE.
$pages = drupal_strtolower($pages);
if ($visibility < I18N_SELECT_PAGE_PHP) {
// @see views_ajax()
// @see I18NSelectAdminViewsAjax::testViewsAjaxWithoutSkippingTags()
$path = isset($_REQUEST['view_path']) ? $_REQUEST['view_path'] : $_GET['q'];
// Convert the Drupal path to lowercase.
$path = drupal_strtolower(drupal_get_path_alias($path));
// Compare the lowercase internal and lowercase path alias (if any).
$page_match = drupal_match_path($path, $pages);
if ($path != $_GET['q']) {
$page_match = $page_match || drupal_match_path($_GET['q'], $pages);
}
// When $visibility has a value of 0 (I18N_SELECT_PAGE_NOTLISTED),
// the block is displayed on all pages except those listed in $pages.
// When set to 1 (I18N_SELECT_PAGE_LISTED), it is displayed only on
// those pages listed in $pages.
$mode = !($visibility xor $page_match);
}
elseif (module_exists('php')) {
$mode = php_eval($pages);
}
else {
$mode = FALSE;
}
}
else {
// No pages defined, still respect the setting (unlike blocks).
$mode = $visibility == I18N_SELECT_PAGE_NOTLISTED;
}
}
return $mode;
}
/**
* Implementation of hook_query_node_access_alter().
*
* Rewrite node queries so language selection options are enforced.
*/
function i18n_select_query_node_access_alter(QueryAlterableInterface $query) {
if (i18n_select_mode('nodes') && i18n_select_check_query($query, 'nid') && ($table_alias = i18n_select_check_table($query, 'node', 'nid'))) {
$query
->condition($table_alias . '.language', i18n_select_langcodes());
// Mark query as altered
$query
->addTag('i18n_select');
}
}
/**
* Implementation of hook_query_term_access_alter().
*
* Rewrite taxonomy term queries so language selection options are enforced.
*/
function i18n_select_query_term_access_alter(QueryAlterableInterface $query) {
if (module_exists('i18n_taxonomy') && i18n_select_mode('taxonomy') && i18n_select_check_query($query, 'tid') && ($table_alias = i18n_select_check_table($query, 'taxonomy_term_data', 'tid'))) {
$query
->condition($table_alias . '.language', i18n_select_langcodes());
// Mark query as altered
$query
->addTag('i18n_select');
}
}
/**
* Check table exists in query and get alias for it.
*
* @param $query
* Query object
* @param $table_name
* Table name to find.
* @param $field_name
* field to join the table if needed.
*
* @return
* Table alias if found, none if not.
*/
function i18n_select_check_table($query, $table_name, $field_name) {
$tables = $query
->getTables();
foreach ($tables as $table) {
if (!$table instanceof SelectQueryInterface && $table['table'] == $table_name) {
return _i18n_select_table_alias($table);
}
}
// Join the table if we can find the key field on any of the tables
// And all the conditions have a table alias (or there's a unique table).
if (count($tables) == 1) {
$table = reset($tables);
$table_alias = _i18n_select_table_alias($table);
if (i18n_select_check_conditions($query, $table_alias)) {
$join_table = $table_alias;
}
}
elseif (i18n_select_check_conditions($query)) {
// Try to find the right field in the table schema.
foreach ($tables as $table) {
$schema = drupal_get_schema($table['table']);
if ($schema && !empty($schema['fields'][$field_name])) {
$join_table = _i18n_select_table_alias($table);
break;
}
}
}
if (!empty($join_table)) {
return $query
->join($table_name, $table_name, $join_table . '.' . $field_name . ' = %alias.' . $field_name);
}
else {
return FALSE;
}
}
/**
* Get table alias
*/
function _i18n_select_table_alias($table) {
return !empty($table['alias']) ? $table['alias'] : $table['table'];
}
/**
* Check all query conditions have a table alias.
*
* @param $table_alias
* Optional table alias for fields without table.
*
* @return boolean
* TRUE if table conditions are ok, FALSE otherwise.
*/
function i18n_select_check_conditions($query, $table_alias = NULL) {
$conditions =& $query
->conditions();
foreach ($conditions as $index => $condition) {
if (is_array($condition) && !empty($condition['field'])) {
if (strpos($condition['field'], '.') === FALSE) {
if ($table_alias) {
// Change the condition to include a table alias.
$conditions[$index]['field'] = $table_alias . '.' . $condition['field'];
}
else {
// We won't risk joining anything here.
return FALSE;
}
}
}
}
return TRUE;
}
/**
* Check whether we should apply language conditions here:
* - The query has not been tagged with 'i18n_select'
* - The query doesn't have already a language condition
* - All the conditions have a table alias or there's only one table.
* - We are not loading specific objects (no condition for index field).
*
* @param $query
* Query object.
* @param $index_field
* Object index field to check we don't have 'IN' conditions for it.
*/
function i18n_select_check_query($query, $index_field = NULL) {
static $tags;
// Skip queries with certain tags
if (!isset($tags)) {
$tags = ($skip = variable_get('i18n_select_skip_tags', 'views')) ? array_map('trim', explode(',', $skip)) : array();
$tags[] = 'i18n_select';
}
foreach ($tags as $tag) {
if ($query
->hasTag($tag)) {
return FALSE;
}
}
// Check all the conditions to see whether the query is suitable for altering.
foreach ($query
->conditions() as $condition) {
if (is_array($condition)) {
// @todo For some complex queries, like search ones, field is a DatabaseCondition object
if (!isset($condition['field']) || !is_string($condition['field'])) {
// There's a weird condition field, we won't take any chances.
return FALSE;
}
else {
// Just check the condition doesn't include the language field
if (strpos($condition['field'], '.') === FALSE) {
$field = $condition['field'];
}
else {
list($table, $field) = explode('.', $condition['field']);
}
if ($field == 'language') {
return FALSE;
}
// Check 'IN' conditions for index field, usually entity loading for specific objects.
if ($field == $index_field && $condition['operator'] == 'IN') {
return FALSE;
}
}
}
}
// If the language field is present we don't want to do any filtering.
$fields = $query
->getFields();
if (isset($fields['language'])) {
return FALSE;
}
return TRUE;
}
/**
* Get main language for content selection
*/
function i18n_select_language() {
return $GLOBALS[LANGUAGE_TYPE_CONTENT];
}
/**
* Get language codes for content selection to use in query conditions
*/
function i18n_select_langcodes() {
return array(
i18n_select_language()->language,
LANGUAGE_NONE,
);
}
Functions
Name | Description |
---|---|
i18n_select_block_list_alter | Implements hook_block_list_alter(). |
i18n_select_check_conditions | Check all query conditions have a table alias. |
i18n_select_check_query | Check whether we should apply language conditions here: |
i18n_select_check_table | Check table exists in query and get alias for it. |
i18n_select_init | Implements hook_init(). |
i18n_select_langcodes | Get language codes for content selection to use in query conditions |
i18n_select_language | Get main language for content selection |
i18n_select_menu | Implements hook_menu(). |
i18n_select_mode | Get current mode for i18n selection |
i18n_select_page | Check current path to enable selection. |
i18n_select_query_node_access_alter | Implementation of hook_query_node_access_alter(). |
i18n_select_query_term_access_alter | Implementation of hook_query_term_access_alter(). |
_i18n_select_table_alias | Get table alias |
Constants
Name | Description |
---|---|
I18N_SELECT_MISSING | |
I18N_SELECT_NONE | |
I18N_SELECT_NORMAL | |
I18N_SELECT_PAGE_LISTED | Enable on only the listed pages. |
I18N_SELECT_PAGE_NOTLISTED | Enable on every page except the listed pages. |
I18N_SELECT_PAGE_PHP | Enable if the associated PHP code returns TRUE. |