Projet

Général

Profil

Paste
Télécharger (18,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ds / modules / ds_ui / includes / ds.fields.inc @ 7fe061e8

1
<?php
2

    
3
/**
4
 * @file
5
 * Administrative functions for managing custom fields for every entity.
6
 */
7

    
8
/**
9
 * Shows the list of custom fields.
10
 */
11
function ds_custom_fields_list() {
12
  $output = '';
13

    
14
  ctools_include('export');
15
  $custom_fields = ctools_export_crud_load_all('ds_fields');
16
  if (!empty($custom_fields)) {
17

    
18
    $rows = array();
19
    foreach ($custom_fields as $field_key => $field_value) {
20
      $row = array();
21
      $row[] = check_plain($field_value->label);
22
      $row[] = ds_field_human_name($field_value->field_type);
23
      $row[] = $field_key;
24
      $row[] = ucwords(str_replace('_', ' ', implode(', ', $field_value->entities)));
25
      $operations = l(t('Edit'), 'admin/structure/ds/fields/manage/' . $field_key, array('alias' => TRUE));
26

    
27
      if ($field_value->export_type == 3) {
28
        $operations .= ' - ' . l(t('Revert'), 'admin/structure/ds/fields/revert/' . $field_key, array('alias' => TRUE));
29
      }
30
      elseif ($field_value->export_type == 1) {
31
        $operations .= ' - ' . l(t('Delete'), 'admin/structure/ds/fields/delete/' . $field_key, array('alias' => TRUE));
32
      }
33
      $row[] = $operations;
34
      $rows[] = $row;
35
    }
36

    
37
    $table = array(
38
      'header' => array(
39
        'Label',
40
        'Type',
41
        'Machine name',
42
        'Entities',
43
        'Operations',
44
      ),
45
      'rows' => $rows,
46
    );
47

    
48
    $output = theme('table', $table);
49
  }
50
  else {
51
    $output = t('No custom fields have been defined.');
52
  }
53

    
54
  return $output;
55
}
56

    
57
/**
58
 * Return the human name of a field.
59
 *
60
 * @return $human_name
61
 *   The human name of a field.
62
 */
63
function ds_field_human_name($type) {
64

    
65
  switch ($type) {
66
    case DS_FIELD_TYPE_CODE:
67
      return t('Code field');
68
    case DS_FIELD_TYPE_BLOCK:
69
      return t('Block field');
70
    case DS_FIELD_TYPE_CTOOLS:
71
      return t('Dynamic field');
72
    case DS_FIELD_TYPE_PREPROCESS:
73
      return t('Preprocess field');
74
  }
75

    
76
  // Fallback
77
  return t('Unknown');
78
}
79

    
80
/**
81
 * Manage a field. This will redirect to the exact form.
82
 */
83
function ds_custom_manage($field_key = '') {
84
  $redirect = '';
85
  ctools_include('export');
86
  $custom_fields = ctools_export_crud_load_all('ds_fields');
87
  if (isset($custom_fields[$field_key])) {
88
    $field = $custom_fields[$field_key];
89
    switch ($field->field_type) {
90
      case DS_FIELD_TYPE_CODE:
91
        $redirect = 'admin/structure/ds/fields/manage_custom/' . $field_key;
92
        break;
93

    
94
      case DS_FIELD_TYPE_BLOCK:
95
        $redirect = 'admin/structure/ds/fields/manage_block/' . $field_key;
96
        break;
97

    
98
      case DS_FIELD_TYPE_CTOOLS:
99
        $redirect = 'admin/structure/ds/fields/manage_ctools/' . $field_key;
100
        break;
101

    
102
      case DS_FIELD_TYPE_PREPROCESS:
103
        $redirect = 'admin/structure/ds/fields/manage_preprocess/' . $field_key;
104
        break;
105

    
106
      default:
107
        drupal_set_message(t('Field not found'));
108
        $redirect = 'admin/structure/ds/fields';
109
        break;
110
    }
111
  }
112

    
113
  drupal_goto($redirect);
114
}
115

    
116
/**
117
 * Shared form for all fields.
118
 */
119
function ds_shared_form(&$form, $field) {
120
  ctools_include('export');
121
  $custom_fields = ctools_export_crud_load_all('ds_fields');
122
  if (isset($custom_fields[$field])) {
123
    $field = $custom_fields[$field];
124
    if (!isset($field->ui_limit)) {
125
      $field->ui_limit = '';
126
    }
127
  }
128
  else {
129
    $field = new stdClass;
130
    $field->label = '';
131
    $field->field = '';
132
    $field->ui_limit = '';
133
    $field->entities = array();
134
    $field->properties = array();
135
  }
136

    
137
  $form['name'] = array(
138
    '#title' => t('Label'),
139
    '#type' => 'textfield',
140
    '#default_value' => $field->label,
141
    '#description' => t('The human-readable label of the field.'),
142
    '#maxlength' => 128,
143
    '#required' => TRUE,
144
    '#size' => 30,
145
  );
146

    
147
  $form['field'] = array(
148
    '#type' => 'machine_name',
149
    '#default_value' => $field->field,
150
    '#maxlength' => 32,
151
    '#description' => t('The machine-readable name of this field. This name must contain only lowercase letters and underscores. This name must be unique.'),
152
    '#disabled' => !empty($field->field),
153
    '#machine_name' => array(
154
      'exists' => 'ds_field_unique',
155
    ),
156
  );
157

    
158
  $entity_options = array();
159
  $entities = entity_get_info();
160
  foreach ($entities as $entity_type => $entity_info) {
161
    if ((isset($entity_info['fieldable']) && $entity_info['fieldable']) || $entity_type == 'ds_views') {
162
      $entity_options[$entity_type] = drupal_ucfirst(str_replace('_', ' ', $entity_type));
163
    }
164
  }
165
  $form['entities'] = array(
166
    '#title' => t('Entities'),
167
    '#description' => t('Select the entities for which this field will be made available.'),
168
    '#type' => 'checkboxes',
169
    '#required' => TRUE,
170
    '#options' => $entity_options,
171
    '#default_value' => $field->entities,
172
  );
173

    
174
  $form['ui_limit'] = array(
175
    '#title' => t('Limit field'),
176
    '#description' => t('Limit this field on field UI per bundles and/or view modes. The values are in the form of $bundle|$view_mode, where $view_mode may be either a view mode set to use custom settings, or \'default\'. You may use * to select all, e.g article|*, *|full or *|*. Enter one value per line.'),
177
    '#type' => 'textarea',
178
    '#default_value' => $field->ui_limit,
179
    '#element_validate' => array('ds_ui_limit_validate'),
180
  );
181

    
182
  $form['submit'] = array(
183
    '#type' => 'submit',
184
    '#value' => t('Save'),
185
    '#weight' => 100,
186
  );
187

    
188
  // Validate & submit are also the same.
189
  $form['#validate'][] = 'ds_shared_form_validate';
190
  $form['#submit'][] = 'ds_shared_form_submit';
191

    
192
  return $field;
193
}
194

    
195
/**
196
 * Element validation function for ui limit field.
197
 */
198
function ds_ui_limit_validate($element, &$form_state, $form) {
199
  // Get all enabled entity types.
200
  $entity_types = array_filter($form_state['values']['entities']);
201

    
202
  if (!empty($element['#value'])) {
203
    $ui_limit = $element['#value'];
204

    
205
    $lines = explode("\n", str_replace("\r", "\n", $ui_limit));
206
    // Ensure that all strings are trimmed and filter out empty lines.
207
    $lines = array_filter(array_map('trim', $lines));
208

    
209
    $error = FALSE;
210
    foreach ($lines as $line) {
211
      // Each line should hold a pipe character to seperate bundle and view_mode.
212
      if (strpos($line, '|') === FALSE) {
213
        $error = TRUE;
214
        continue;
215
      }
216

    
217
      list($bundle, $view_mode) = explode('|', $line);
218

    
219
      if (empty($bundle) || empty($view_mode) || !_ds_check_existing_ui_limit($entity_types, $bundle, $view_mode)) {
220
        $error = TRUE;
221
      }
222
    }
223
    if ($error) {
224
      form_error($element, t('The values are in the form of $bundle|$view_mode, where $view_mode may be either a view mode set to use custom settings, or \'default\'.'));
225
    }
226

    
227
    // Set trimmed and validated entry back as value.
228
    form_set_value($element, implode("\n", $lines), $form_state);
229
  }
230
}
231

    
232
/**
233
 * Helper function to check if bundle + view_mode combination exists.
234
 */
235
function _ds_check_existing_ui_limit($entity_types, $bundle, $view_mode) {
236
  $exists = FALSE;
237
  foreach ($entity_types as $entity_type) {
238
    $info = entity_get_info($entity_type);
239

    
240
    // Combine allowed bundles and entity specific ones.
241
    $bundle_allowed = array('*');
242
    $bundles = array_merge($bundle_allowed, array_keys($info['bundles']));
243

    
244
    // Combine allowed view_modes and entity specific ones.
245
    $view_mode_allowed = array('*', 'default');
246
    $view_modes = array_merge($view_mode_allowed, array_keys($info['view modes']));
247

    
248
    if (in_array($bundle, $bundles) &&
249
      in_array($view_mode, $view_modes)) {
250

    
251
      $exists = TRUE;
252
      break;
253
    }
254
  }
255
  if (!$exists) {
256
    drupal_set_message(t('Incorrect field limit combination: @bundle|@view_mode', array('@bundle' => $bundle, '@view_mode' => $view_mode)), 'error');
257
  }
258

    
259
  return $exists;
260
}
261

    
262
/**
263
 * Return whether a field machine name is unique.
264
 */
265
function ds_field_unique($name) {
266
  ctools_include('export');
267
  $custom_fields = ctools_export_crud_load_all('ds_fields');
268
  $value = strtr($name, array('-' => '_'));
269
  return isset($custom_fields[$value]) ? TRUE : FALSE;
270
}
271

    
272
/**
273
 * Shared field form validation.
274
 */
275
function ds_shared_form_validate($form, &$form_state) {
276
  $field = new stdClass;
277
  $field->properties = array();
278
  $field->field = $form_state['values']['field'];
279
  $field->label = $form_state['values']['name'];
280
  $field->ui_limit = $form_state['values']['ui_limit'];
281

    
282
  $entities = $form_state['values']['entities'];
283
  foreach ($entities as $key => $value) {
284
    if ($key !== $value) {
285
      unset($entities[$key]);
286
    }
287
  }
288
  $field->entities = $entities;
289
  $form_state['field'] = $field;
290
}
291

    
292
/**
293
 * Save any field.
294
 */
295
function ds_shared_form_submit($form, &$form_state) {
296
  $field = $form_state['field'];
297

    
298
  // Delete previous field configuration.
299
  db_delete('ds_fields')
300
    ->condition('field', $field->field)
301
    ->execute();
302

    
303
  // Save field and clear ds_fields.
304
  drupal_write_record('ds_fields', $field);
305
  cache_clear_all('ds_fields:', 'cache', TRUE);
306

    
307
  // Redirect.
308
  $form_state['redirect'] = 'admin/structure/ds/fields';
309
  drupal_set_message(t('The field %field has been saved', array('%field' => $field->label)));
310
}
311

    
312
/**
313
 * Manage a custom field.
314
 */
315
function ds_edit_custom_field_form($form, &$form_state, $custom_field = '') {
316
  drupal_set_title(empty($custom_field) ? t('Add a code field') : t('Edit code field'));
317

    
318
  $custom_field = ds_shared_form($form, $custom_field);
319

    
320
  $form['code'] = array(
321
    '#type' => 'text_format',
322
    '#title' => t('Field code'),
323
    '#default_value' => isset($custom_field->properties['code']['value']) ? $custom_field->properties['code']['value'] : '',
324
    '#format' => isset($custom_field->properties['code']['format']) ? $custom_field->properties['code']['format'] : 'ds_code',
325
    '#base_type' => 'textarea',
326
    '#required' => TRUE,
327
  );
328

    
329
  $form['use_token'] = array(
330
    '#type' => 'checkbox',
331
    '#title' => t('Token'),
332
    '#description' => t('Toggle this checkbox if you are using tokens in this field.'),
333
    '#default_value' => isset($custom_field->properties['use_token']) ? $custom_field->properties['use_token'] : '',
334
  );
335

    
336
  // Token support.
337
  if (module_exists('token')) {
338

    
339
    $form['tokens'] = array(
340
      '#title' => t('Tokens'),
341
      '#type' => 'container',
342
      '#states' => array(
343
        'invisible' => array(
344
          'input[name="use_token"]' => array('checked' => FALSE),
345
        ),
346
      ),
347
    );
348
    $form['tokens']['help'] = array(
349
      '#theme' => 'token_tree',
350
      '#token_types' => 'all',
351
      '#global_types' => FALSE,
352
      '#dialog' => TRUE,
353
    );
354
  }
355
  else {
356
    $form['use_token']['#description'] = t('Toggle this checkbox if you are using tokens in this field. If the token module is installed, you get a nice list of all tokens available in your site.');
357
  }
358

    
359
  $form['#validate'][] = 'ds_custom_field_form_validate';
360

    
361
  return $form;
362
}
363

    
364
/**
365
 * Custom field form validation.
366
 */
367
function ds_custom_field_form_validate($form, &$form_state) {
368
  $form_state['field']->field_type = DS_FIELD_TYPE_CODE;
369
  $form_state['field']->properties['code'] = $form_state['values']['code'];
370
  $form_state['field']->properties['use_token'] = $form_state['values']['use_token'];
371
}
372

    
373
/**
374
 * Manage a CTools field.
375
 */
376
function ds_edit_ctools_field_form($form, &$form_state, $ctools_field = '') {
377
  drupal_set_title(empty($ctools_field) ? t('Add a dynamic field') : t('Edit dynamic field'));
378

    
379
  $custom_field = ds_shared_form($form, $ctools_field);
380
  $form['info'] = array(
381
    '#markup' => t('The content of this field is configurable on the "Manage display" screens.'),
382
    '#weight' => -10,
383
  );
384
  $form['#validate'][] = 'ds_ctools_field_form_validate';
385
  return $form;
386
}
387

    
388
/**
389
 * CTools field form validation.
390
 */
391
function ds_ctools_field_form_validate($form, &$form_state) {
392
  $form_state['field']->field_type = DS_FIELD_TYPE_CTOOLS;
393
  $form_state['field']->properties['default'] = array();
394
  $form_state['field']->properties['settings'] = array('show_title' => array('type' => 'checkbox'), 'title_wrapper' => array('type' => 'textfield', 'description' => t('Eg: h1, h2, p')), 'ctools' => array('type' => 'ctools'));
395
}
396

    
397
/**
398
 * Manage a Preprocess field.
399
 */
400
function ds_edit_preprocess_field_form($form, &$form_state, $preprocess_field = '') {
401
  drupal_set_title(empty($preprocess_field) ? t('Add a preprocess field') : t('Edit preprocess field'));
402

    
403
  $custom_field = ds_shared_form($form, $preprocess_field);
404
  $form['info'] = array(
405
    '#markup' => t('The machine name of this field must reflect the key in the variables, e.g. "submitted". So in most cases, it is very likely you will have to manually edit the machine name as well, which can not be changed anymore after saving. Note that this field type works best on Nodes.'),
406
    '#weight' => -10,
407
  );
408
  $form['#validate'][] = 'ds_preprocess_field_form_validate';
409
  return $form;
410
}
411

    
412
/**
413
 * CTools field form validation.
414
 */
415
function ds_preprocess_field_form_validate($form, &$form_state) {
416
  $form_state['field']->field_type = DS_FIELD_TYPE_PREPROCESS;
417
}
418

    
419
/**
420
 * Manage a custom block.
421
 */
422
function ds_edit_block_field_form($form, &$form_state, $custom_block = '') {
423
  drupal_set_title(empty($custom_block) ? t('Add a block field') : t('Edit block field'));
424

    
425
  $custom_block = ds_shared_form($form, $custom_block);
426

    
427
  $blocks = array();
428
  foreach (module_implements('block_info') as $module) {
429
    $module_blocks = module_invoke($module, 'block_info');
430
    if ($module_blocks) {
431
      foreach ($module_blocks as $module_key => $info) {
432
        $blocks[drupal_ucfirst($module)][$module . '|' . $module_key] = $info['info'];
433
      }
434
    }
435
  }
436
  ksort($blocks);
437
  foreach($blocks as &$subarray) {
438
    asort($subarray);
439
  }
440

    
441
  $form['block_identity']['block'] = array(
442
    '#type' => 'select',
443
    '#options' => $blocks,
444
    '#title' => t('Block'),
445
    '#required' => TRUE,
446
    '#default_value' => isset($custom_block->properties['block']) ? $custom_block->properties['block'] : '',
447
  );
448
  $form['block_identity']['block_render'] = array(
449
    '#type' => 'select',
450
    '#options' => array(
451
      DS_BLOCK_TEMPLATE => t('Default'),
452
      DS_BLOCK_TITLE_CONTENT => t('Show block title + content'),
453
      DS_BLOCK_CONTENT => t('Show only block content'),
454
    ),
455
    '#title' => t('Layout'),
456
    '#required' => TRUE,
457
    '#default_value' => isset($custom_block->properties['block_render']) ? $custom_block->properties['block_render'] : '',
458
  );
459

    
460
  $form['#validate'][] = 'ds_block_field_form_validate';
461

    
462
  return $form;
463
}
464

    
465
/**
466
 * Custom field form validation.
467
 */
468
function ds_block_field_form_validate($form, &$form_state) {
469
  $form_state['field']->field_type = DS_FIELD_TYPE_BLOCK;
470
  $form_state['field']->properties = array();
471
  $form_state['field']->properties['block'] = $form_state['values']['block'];
472
  $form_state['field']->properties['block_render'] = $form_state['values']['block_render'];
473
}
474

    
475
/**
476
 * Menu callback: Confirmation custom field delete form.
477
 */
478
function ds_delete_field_confirm($form, &$form_state, $field = '') {
479
  return ds_remove_fields_form($form, $form_state, $field, 'delete');
480
}
481

    
482
/**
483
 * Menu callback: Confirmation custom field delete form.
484
 */
485
function ds_revert_field_confirm($form, &$form_state, $field = '') {
486
  return ds_remove_fields_form($form, $form_state, $field, 'revert');
487
}
488

    
489
/**
490
 * Confirmation delete or revert form.
491
 */
492
function ds_remove_fields_form($form, &$form_state, $field = '', $action = 'delete') {
493
  ctools_include('export');
494
  $custom_fields = ctools_export_crud_load_all('ds_fields');
495
  if (isset($custom_fields[$field])) {
496
    $field = $custom_fields[$field];
497
    $form['#ds_field'] = $field;
498
    return confirm_form($form,
499
      t('Are you sure you want to ' . $action . ' %field?', array('%field' => $field->label)),
500
      'admin/structure/ds/fields',
501
      t('This action cannot be undone.'),
502
      t(drupal_ucfirst($action)),
503
      t('Cancel')
504
    );
505
  }
506
  else {
507
    drupal_set_message(t('Unknown field'));
508
    drupal_goto('admin/structure/ds/fields');
509
  }
510
}
511

    
512
/**
513
 * Submit callback: confirmed delete submit.
514
 */
515
function ds_delete_field_confirm_submit($form, &$form_state) {
516
  ds_remove_field_confirm_submit($form, $form_state, 'deleted');
517
}
518

    
519
/**
520
 * Submit callback: confirmed revert submit.
521
 */
522
function ds_revert_field_confirm_submit($form, &$form_state) {
523
  ds_remove_field_confirm_submit($form, $form_state, 'reverted');
524
}
525

    
526
/**
527
 * Confirmed field delete or revert submit callback.
528
 */
529
function ds_remove_field_confirm_submit($form, &$form_state, $action = 'deleted') {
530

    
531
  $field = $form['#ds_field'];
532

    
533
  // Remove field.
534
  db_delete('ds_fields')
535
    ->condition('field', $field->field)
536
    ->execute();
537

    
538
  // Clear cache.
539
  cache_clear_all('ds_fields:', 'cache', TRUE);
540

    
541
  // Redirect.
542
  $form_state['redirect'] = 'admin/structure/ds/fields';
543
  drupal_set_message(t('The field %field has been ' . $action, array('%field' => $field->label)));
544
}
545

    
546
/**
547
 * Handles ctools modal Add field
548
 *
549
 * @param $js
550
 *  Whether js is used or not.
551
 * @param $field_type
552
 *   The name of the field type.
553
 */
554
function ds_ajax_add_field($js, $field_type) {
555

    
556
  if (!$js) {
557
    // We don't support degrading this from js because we're not
558
    // using the server to remember the state of the table.
559
    drupal_goto("admin/structure/ds/fields/" . $field_type);
560
    return;
561
  }
562

    
563
  ctools_include('ajax');
564
  ctools_include('modal');
565

    
566
  switch ($field_type) {
567

    
568
    case "manage_ctools":
569
      $title = t('Add a dynamic field');
570
      $form_name = "ds_edit_ctools_field_form";
571
      break;
572

    
573
    case "manage_preprocess":
574
      $title = t('Add a preprocess field');
575
      $form_name = "ds_edit_preprocess_field_form";
576
      break;
577

    
578
    case "manage_block":
579
      $title = t('Add a block field');
580
      $form_name = "ds_edit_block_field_form";
581
      break;
582

    
583
    default:
584
      $title = t('Add a code field');
585
      $form_name = "ds_edit_custom_field_form";
586
      $field_type = 'manage_custom';
587
      break;
588
  }
589

    
590
  $form_state = array();
591
  $form_state['build_info']['args'] = array();
592
  $form_state += array(
593
    'title' => $title,
594
    'ajax' => TRUE,
595
    're_render' => FALSE,
596
  );
597

    
598
  $output = NULL;
599
  form_load_include($form_state, 'inc', 'ds_ui', 'includes/ds.fields');
600

    
601
  $output = ctools_modal_form_wrapper($form_name, $form_state);
602

    
603
  // Field is saved.
604
  if ($form_state['executed']) {
605

    
606
    $output = array();
607

    
608
    // Do not print messages on screen.
609
    if ($messages = theme('status_messages')) {
610
      $output[] = ajax_command_append('#console', $messages);
611
    }
612

    
613
    // Close the modal.
614
    $output[] = ctools_modal_command_dismiss();
615

    
616
    // Call our own javascript function which will trigger a refresh of the table.
617
    $output[] = ajax_command_invoke('#field-display-overview', 'dsRefreshDisplayTable');
618
  }
619

    
620
  drupal_add_http_header('Content-Type', 'application/json');
621
  print ajax_render($output);
622
  exit;
623
}