123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- <?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 boolean
- * 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) {
- // Convert the Drupal path to lowercase
- $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
- // 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);
- }
|