Projet

Général

Profil

Paste
Télécharger (9,64 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / i18n / i18n_select / i18n_select.module @ 9faa5de0

1
<?php
2
/**
3
 * @file
4
 * Multilingual content selection module.
5
 *
6
 * Alters content queries to add language conditions.
7
 *
8
 * Queries tagged with 'i18n_select' or that already have a language condition will not be altered.
9
 */
10

    
11
// No language selection
12
define('I18N_SELECT_NONE', 0);
13
// Content with current language and undefined language
14
define('I18N_SELECT_NORMAL', 1);
15
// Select default language when current language is missing
16
define('I18N_SELECT_MISSING', 2);
17

    
18
/**
19
 * Enable on every page except the listed pages.
20
 */
21
define('I18N_SELECT_PAGE_NOTLISTED', 0);
22
/**
23
 * Enable on only the listed pages.
24
 */
25
define('I18N_SELECT_PAGE_LISTED', 1);
26
/**
27
 * Enable if the associated PHP code returns TRUE.
28
 */
29
define('I18N_SELECT_PAGE_PHP', 2);
30

    
31
/**
32
 * Implements hook_init().
33
 */
34
function i18n_select_init() {
35
  // Determine selection mode for this page
36
  i18n_select(i18n_select_page());
37
}
38

    
39
/**
40
 * Implements hook_block_list_alter().
41
 *
42
 * Dirty trick to enable selection for blocks though it may be disabled for the current page.
43
 */
44
function i18n_select_block_list_alter(&$blocks) {
45
  // Still, skip for form submission. There are pages like the ones produced
46
  // by overlay that render the blocks before the page.
47
  // See overlay_init(), overlay_overlay_child_initialize()
48
  if (empty($_POST) && !isset($_GET['token']) && variable_get('i18n_select_page_block', TRUE)) {
49
    i18n_select(TRUE);
50
  }
51
}
52

    
53
/**
54
 * Implements hook_menu().
55
 */
56
function i18n_select_menu() {
57
  $items['admin/config/regional/i18n/select'] = array(
58
    'title' => 'Selection',
59
    'description' => 'Configure extended options for multilingual content and translations.',
60
    'page callback' => 'drupal_get_form',
61
    'page arguments' => array('i18n_select_admin_settings'),
62
    'access arguments' => array('administer site configuration'),
63
    'file' => 'i18n_select.admin.inc',
64
    'type' => MENU_LOCAL_TASK,
65
  );
66
  return $items;
67
}
68

    
69
/**
70
 * Get current mode for i18n selection
71
 *
72
 * @param $type
73
 *   Selection type: 'nodes', 'taxonomy', etc..
74
 */
75
function i18n_select_mode($type = NULL) {
76
  if (i18n_select() && (!$type || variable_get('i18n_select_' . $type, TRUE))) {
77
    return I18N_SELECT_NORMAL;
78
  }
79
  else {
80
    return I18N_SELECT_NONE;
81
  }
82
}
83

    
84
/**
85
 * Check current path to enable selection.
86
 *
87
 * This works pretty much like block visibility.
88
 *
89
 * @return bool
90
 *   TRUE if content selection should be enabled for this page.
91
 */
92
function i18n_select_page() {
93
  static $mode;
94

    
95
  if (!isset($mode)) {
96
    $mode = &drupal_static(__FUNCTION__);
97
    $visibility = variable_get('i18n_select_page_mode', I18N_SELECT_PAGE_NOTLISTED);
98
    if ($pages = variable_get('i18n_select_page_list', 'admin/*')) {
99
      // Convert path to lowercase. This allows comparison of the same path
100
      // with different case. Ex: /Page, /page, /PAGE.
101
      $pages = drupal_strtolower($pages);
102
      if ($visibility < I18N_SELECT_PAGE_PHP) {
103
        // @see views_ajax()
104
        // @see I18NSelectAdminViewsAjax::testViewsAjaxWithoutSkippingTags()
105
        $path = isset($_REQUEST['view_path']) ? $_REQUEST['view_path'] : $_GET['q'];
106
        // Convert the Drupal path to lowercase.
107
        $path = drupal_strtolower(drupal_get_path_alias($path));
108
        // Compare the lowercase internal and lowercase path alias (if any).
109
        $page_match = drupal_match_path($path, $pages);
110
        if ($path != $_GET['q']) {
111
          $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
112
        }
113
        // When $visibility has a value of 0 (I18N_SELECT_PAGE_NOTLISTED),
114
        // the block is displayed on all pages except those listed in $pages.
115
        // When set to 1 (I18N_SELECT_PAGE_LISTED), it is displayed only on
116
        // those pages listed in $pages.
117
        $mode = !($visibility xor $page_match);
118
      }
119
      elseif (module_exists('php')) {
120
        $mode = php_eval($pages);
121
      }
122
      else {
123
        $mode = FALSE;
124
      }
125
    }
126
    else {
127
      // No pages defined, still respect the setting (unlike blocks).
128
      $mode = $visibility == I18N_SELECT_PAGE_NOTLISTED;
129
    }
130
  }
131

    
132
  return $mode;
133
}
134

    
135
/**
136
 * Implementation of hook_query_node_access_alter().
137
 *
138
 * Rewrite node queries so language selection options are enforced.
139
 */
140
function i18n_select_query_node_access_alter(QueryAlterableInterface $query) {
141
  if (i18n_select_mode('nodes') && i18n_select_check_query($query, 'nid') &&
142
    ($table_alias = i18n_select_check_table($query, 'node', 'nid'))) {
143
    $query->condition($table_alias . '.language', i18n_select_langcodes());
144
    // Mark query as altered
145
    $query->addTag('i18n_select');
146
  }
147
}
148

    
149
/**
150
 * Implementation of hook_query_term_access_alter().
151
 *
152
 * Rewrite taxonomy term queries so language selection options are enforced.
153
 */
154
function i18n_select_query_term_access_alter(QueryAlterableInterface $query) {
155
  if (module_exists('i18n_taxonomy') && i18n_select_mode('taxonomy') && i18n_select_check_query($query, 'tid') &&
156
    ($table_alias = i18n_select_check_table($query, 'taxonomy_term_data', 'tid'))) {
157
    $query->condition($table_alias . '.language', i18n_select_langcodes());
158
    // Mark query as altered
159
    $query->addTag('i18n_select');
160
  }
161
}
162

    
163
/**
164
 * Check table exists in query and get alias for it.
165
 *
166
 * @param $query
167
 *   Query object
168
 * @param $table_name
169
 *   Table name to find.
170
 * @param $field_name
171
 *   field to join the table if needed.
172
 *
173
 * @return
174
 *   Table alias if found, none if not.
175
 */
176
function i18n_select_check_table($query, $table_name, $field_name) {
177
  $tables = $query->getTables();
178
  foreach ($tables as $table) {
179
    if (!($table instanceof SelectQueryInterface) && $table['table'] == $table_name) {
180
      return _i18n_select_table_alias($table);
181
    }
182
  }
183
  // Join the table if we can find the key field on any of the tables
184
  // And all the conditions have a table alias (or there's a unique table).
185
  if (count($tables) == 1) {
186
    $table = reset($tables);
187
    $table_alias = _i18n_select_table_alias($table);
188
    if (i18n_select_check_conditions($query, $table_alias)) {
189
      $join_table = $table_alias;
190
    }
191
  }
192
  elseif (i18n_select_check_conditions($query)) {
193
    // Try to find the right field in the table schema.
194
    foreach ($tables as $table) {
195
      $schema = drupal_get_schema($table['table']);
196
      if ($schema && !empty($schema['fields'][$field_name])) {
197
        $join_table = _i18n_select_table_alias($table);
198
        break;
199
      }
200
    }
201
  }
202
  if (!empty($join_table)) {
203
    return $query->join($table_name, $table_name, $join_table . '.' . $field_name . ' = %alias.' . $field_name);
204
  }
205
  else {
206
    return FALSE;
207
  }
208
}
209

    
210
/**
211
 * Get table alias
212
 */
213
function _i18n_select_table_alias($table) {
214
  return !empty($table['alias']) ? $table['alias'] : $table['table'];
215
}
216

    
217
/**
218
 * Check all query conditions have a table alias.
219
 *
220
 * @param $table_alias
221
 *   Optional table alias for fields without table.
222
 *
223
 * @return boolean
224
 *   TRUE if table conditions are ok, FALSE otherwise.
225
 */
226
function i18n_select_check_conditions($query, $table_alias = NULL) {
227
  $conditions =& $query->conditions();
228
  foreach ($conditions as $index => $condition) {
229
    if (is_array($condition) && !empty($condition['field'])) {
230
      if (strpos($condition['field'], '.') === FALSE) {
231
        if ($table_alias) {
232
          // Change the condition to include a table alias.
233
          $conditions[$index]['field'] = $table_alias . '.' . $condition['field'];
234
        }
235
        else {
236
          // We won't risk joining anything here.
237
          return FALSE;
238
        }
239
      }
240
    }
241
  }
242
  return TRUE;
243
}
244

    
245
/**
246
 * Check whether we should apply language conditions here:
247
 * - The query has not been tagged with 'i18n_select'
248
 * - The query doesn't have already a language condition
249
 * - All the conditions have a table alias or there's only one table.
250
 * - We are not loading specific objects (no condition for index field).
251
 *
252
 * @param $query
253
 *   Query object.
254
 * @param $index_field
255
 *   Object index field to check we don't have 'IN' conditions for it.
256
 */
257
function i18n_select_check_query($query, $index_field = NULL) {
258
  static $tags;
259
  // Skip queries with certain tags
260
  if (!isset($tags)) {
261
    $tags = ($skip = variable_get('i18n_select_skip_tags', 'views')) ? array_map('trim', explode(',', $skip)) : array();
262
    $tags[] = 'i18n_select';
263
  }
264
  foreach ($tags as $tag) {
265
    if ($query->hasTag($tag)) {
266
      return FALSE;
267
    }
268
  }
269
  // Check all the conditions to see whether the query is suitable for altering.
270
  foreach ($query->conditions() as $condition) {
271
    if (is_array($condition)) {
272
      // @todo For some complex queries, like search ones, field is a DatabaseCondition object
273
      if (!isset($condition['field']) || !is_string($condition['field'])) {
274
        // There's a weird condition field, we won't take any chances.
275
        return FALSE;
276
      }
277
      else {
278
        // Just check the condition doesn't include the language field
279
        if (strpos($condition['field'], '.') === FALSE) {
280
          $field = $condition['field'];
281
        }
282
        else {
283
          list($table, $field) = explode('.', $condition['field']);
284
        }
285
        if ($field == 'language') {
286
          return FALSE;
287
        }
288
        // Check 'IN' conditions for index field, usually entity loading for specific objects.
289
        if ($field == $index_field && $condition['operator'] == 'IN') {
290
          return FALSE;
291
        }
292
      }
293
    }
294
  }
295
  // If the language field is present we don't want to do any filtering.
296
  $fields = $query->getFields();
297
  if (isset($fields['language'])) {
298
    return FALSE;
299
  }
300

    
301
  return TRUE;
302
}
303

    
304
/**
305
 * Get main language for content selection
306
 */
307
function i18n_select_language() {
308
  return $GLOBALS[LANGUAGE_TYPE_CONTENT];
309
}
310

    
311
/**
312
 * Get language codes for content selection to use in query conditions
313
 */
314
function i18n_select_langcodes() {
315
  return array(i18n_select_language()->language, LANGUAGE_NONE);
316
}
317