'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); }