Projet

Général

Profil

Révision 98a362c2

Ajouté par Assos Assos il y a plus de 6 ans

Weekly update of contrib modules

Voir les différences:

drupal7/sites/all/modules/shs/shs.module
28 28
 * Implements hook_js().
29 29
 */
30 30
function shs_js() {
31
  return array(
31
  $settings = array(
32 32
    'json' => array(
33 33
      'callback' => 'shs_json',
34
      'access callback'  => 'user_access',
34
      'access callback' => 'user_access',
35 35
      'access arguments' => array('access content'),
36
      'dependencies' => array('taxonomy'),
36
      'includes' => array('path'),
37
      'dependencies' => array('taxonomy', 'field', 'field_sql_storage'),
37 38
    ),
38 39
  );
40
  drupal_alter('shs_js_info', $settings);
41
  return $settings;
42
}
43

  
44
/**
45
 * Implements hook_requirements().
46
 */
47
function shs_requirements($phase) {
48
  $requirements = array();
49
  $t = get_t();
50

  
51
  if ($phase !== 'runtime' || !module_exists('chosen')) {
52
    return $requirements;
53
  }
54
  if (($info = drupal_get_library('chosen', 'chosen')) === FALSE) {
55
    return $requirements;
56
  }
57
  // Chosen version should be at least 1.0.
58
  if (version_compare($info['version'], '1.1.0') < 0) {
59
    $requirements['shs'] = array(
60
      'title' => $t('Simple hierarchical select: chosen integration'),
61
      'description' => $t('If you would like to use chosen with Simple hierarchical select you need to install at least version 1.1.0 of !chosen_library.', array('!chosen_library' => l('Chosen', 'http://harvesthq.github.io/chosen/'))),
62
      'severity' => REQUIREMENT_WARNING,
63
      'value' => $t('Chosen library too old (installed version is !version)', array('!version' => $info['version'])),
64
    );
65
  }
66

  
67
  return $requirements;
39 68
}
40 69

  
41 70
/**
......
80 109
    'shs_json_term_get_children' => array(
81 110
      'callback' => 'shs_json_term_get_children',
82 111
      'arguments' => array(
83
        'vid' => 'is_numeric',
112
        'vid' => 'shs_json_validation_vocabulary_identifier',
84 113
        'parent' => 'is_array',
85 114
        'settings' => 'is_array',
115
        'field' => 'is_string',
86 116
      ),
87 117
    ),
88 118
    'shs_json_term_add' => array(
89 119
      'callback' => 'shs_json_term_add',
90 120
      'arguments' => array(
91
        'vid' => 'is_numeric',
121
        'vid' => 'shs_json_validation_vocabulary_identifier',
92 122
        'parent' => 'is_numeric',
93 123
        'name' => 'is_string',
124
        'field' => 'is_string',
94 125
      ),
95 126
    ),
96 127
  );
......
116 147
  // Get arguments from callback definition.
117 148
  $callback_arguments = $callback['arguments'];
118 149
  foreach ($arguments as $key => $value) {
119
    if (isset($callback_arguments[$key])) {
120
      $argument_valid = TRUE;
121
      if ((($validation_function = $callback_arguments[$key]) !== FALSE) && function_exists($validation_function)) {
122
        // Validate argument.
123
        $argument_valid = $validation_function($value);
124
      }
125
      if ($argument_valid) {
126
        // Add argument and its value to the result list.
127
        $result[$key] = $value;
128
      }
150
    if (!isset($callback_arguments[$key])) {
151
      continue;
152
    }
153
    $argument_valid = TRUE;
154
    if ((($validation_function = $callback_arguments[$key]) !== FALSE) && function_exists($validation_function)) {
155
      // Validate argument.
156
      $argument_valid = $validation_function($value);
157
    }
158
    if ($argument_valid) {
159
      // Add argument and its value to the result list.
160
      $result[$key] = $value;
129 161
    }
130 162
  }
131 163
  return $result;
......
135 167
 * Implements hook_views_data_alter().
136 168
 */
137 169
function shs_views_data_alter(&$data) {
138
  // Get a list of all field instances with widget type "taxonomy_shs".
139
  $instances = _shs_get_instances('node');
140
  foreach ($instances as $field_instances) {
141
    foreach ($field_instances as $field_name => $instance) {
142
      // Replace filter handler for this field.
143
      if (!empty($data["field_data_{$field_name}"]["{$field_name}_tid"]['filter']['handler'])) {
144
        $data["field_data_{$field_name}"]["{$field_name}_tid"]['filter']['handler'] = 'shs_handler_filter_term_node_tid';
145
      }
146
    }
147
  }
148

  
149 170
  // Add filter handler for term ID with depth.
150 171
  $data['node']['shs_term_node_tid_depth'] = array(
151 172
    'help' => t('Display content if it has the selected taxonomy terms, or children of the selected terms. Due to additional complexity, this has fewer options than the versions without depth. Optionally the filter will use a simple hierarchical select for the selection of terms.'),
152 173
    'real field' => 'nid',
153 174
    'filter' => array(
154
      'title' => t('Has taxonomy terms (with depth; %type)', array('%type' => 'Simple hierarchical select')),
175
      'title' => t('Has taxonomy terms (with depth; @type)', array('@type' => 'Simple hierarchical select')),
155 176
      'handler' => 'shs_handler_filter_term_node_tid_depth',
156 177
    ),
157 178
  );
158 179
}
159 180

  
181
/**
182
 * Implements hook_field_views_data_alter().
183
 */
184
function shs_field_views_data_alter(&$result, &$field, $module) {
185
  if (empty($field['columns']) || !in_array($field['type'], array('taxonomy_term_reference', 'entityreference'))) {
186
    return;
187
  }
188
  if ($field['type'] == 'entityreference' && (empty($field['settings']['target_type']) || $field['settings']['target_type'] != 'taxonomy_term')) {
189
    // Do not change entityreference fields that do not reference terms.
190
    return;
191
  }
192
  $field_column = key($field['columns']);
193
  foreach ($result as $key => $group) {
194
    $field_identifier = sprintf('%s_%s', $field['field_name'], $field_column);
195
    if (empty($group[$field_identifier]) || empty($group[$field_identifier]['filter']['handler'])) {
196
      // Only modify field definitions for the primary column.
197
      continue;
198
    }
199
    // Replace handler.
200
    $result[$key][$field_identifier]['filter']['handler'] = ($field['type'] == 'entityreference') ? 'shs_handler_filter_entityreference' : 'shs_handler_filter_term_node_tid';
201
  }
202
}
203

  
204
/**
205
 * Implements hook_conditional_fields_states_handlers_alter().
206
 */
207
function shs_conditional_fields_states_handlers_alter(&$handlers) {
208
  $handlers += array(
209
    'shs_conditional_fields_states_handler_shs' => array(
210
      array(
211
        'tid' => array(
212
          '#type' => 'select',
213
        ),
214
      ),
215
    ),
216
  );
217
}
218

  
219
/**
220
 * States handler for simple hierarchical selects.
221
 */
222
function shs_conditional_fields_states_handler_shs($field, $field_info, &$options, &$state) {
223
  switch ($options['values_set']) {
224
    case CONDITIONAL_FIELDS_DEPENDENCY_VALUES_WIDGET:
225
    case CONDITIONAL_FIELDS_DEPENDENCY_VALUES_AND:
226
      if (empty($state[$options['state']][$options['selector']])) {
227
        return;
228
      }
229
      $old_state = $state[$options['state']][$options['selector']];
230
      if (isset($old_state['value'][0]['tid'])) {
231
        // Completly remove old state.
232
        unset($state[$options['state']][$options['selector']]);
233
        $options['selector'] .= '-0-tid';
234
        $state[$options['state']][$options['selector']] = $old_state;
235
        $state[$options['state']][$options['selector']]['value'] = $old_state['value'][0]['tid'];
236
      }
237
      return;
238

  
239
    case CONDITIONAL_FIELDS_DEPENDENCY_VALUES_XOR:
240
      $select_states[$options['state']][] = 'xor';
241

  
242
    case CONDITIONAL_FIELDS_DEPENDENCY_VALUES_REGEX:
243
      $regex = TRUE;
244
    case CONDITIONAL_FIELDS_DEPENDENCY_VALUES_NOT:
245
    case CONDITIONAL_FIELDS_DEPENDENCY_VALUES_OR:
246
      foreach ($options['values'] as $value) {
247
        $select_states[$options['state']][] = array(
248
          $options['selector'] => array(
249
            $options['condition'] => empty($regex) ? array($value) : $options['value'],
250
          ),
251
        );
252
      }
253
      break;
254
  }
255

  
256
  $state = $select_states;
257
}
258

  
160 259
/**
161 260
 * Implements hook_field_widget_info().
162 261
 */
......
164 263
  return array(
165 264
    'taxonomy_shs' => array(
166 265
      'label' => t('Simple hierarchical select'),
167
      'field types' => array('taxonomy_term_reference'),
266
      'field types' => array('taxonomy_term_reference', 'entityreference'),
168 267
      'settings' => array(
169 268
        'shs' => array(
170
          'node_count' => FALSE,
171 269
          'create_new_terms' => FALSE,
172 270
          'create_new_levels' => FALSE,
173 271
          'force_deepest' => FALSE,
......
178 276
}
179 277

  
180 278
/**
181
 * Implements hook__field_widget_settings_form().
279
 * Implements hook_form_FORM_ID_alter().
280
 */
281
function shs_form_field_ui_field_settings_form_alter(&$form, &$form_state, $form_id) {
282
  if (module_exists('entityreference') && $form['field']['type']['#value'] == 'entityreference' && $form['field']['settings']['#instance']['widget']['type'] == 'taxonomy_shs') {
283
    $form['field']['settings']['#field']['settings']['target_type'] = 'taxonomy_term';
284
    $form['field']['settings']['#process'][] = 'shs_entityreference_field_settings_process';
285
  }
286
}
287

  
288
/**
289
 * Implements hook_form_FORM_ID_alter().
290
 */
291
function shs_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
292
  if (module_exists('entityreference') && $form['#field']['type'] == 'entityreference' && $form['#instance']['widget']['type'] == 'taxonomy_shs') {
293
    $form['#field']['settings']['target_type'] = 'taxonomy_term';
294
    $form['field']['settings']['#process'][] = 'shs_entityreference_field_settings_process';
295
  }
296
}
297

  
298
/**
299
 * Additional processing function for the entityreference field settings form.
300
 *
301
 * @param array $form
302
 *   Form structure to process.
303
 * @param array $form_state
304
 *   Current form state.
305
 *
306
 * @return array
307
 *   Processed form structure.
308
 */
309
function shs_entityreference_field_settings_process($form, $form_state) {
310
  if (!empty($form['target_type'])) {
311
    // Reduce list of available target types to taxonomy terms.
312
    $form['target_type']['#options'] = array(
313
      'taxonomy_term' => t('Taxonomy term'),
314
    );
315
  }
316
  return $form;
317
}
318

  
319
/**
320
 * Implements hook_field_widget_settings_form().
182 321
 */
183 322
function shs_field_widget_settings_form($field, $instance) {
184 323
  $widget = $instance['widget'];
......
193 332
    '#collapsed' => FALSE,
194 333
    '#tree' => TRUE,
195 334
  );
196
  $form['shs']['node_count'] = array(
197
    '#type' => 'checkbox',
198
    '#title' => t('Display number of nodes'),
199
    '#description' => t('Display the number of nodes associated with the term.'),
200
    '#default_value' => empty($settings['shs']['node_count']) ? FALSE : $settings['shs']['node_count'],
201
  );
202
  $form['shs']['create_new_terms'] = array(
203
    '#type' => 'checkbox',
204
    '#title' => t('Allow creating new terms'),
205
    '#description' => t('If checked the user will be able to create new terms (permission to edit terms in this vocabulary must be set).'),
206
    '#default_value' => empty($settings['shs']['create_new_terms']) ? FALSE : $settings['shs']['create_new_terms'],
207
  );
208
  $form['shs']['create_new_levels'] = array(
209
    '#type' => 'checkbox',
210
    '#title' => t('Allow creating new levels'),
211
    '#description' => t('If checked the user will be able to create new children for items which do not have any children yet (permission to edit terms in this vocabulary must be set).'),
212
    '#default_value' => empty($settings['shs']['create_new_levels']) ? FALSE : $settings['shs']['create_new_levels'],
213
    '#states' => array(
214
      'visible' => array(
215
        ':input[name="instance[widget][settings][shs][create_new_terms]"]' => array('checked' => TRUE),
335

  
336
  if ($field['type'] != 'entityreference' || ($field['type'] == 'entityreference' && !empty($field['settings']['handler_settings']['target_bundles']) && count($field['settings']['handler_settings']['target_bundles']) == 1)) {
337
    $form['shs']['create_new_terms'] = array(
338
      '#type' => 'checkbox',
339
      '#title' => t('Allow creating new terms'),
340
      '#description' => t('If checked the user will be able to create new terms (permission to edit terms in this vocabulary must be set).'),
341
      '#default_value' => empty($settings['shs']['create_new_terms']) ? FALSE : $settings['shs']['create_new_terms'],
342
    );
343
    $form['shs']['create_new_levels'] = array(
344
      '#type' => 'checkbox',
345
      '#title' => t('Allow creating new levels'),
346
      '#description' => t('If checked the user will be able to create new children for items which do not have any children yet (permission to edit terms in this vocabulary must be set).'),
347
      '#default_value' => empty($settings['shs']['create_new_levels']) ? FALSE : $settings['shs']['create_new_levels'],
348
      '#states' => array(
349
        'visible' => array(
350
          ':input[name="instance[widget][settings][shs][create_new_terms]"]' => array('checked' => TRUE),
351
        ),
216 352
      ),
217
    ),
218
  );
353
    );
354
  }
219 355
  $form['shs']['force_deepest'] = array(
220 356
    '#type' => 'checkbox',
221 357
    '#title' => t('Force selection of deepest level'),
......
252 388
 * Implements hook_field_widget_form().
253 389
 */
254 390
function shs_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
391
  $field_column = key($field['columns']);
255 392
  // Get value.
256 393
  $element_value = NULL;
257
  if (!empty($items[$delta]['tid'])) {
394
  $submitted_value = NULL;
395
  if (!empty($form_state['values']) && !empty($element['#parents'])) {
396
    $submitted_value = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
397
  }
398
  if (!empty($items[$delta][$field_column])) {
258 399
    // Use saved value from database or cache.
259
    $element_value = $items[$delta]['tid'];
400
    $element_value = $items[$delta][$field_column];
260 401
  }
261
  elseif (!empty($form_state['values'][$element['#field_name']][$element['#language']][$delta]['tid'])) {
402
  elseif (!empty($submitted_value)) {
262 403
    // Use value from form_state (for example for fields with cardinality = -1).
263
    $element_value = $form_state['values'][$element['#field_name']][$element['#language']][$delta]['tid'];
404
    $element_value = array('tid' => $submitted_value);
264 405
  }
265 406

  
266
  // Get vocabulary.
267
  $allowed_values = reset($field['settings']['allowed_values']);
268
  if (empty($allowed_values['vocabulary']) || ($vocabulary = taxonomy_vocabulary_machine_name_load($allowed_values['vocabulary'])) === FALSE) {
269
    // No vocabulary selected yet or vocabulary not found.
407
  // Get vocabulary names from allowed values.
408
  if ($field['type'] == 'entityreference') {
409
    if ('views' === $field['settings']['handler']) {
410
      $vocabulary_names = array();
411
      $view_settings = $field['settings']['handler_settings']['view'];
412
      // Try to load vocabularies from view filter.
413
      $vocabulary_names = _shs_entityreference_views_get_vocabularies($view_settings['view_name'], $view_settings['display_name']);
414
    }
415
    else {
416
      $vocabulary_names = $field['settings']['handler_settings']['target_bundles'];
417
    }
418
  }
419
  else {
420
    $allowed_values = reset($field['settings']['allowed_values']);
421
    $vocabulary_names = empty($allowed_values['vocabulary']) ? FALSE : $allowed_values['vocabulary'];
422
  }
423
  if (empty($vocabulary_names) && (empty($field['settings']['handler']) || ('views' !== $field['settings']['handler']))) {
424
    // No vocabulary selected yet.
270 425
    return array();
271 426
  }
427
  if (!is_array($vocabulary_names)) {
428
    $vocabulary_names = array($vocabulary_names);
429
  }
430
  $vocabularies = array();
431
  foreach ($vocabulary_names as $vocabulary_name) {
432
    if (($vocabulary = taxonomy_vocabulary_machine_name_load($vocabulary_name)) === FALSE) {
433
      // Vocabulary not found. Stop here.
434
      return array();
435
    }
436
    $vocabularies[] = $vocabulary;
437
  }
272 438

  
273
  // Check if term exists (may be deleted).
439
  // Check if term exists (the term could probably be deleted meanwhile).
274 440
  if ($element_value && (($term = taxonomy_term_load($element_value)) === FALSE)) {
275 441
    $element_value = 0;
276 442
  }
277 443

  
278
  if (!user_access('edit terms in ' . $vocabulary->vid)) {
279
    // Update setting based on permission.
444
  if (count($vocabularies) > 1 || !isset($vocabulary) || (isset($vocabulary) && !user_access('edit terms in ' . $vocabulary->vid))) {
445
    // Creating new terms is allowed only with proper permission and if only one
446
    // vocabulary is selected as source.
280 447
    $instance['widget']['settings']['shs']['create_new_terms'] = FALSE;
281 448
  }
449
  $instance['widget']['settings']['shs']['test_create_new_terms'] = module_implements('shs_add_term_access');
282 450
  $instance['widget']['settings']['shs']['required'] = $element['#required'];
283 451

  
284
  // Element is required and there is no initial value.
285
  if (empty($element_value) && $element['#required']) {
286
    // Load list of options.
287
    $options = shs_term_get_children($vocabulary->vid, 0);
288
    if (count($options)) {
289
      // Set element value to first available option.
290
      $option_keys = array_keys($options);
291
      $element_value = reset($option_keys);
452
  // Prepare the list of options.
453
  if ($field['type'] == 'entityreference') {
454
    // Get current selection handler.
455
    $handler = entityreference_get_selection_handler($field, $instance, $element['#entity_type'], $element['#entity']);
456
    $referencable_entities = $handler->getReferencableEntities();
457
    $options = array(
458
      '_none' => empty($element['#required']) ? t('- None -', array(), array('context' => 'shs')) : t('- Select a value -', array(), array('context' => 'shs')),
459
    );
460
    foreach ($referencable_entities as $v_name => $terms) {
461
      $options += $terms;
292 462
    }
293 463
  }
294

  
464
  else {
465
    $properties = _options_properties('select', FALSE, $element['#required'], !empty($element_value));
466
    $options = _options_get_options($field, $instance, $properties, $element['#entity_type'], $element['#entity']);
467
  }
295 468
  // Create element.
296 469
  $element += array(
297
    '#type' => 'textfield',
470
    '#type' => 'select',
298 471
    '#default_value' => empty($element_value) ? NULL : $element_value,
472
    '#options' => $options,
299 473
    '#attributes' => array(
300 474
      'class' => array('shs-enabled'),
301 475
    ),
......
304 478
    '#element_validate' => array('shs_field_widget_validate'),
305 479
    '#after_build' => array('shs_field_widget_afterbuild'),
306 480
    '#shs_settings' => $instance['widget']['settings']['shs'],
307
    '#shs_vocabulary' => $vocabulary,
481
    '#shs_vocabularies' => $vocabularies,
308 482
  );
309 483

  
310
  return array('tid' => $element);
484
  $return = array($field_column => $element);
485
  if (!empty($element['#title'])) {
486
    // Set title to "parent" element to enable label translation.
487
    $return['#title'] = $element['#title'];
488
  }
489
  return $return;
311 490
}
312 491

  
313 492
/**
......
324 503
  }
325 504

  
326 505
  $parents = array();
327
  // Get value from element.
328
  if (!empty($form_state['values'][$element['#field_name']][$element['#language']][$element['#delta']]['tid'])) {
506
  // Get default value from form state and set it to element.
507
  $default_value = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
508
  if (!empty($default_value)) {
329 509
    // Use value from form_state (for example for fields with cardinality = -1).
330
    $element['#default_value'] = $form_state['values'][$element['#field_name']][$element['#language']][$element['#delta']];
510
    $element['#default_value'] = $default_value;
331 511
  }
332 512

  
333 513
  // Add main Javascript behavior and style only once.
......
341 521
  // Create Javascript settings for the element only if it hasn't been added
342 522
  // before.
343 523
  if (empty($js_added[$element['#name']][$js_hash])) {
344
    $element_value = $element['#default_value']['tid'];
524
    $element_value = $element['#default_value'];
345 525

  
346
    if (empty($element_value)) {
347
      // Add fake parent for new items.
526
    // Ensure field is rendered if it is required but not selected.
527
    if (empty($element_value) || $element_value == '_none') {
528
      // Add fake parent for new items or field required submit fail.
348 529
      $parents[] = array('tid' => 0);
349 530
    }
350 531
    else {
......
355 536
      }
356 537
    }
357 538

  
539
    $vocabularies = $element['#shs_vocabularies'];
540
    $vocabulary_identifier = NULL;
541
    if (count($vocabularies) == 1) {
542
      // Get ID from first (and only) vocabulary.
543
      $vocabulary_identifier = $vocabularies[0]->vid;
544
    }
545
    else {
546
      $vocabulary_identifier = array(
547
        'field_name' => $element['#field_name'],
548
      );
549
    }
550

  
358 551
    // Create settings needed for our js magic.
359 552
    $settings_js = array(
360 553
      'shs' => array(
361 554
        "{$element['#name']}" => array(
362 555
          $js_hash => array(
363
            'vid' => $element['#shs_vocabulary']->vid,
556
            'vid' => $vocabulary_identifier,
364 557
            'settings' => $element['#shs_settings'],
365 558
            'default_value' => $element['#default_value'],
366 559
            'parents' => array_reverse($parents),
560
            'any_label' => empty($element['#required']) ? t('- None -', array(), array('context' => 'shs')) : t('- Select a value -', array(), array('context' => 'shs')),
561
            'any_value' => '_none',
367 562
          ),
368 563
        ),
369 564
      ),
370 565
    );
566
    // Allow other modules to alter these settings.
567
    drupal_alter(array('shs_js_settings', "shs_{$element['#field_name']}_js_settings"), $settings_js, $element['#field_name'], $vocabulary_identifier);
371 568

  
372 569
    // Add settings.
373 570
    drupal_add_js($settings_js, 'setting');
......
378 575
    $js_added[$element['#name']][$js_hash] = TRUE;
379 576
  }
380 577

  
578
  unset($element['#needs_validation']);
381 579
  return $element;
382 580
}
383 581

  
......
386 584
 */
387 585
function shs_field_widget_validate($element, &$form_state, $form) {
388 586
  $field_name = $element['#field_name'];
389
  $field_language = $element['#language'];
587
  $instance = field_widget_instance($element, $form_state);
390 588

  
391
  if (empty($form_state['field'][$field_name][$field_language]['instance']['widget'])) {
589
  if (empty($instance['widget'])) {
392 590
    return;
393 591
  }
394
  $field = $form_state['field'][$field_name][$field_language];
395
  $instance = $field['instance'];
396
  $settings = empty($instance['widget']['settings']['shs']) ? array() : $instance['widget']['settings']['shs'];
397 592

  
593
  // Load default settings.
594
  $settings = empty($instance['widget']['settings']['shs']) ? array() : $instance['widget']['settings']['shs'];
595
  if (!empty($element['#shs_settings'])) {
596
    // Use settings directly applied to widget (possibly overridden in
597
    // hook_field_widget_form_alter() or
598
    // hook_field_widget_WIDGET_TYPE_form_alter()).
599
    $settings = $element['#shs_settings'];
600
  }
398 601
  // Do we want to force the user to select terms from the deepest level?
399 602
  $force_deepest_level = empty($settings['force_deepest']) ? FALSE : $settings['force_deepest'];
400
  $value = empty($element['#value']) ? 0 : $element['#value'];
603
  $field = field_widget_field($element, $form_state);
604

  
605
  $value = empty($element['#value']) ? '_none' : $element['#value'];
606
  if ($value == '_none') {
607
    unset($element['#value']);
608
    form_set_value($element, NULL, $form_state);
609
  }
610
  if ($element['#required'] && $value == '_none') {
611
    $element_name = empty($element['#title']) ? $instance['label'] : $element['#title'];
612
    form_error($element, t('!name field is required.', array('!name' => $element_name)));
613
    return;
614
  }
401 615
  if ($force_deepest_level && $value) {
402
    // Get vocabulary.
403
    $allowed_values = reset($field['field']['settings']['allowed_values']);
404
    if (empty($allowed_values['vocabulary']) || ($vocabulary = taxonomy_vocabulary_machine_name_load($allowed_values['vocabulary'])) === FALSE) {
405
      // No vocabulary selected yet or vocabulary not found.
406
      form_error($element, t('Vocabulary %machine_name is configured as source for field %field_name but could not be found.', array('%machine_name' => $allowed_values['vocabulary'], '%field_name' => $field_name)));
616
    // Get vocabulary names from allowed values.
617
    if ($field['type'] == 'entityreference') {
618
      $vocabulary_names = $field['settings']['handler_settings']['target_bundles'];
407 619
    }
408
    // Does the selected term has any children?
409
    $children = shs_term_get_children($vocabulary->vid, $value);
410
    if (count($children)) {
411
      form_error($element, t('You need to select a term from the deepest level.'));
620
    else {
621
      $allowed_values = reset($field['settings']['allowed_values']);
622
      $vocabulary_names = empty($allowed_values['vocabulary']) ? FALSE : $allowed_values['vocabulary'];
623
    }
624
    if (empty($vocabulary_names)) {
625
      // No vocabulary selected yet.
626
      form_error($element, t('No vocabulary is configured as source for field %field_name.', array('%field_name' => $instance['label'], '%field_machine_name' => $field_name)));
627
    }
628
    if (!is_array($vocabulary_names)) {
629
      $vocabulary_names = array($vocabulary_names);
630
    }
631
    foreach ($vocabulary_names as $vocabulary_name) {
632
      if (($vocabulary = taxonomy_vocabulary_machine_name_load($vocabulary_name)) === FALSE) {
633
        // Vocabulary not found. Stop here.
634
        form_error($element, t('Vocabulary %machine_name is configured as source for field %field_name but could not be found.', array('%machine_name' => $vocabulary_name, '%field_name' => $instance['label'], '%field_machine_name' => $field_name)));
635
        return;
636
      }
637
      // Does the selected term has any children?
638
      $children = shs_term_get_children($vocabulary->vid, $value);
639
      if (count($children)) {
640
        form_error($element, t('You need to select a term from the deepest level in field %field_name.', array('%field_name' => $instance['label'], '%field_machine_name' => $field_name)));
641
        return;
642
      }
412 643
    }
413 644
  }
414 645
}
......
420 651
  return array(
421 652
    'shs_default' => array(
422 653
      'label' => t('Simple hierarchy'),
423
      'field types' => array('taxonomy_term_reference'),
654
      'field types' => array('taxonomy_term_reference', 'entityreference'),
424 655
      'settings' => array(
425 656
        'linked' => FALSE,
426 657
      ),
......
468 699
 * Implements hook_field_formatter_prepare_view().
469 700
 */
470 701
function shs_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
702
  $field_column = key($field['columns']);
471 703
  foreach ($entities as $entity_id => $entity) {
704
    if (empty($instances[$entity_id]['widget']['type']) || $instances[$entity_id]['widget']['type'] != 'taxonomy_shs') {
705
      return;
706
    }
472 707
    foreach ($items[$entity_id] as $delta => $item) {
473 708
      $items[$entity_id][$delta]['parents'] = array();
474 709
      // Load list of parent terms.
475
      $parents = taxonomy_get_parents_all($item['tid']);
710
      $parents = taxonomy_get_parents_all($item[$field_column]);
476 711
      // Remove current term from list.
477 712
      array_shift($parents);
713
      if (module_exists('i18n_taxonomy')) {
714
        // Localize terms.
715
        $parents = i18n_taxonomy_localize_terms($parents);
716
      }
478 717
      foreach (array_reverse($parents) as $parent) {
479 718
        $items[$entity_id][$delta]['parents'][$parent->tid] = $parent;
480 719
      }
481 720
      // Load term.
482
      $items[$entity_id][$delta]['term'] = taxonomy_term_load($item['tid']);
721
      $term_current = taxonomy_term_load($item[$field_column]);
722
      if (module_exists('i18n_taxonomy')) {
723
        // Localize current term.
724
        $term_current = i18n_taxonomy_localize_terms($term_current);
725
      }
726
      $items[$entity_id][$delta]['term'] = $term_current;
483 727
    }
484 728
  }
485 729
}
......
491 735
  $elements = array();
492 736
  $settings = $display['settings'];
493 737

  
738
  if (empty($items) || $instance['widget']['type'] != 'taxonomy_shs') {
739
    return $elements;
740
  }
741

  
494 742
  switch ($display['type']) {
495 743
    case 'shs_default':
496 744
      foreach ($items as $delta => $item) {
497
        if (empty($item['tid'])) {
745
        if (empty($item['term'])) {
498 746
          continue;
499 747
        }
500 748
        $list_items = array();
......
533 781
 * The structure is stored in the database cache as well as in drupal_static().
534 782
 * Cache has the following structure:
535 783
 * <code>
536
 *   [$parent] => array(
537
 *     [0] => array(tid1, tid2, tid3), // !$node_count.
538
 *     [1] => array('tid1 (x)', 'tid2 (x)', 'tid3 (x)'), // $node_count.
539
 *   ),
784
 *   [$parent] => array(),
540 785
 * </code>
541 786
 *
542
 * @param <int> $vid
543
 *   ID of vocabulary the term is associated to.
787
 * @param <mixed> $identifier
788
 *   Either a vocabulary ID or an array with the following keys:
789
 *   - field_name: Name of field which sends the request.
544 790
 * @param <int> $parent
545 791
 *   ID of parent term.
546 792
 * @param <array> $settings
547
 *   Additional settings (for example "display node count").
793
 *   Additional settings (for example "language", etc.,).
548 794
 * @param <boolean> $reset
549 795
 *   If TRUE, rebuild the cache for the given $vid and $parent.
550 796
 *
551 797
 * @return <array>
552 798
 *   List of child terms keyed by term id.
553 799
 */
554
function shs_term_get_children($vid, $parent = 0, $settings = array(), $reset = FALSE) {
800
function shs_term_get_children($identifier, $parent = 0, $settings = array(), $reset = FALSE) {
801
  global $language;
802
  $langcode = $language->language;
803
  if (empty($settings['language']->language)) {
804
    $settings['language'] = $language;
805
  }
806
  else {
807
    $langcode = $settings['language']->language;
808
  }
809

  
810
  $vocabularies = array();
811
  $vocabulary_cache_key = NULL;
812
  if (is_numeric($identifier)) {
813
    $vocabulary_cache_key = $identifier;
814
    if (($vocabulary = taxonomy_vocabulary_load($identifier)) === FALSE) {
815
      watchdog('Simple hierarchical select', 'Unknown vocabulary with ID !vid used to get terms.', array('!vid' => $identifier));
816
      return array();
817
    }
818
    $vocabularies[$vocabulary->machine_name] = $identifier;
819
  }
820
  elseif (is_array($identifier) && !empty($identifier['field_name'])) {
821
    $vocabulary_cache_key = $identifier['field_name'];
822
  }
823

  
555 824
  $terms = &drupal_static(__FUNCTION__, array());
556
  $node_count = !empty($settings['node_count']) && variable_get('taxonomy_maintain_index_table', TRUE);
557 825

  
558
  if ($reset || ($vid && empty($terms[$vid][$parent][$node_count]))) {
826
  if ($reset || ($vocabulary_cache_key && empty($terms[$vocabulary_cache_key][$langcode][$parent]))) {
559 827
    // Initialize list.
560
    $terms[$vid][$parent] = array(
561
      0 => array(),
562
      1 => array(),
563
    );
564
    $cache_key = "shs:{$vid}";
828
    $terms[$vocabulary_cache_key][$langcode][$parent] = array();
829
    $cache_key = "shs:{$vocabulary_cache_key}";
565 830
    // Get cached values.
566 831
    $cache = cache_get($cache_key);
567
    if ($reset || !$cache || ($cache->expire && time() > $cache->expire) || empty($cache->data[$parent][$node_count])) {
832
    if ($reset || !$cache || ($cache->expire && time() > $cache->expire) || empty($cache->data[$langcode][$parent])) {
568 833
      // Cache is empty or data has become outdated or the parent is not cached.
569 834
      if ($cache) {
570 835
        // Cache exists and is not yet expired but $parent is missing.
571
        $terms[$vid] = $cache->data;
836
        $terms[$vocabulary_cache_key] = $cache->data;
572 837
      }
573 838
      if ($reset) {
574
        $terms[$vid][$parent] = array(
575
          0 => array(),
576
          1 => array(),
577
        );
839
        $terms[$vocabulary_cache_key][$langcode][$parent] = array();
578 840
      }
579
      // Get term children (only first level).
580
      $tree = taxonomy_get_tree($vid, $parent, 1);
581
      foreach ($tree as $term) {
582
        $terms[$vid][$parent][0][$term->tid] = $term->name;
583
        if ($node_count) {
584
          // Count nodes associated to this term (and its children).
585
          $num_nodes = _shs_term_get_node_count($term, TRUE);
586
          // Update term label.
587
          $terms[$vid][$parent][1][$term->tid] = t('!term_name (!node_count)', array('!term_name' => $term->name, '!node_count' => $num_nodes));
841

  
842
      if (!is_numeric($vocabulary_cache_key) && is_array($identifier)) {
843
        // Get list of vocabularies from field configuration.
844
        $field = field_info_field($identifier['field_name']);
845
        if (!empty($field['settings']['handler_settings']['target_bundles'])) {
846
          foreach ($field['settings']['handler_settings']['target_bundles'] as $vocabulary_name) {
847
            if (($vocabulary = taxonomy_vocabulary_machine_name_load($vocabulary_name)) !== FALSE) {
848
              $vocabularies[$vocabulary_name] = $vocabulary->vid;
849
            }
850
          }
851
        }
852
      }
853

  
854
      foreach ($vocabularies as $name => $vid) {
855
        // Get term children (only first level).
856
        // Only load entities if i18n_taxonomy or entity_translation is
857
        // installed.
858
        $load_entities = module_exists('i18n_taxonomy') || module_exists('entity_translation');
859
        $tree = taxonomy_get_tree($vid, $parent, 1, $load_entities);
860
        foreach ($tree as $term) {
861
          $term_name = $term->name;
862
          if (module_exists('i18n_taxonomy')) {
863
            $term_name = i18n_taxonomy_term_name($term, $langcode);
864
          }
865
          else if (module_exists('entity_translation')) {
866
            $term_name = entity_label('taxonomy_term', $term);
867
          }
868
          $terms[$vocabulary_cache_key][$langcode][$parent][$term->tid] = $term_name;
588 869
        }
589 870
      }
590 871
      // Set cached data.
591
      cache_set($cache_key, $terms[$vid], 'cache', CACHE_PERMANENT);
872
      cache_set($cache_key, $terms[$vocabulary_cache_key], 'cache', CACHE_PERMANENT);
592 873
    }
593 874
    else {
594 875
      // Use cached data.
595
      $terms[$vid] = $cache->data;
876
      $terms[$vocabulary_cache_key] = $cache->data;
596 877
    }
597 878
  }
598 879
  // Allow other module to modify the list of terms.
599 880
  $alter_options = array(
600
    'vid' => $vid,
881
    'vid' => $vocabulary_cache_key,
601 882
    'parent' => $parent,
602 883
    'settings' => $settings,
603 884
  );
604 885
  drupal_alter('shs_term_get_children', $terms, $alter_options);
605 886

  
606
  return empty($terms[$vid][$parent][$node_count]) ? array() : $terms[$vid][$parent][$node_count];
887
  return empty($terms[$vocabulary_cache_key][$langcode][$parent]) ? array() : $terms[$vocabulary_cache_key][$langcode][$parent];
607 888
}
608 889

  
609 890
/**
610 891
 * JSON callback to get the list of children of a term.
611 892
 *
612
 * @param <int> $vid
893
 * @param int $vid
613 894
 *   ID of vocabulary the term is associated to.
614
 * @param <int> $parent
615
 *   ID of parent term.
616
 * @param <array> $settings
895
 * @param array $parent
896
 *   List of parent terms.
897
 * @param array $settings
617 898
 *   Additional settings (for example "display node count").
899
 * @param string $field
900
 *   Name of field requesting the term list (DOM element name).
618 901
 *
619
 * @return <array>
902
 * @return array
620 903
 *   Associative list of child terms.
621 904
 *
622 905
 * @see shs_term_get_children()
623 906
 */
624
function shs_json_term_get_children($vid, $parent = array(), $settings = array()) {
907
function shs_json_term_get_children($vid, $parent = array(), $settings = array(), $field = NULL) {
625 908
  $scope = $result = array();
626 909
  foreach ($parent as $tid) {
627 910
    $scope[] = shs_term_get_children($vid, $tid, $settings);
911
    if (shs_add_term_access($vid, $tid, $field)) {
912
      $result[] = array(
913
        'vid' => $vid,
914
      );
915
    }
628 916
  }
629 917

  
630 918
  // Rewrite result set to preserve original sort of terms through JSON request.
......
633 921
      $result[] = array(
634 922
        'tid' => $tid,
635 923
        'label' => $label,
924
        'has_children' => shs_term_has_children($tid, $vid),
636 925
      );
637 926
    }
638 927
  }
639 928

  
640 929
  return $result;
641 930
}
931

  
932
/**
933
 * Check if a term has any children.
934
 *
935
 * Copied from taxonomy_get_children() but just checks existence instead of
936
 * loading terms.
937
 */
938
function shs_term_has_children($tid, $vid) {
939
  $query = db_select('taxonomy_term_data', 't');
940
  $query->addExpression(1);
941
  $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
942
  $query->condition('h.parent', $tid);
943
  if ($vid) {
944
    $query->condition('t.vid', $vid);
945
  }
946
  $query->range(0, 1);
947

  
948
  return (bool) $query->execute()->fetchField();
949
}
950

  
951
/**
952
 * Return access to create new terms.
953
 *
954
 * @param int $vid
955
 *   ID of vocabulary to create the term in.
956
 * @param int $parent
957
 *   ID of parent term (0 for top level).
958
 * @param string $field
959
 *   Name of field requesting the term list (DOM element name).
960
 * @param object $account
961
 *   The user to check access for.
962
 *
963
 * @return bool
964
 *   TRUE or FALSE based on if user can create a term.
965
 */
966
function shs_add_term_access($vid, $parent = NULL, $field = NULL, $account = NULL) {
967
  global $user;
968
  if (!$account) {
969
    $account = $user;
970
  }
971
  $access = module_invoke_all('shs_add_term_access', $vid, $parent, $field, $account);
972
  return !in_array(FALSE, $access, TRUE) && (user_access('edit terms in ' . $vid, $account) || in_array(TRUE, $access));
973
}
974

  
642 975
/**
643 976
 * Adds a term with ajax.
644 977
 *
645
 * @param <int> $vid
978
 * @param int $vid
646 979
 *   ID of vocabulary to create the term in.
647
 * @param <int> $parent
980
 * @param int $parent
648 981
 *   ID of parent term (0 for top level).
649
 * @param <string> $term_name
982
 * @param string $term_name
650 983
 *   Name of new term.
984
 * @param string $field
985
 *   Name of field requesting the term list (DOM element name).
651 986
 *
652
 * @return <mixed>
987
 * @return mixed
653 988
 *   Array with tid and name or FALSE on error.
654 989
 */
655
function shs_json_term_add($vid, $parent, $term_name) {
656
  if (!user_access('edit terms in ' . $vid)) {
990
function shs_json_term_add($vid, $parent, $term_name, $field = NULL) {
991
  global $language_content;
992
  if (!shs_add_term_access($vid, $parent, $field)) {
657 993
    // Sorry, but this user may not add a term to this vocabulary.
658 994
    return FALSE;
659 995
  }
660 996

  
661 997
  $term = (object) array(
662
    'vid' => $vid,
663
    'parent' => $parent,
664
    'name' => check_plain(filter_xss($term_name)),
998
            'vid' => $vid,
999
            'parent' => $parent,
1000
            'name' => str_replace('&amp;', '&', filter_xss($term_name)),
1001
            'language' => $language_content->language,
665 1002
  );
666 1003
  // Save term.
667 1004
  $status = taxonomy_term_save($term);
......
674 1011
 * Implements hook_hook_taxonomy_term_insert().
675 1012
 */
676 1013
function shs_taxonomy_term_insert($term) {
677
  // Update vocabulary cache for the terms parents.
678
  foreach ($term->parent as $parent) {
679
    shs_term_get_children($term->vid, $parent, array('node_count' => TRUE), TRUE);
1014
  if (empty($term->parent)) {
1015
    return;
680 1016
  }
1017
  // Clear shs cache for current vocabulary.
1018
  cache_clear_all("shs:{$term->vid}", 'cache');
681 1019
}
682 1020

  
683 1021
/**
684 1022
 * Implements hook_hook_taxonomy_term_update().
685 1023
 */
686 1024
function shs_taxonomy_term_update($term) {
687
  // Update vocabulary cache for the terms parents.
688
  foreach ($term->parent as $parent) {
689
    shs_term_get_children($term->vid, $parent, array('node_count' => TRUE), TRUE);
1025
  if (empty($term->parent)) {
1026
    return;
690 1027
  }
1028
  // Clear shs cache for current vocabulary.
1029
  cache_clear_all("shs:{$term->vid}", 'cache');
691 1030
}
692 1031

  
693 1032
/**
......
701 1040
 * Implements hook_hook_taxonomy_term_delete().
702 1041
 */
703 1042
function shs_form_taxonomy_overview_terms_submit(&$form, &$form_state) {
704
  // Update vocabulary cache for the terms parents.
705
  shs_term_get_children($form_state['complete form']['#vocabulary']->vid, 0, array('node_count' => TRUE), TRUE);
1043
  if (empty($form_state['complete form']['#vocabulary']->vid)) {
1044
    return;
1045
  }
1046
  // Clear shs cache for current vocabulary.
1047
  cache_clear_all("shs:{$form_state['complete form']['#vocabulary']->vid}", 'cache');
706 1048
}
707 1049

  
708 1050
/**
......
716 1058
}
717 1059

  
718 1060
/**
719
 * Implements hook_hook_taxonomy_term_delete().
1061
 * Submit callback for term form.
720 1062
 */
721 1063
function shs_form_taxonomy_form_term_submit(&$form, &$form_state) {
722
  // Update vocabulary cache for the terms parents.
723
  $parents = db_select('taxonomy_term_hierarchy', 'tth')
724
          ->fields('tth', array('parent'))
725
          ->condition('tid', $form_state['term']->tid)
726
          ->execute()
727
          ->fetchAll();
728
  if ($parents) {
729
    // Update vocabulary cache for the terms parents.
730
    foreach ($parents as $parent) {
731
      shs_term_get_children($form_state['term']->vid, $parent->parent, array('node_count' => TRUE), TRUE);
732
    }
733
  }
1064
  // Clear shs cache for current vocabulary.
1065
  cache_clear_all("shs:{$form_state['term']->vid}", 'cache');
734 1066
}
735 1067

  
736 1068
/**
......
767 1099
  return $instances;
768 1100
}
769 1101

  
770
/**
771
 * Helper function to count number of nodes associated to a term.
772
 *
773
 * @param <object> $term
774
 *   The term object.
775
 * @param <boolean> $count_children
776
 *   If set to TRUE, nodes in child terms are counted also.
777
 *
778
 * @return <int>
779
 *   Number of nodes within the term.
780
 */
781
function _shs_term_get_node_count($term, $count_children = FALSE) {
782
  $num_nodes = &drupal_static(__FUNCTION__, array());
783

  
784
  // Maybe this needs some more caching and value-updates on node_save()/
785
  // _update()/delete().
786
  if (empty($num_nodes["{$term->tid}:{$count_children}"])) {
787
    // Count nodes associated to this term.
788
    $num_nodes["{$term->tid}:{$count_children}"] = db_select('taxonomy_index', 'ti')
789
            ->fields('ti')
790
            ->condition('tid', $term->tid)
791
            ->execute()
792
            ->rowCount();
793

  
794
    if ($count_children) {
795
      $tids = array();
796
      $tree = taxonomy_get_tree($term->vid, $term->tid);
797
      foreach ($tree as $child_term) {
798
        $tids[] = $child_term->tid;
799
      }
800
      if (count($tids)) {
801
        $num_nodes["{$term->tid}:{$count_children}"] += db_select('taxonomy_index', 'ti')
802
                ->fields('ti')
803
                ->condition('tid', $tids, 'IN')
804
                ->execute()
805
                ->rowCount();
806
      }
807
    }
808
  }
809

  
810
  return isset($num_nodes["{$term->tid}:{$count_children}"]) ? $num_nodes["{$term->tid}:{$count_children}"] : 0;
811
}
812

  
813 1102
/**
814 1103
 * Helper function to create a pseudo hash needed for javascript settings.
815 1104
 *
......
830 1119
  }
831 1120
  return $hash;
832 1121
}
1122

  
1123
/**
1124
 * Helper function to validate the vocabulary identifier coming from JSON.
1125
 *
1126
 * @param mixed $identifier
1127
 *   Either a vocabulary ID or an array with the following keys:
1128
 *   - field_name: Name of field which sends the request.
1129
 *
1130
 * @return boolean
1131
 *   TRUE if validation passes, otherwise FALSE.
1132
 */
1133
function shs_json_validation_vocabulary_identifier($identifier) {
1134
  return TRUE;
1135
}
1136

  
1137
/**
1138
 * Helper function to get the vocabularies used as filter in entityreference
1139
 * views.
1140
 *
1141
 * @param string $view_name
1142
 *   Name of view.
1143
 * @param string $display_id
1144
 *   Name of display.
1145
 *
1146
 * return string[]
1147
 *   List of vocabulary identifiers.
1148
 */
1149
function _shs_entityreference_views_get_vocabularies($view_name, $display_id) {
1150
  $view = views_get_view($view_name);
1151
  if (empty($view)) {
1152
    // Failed to load view.
1153
    return array();
1154
  }
1155
  $filters = $view->get_items('filter', $display_id);
1156
  $vocabularies = array();
1157
  foreach ($filters as $key => $filter) {
1158
    if (('taxonomy_vocabulary' !== $filter['table']) || ('machine_name' !== $key)) {
1159
      continue;
1160
    }
1161
    $vocabularies = array_keys($filter['value']) + $vocabularies;
1162
  }
1163

  
1164
  return $vocabularies;
1165
}

Formats disponibles : Unified diff