/[drupal]/contributions/modules/cck/includes/cck.admin.inc
ViewVC logotype

Contents of /contributions/modules/cck/includes/cck.admin.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.24 - (show annotations) (download) (as text)
Thu Jul 16 13:03:41 2009 UTC (4 months, 1 week ago) by yched
Branch: MAIN
Changes since 1.23: +2 -2 lines
File MIME type: text/x-php
#520774 by quicksketch - Default value field shown even if widget specifies NONE/CUSTOM
1 <?php
2 // $Id: cck.admin.inc,v 1.23 2009/07/10 11:31:38 yched Exp $
3
4 /**
5 * @file
6 * Administrative interface for custom field type creation.
7 */
8
9 /**
10 * Menu callback; replacement for node_overview_types().
11 *
12 * TODO Should this be a patch to node module instead,
13 * to allow CCK to adapt the $rows array to add its operation?
14 */
15 function cck_types_overview() {
16 $types = node_type_get_types();
17 $names = node_type_get_names();
18 $header = array(t('Name'), t('Type'), t('Description'), array('data' => t('Operations'), 'colspan' => '4'),);
19 $rows = array();
20 foreach ($names as $key => $name) {
21 $type = $types[$key];
22 if (node_hook($type, 'form')) {
23 $bundle_url_str = str_replace('_', '-', $type->type);
24 $row = array(
25 check_plain($name),
26 check_plain($type->type),
27 );
28 // Make the description smaller
29 $row[] = array('data' => filter_xss_admin($type->description), 'class' => 'description');
30 // Set the edit column.
31 $row[] = array('data' => l(t('edit'), 'admin/build/node-type/'. $bundle_url_str));
32 // Set links for managing fields.
33 // TODO: a hook to allow other cck modules to add more stuff?
34 $row[] = array('data' => l(t('manage fields'), 'admin/build/node-type/'. $bundle_url_str .'/fields'));
35 // Set the delete column.
36 if ($type->custom) {
37 $row[] = array('data' => l(t('delete'), 'admin/build/node-type/'. $bundle_url_str .'/delete'));
38 }
39 else {
40 $row[] = array('data' => '');
41 }
42
43 $rows[] = $row;
44 }
45 }
46
47 if (empty($rows)) {
48 $rows[] = array(array('data' => t('No bundles available.'), 'colspan' => '7', 'class' => 'message'));
49 }
50
51 return theme('table', $header, $rows);
52 }
53
54 /**
55 * Implementation of hook_content_types_overview().
56 *
57 * Display the default upload settings on the Node type overview page.
58 *
59 */
60 function cck_content_types_operations($type) {
61 $bundle_url_str = str_replace('_', '-', $type->type);
62 return array('data' => l(t('manage fields'), 'admin/build/node-type/'. $bundle_url_str .'/fields'));
63 }
64
65 /**
66 * Menu callback; lists all defined fields for quick reference.
67 */
68 function cck_fields_list() {
69 $instances = field_info_instances();
70 $field_types = field_info_field_types();
71 $bundles = field_info_bundles();
72 $header = array(t('Field name'), t('Field type'), t('Used in'));
73 $rows = array();
74 foreach ($instances as $bundle => $info) {
75 foreach ($info as $field_name => $instance) {
76 $field = field_info_field($field_name);
77 $admin_path = _cck_bundle_admin_path($bundle);
78 $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
79 $rows[$field_name]['data'][1] = t($field_types[$field['type']]['label']);
80 $rows[$field_name]['data'][2][] = l($bundles[$bundle]['label'], $admin_path .'/fields');
81 $rows[$field_name]['class'] = $field['locked'] ? 'menu-disabled' : '';
82 }
83 }
84 foreach ($rows as $field_name => $cell) {
85 $rows[$field_name]['data'][2] = implode(', ', $cell['data'][2]);
86 }
87 if (empty($rows)) {
88 $output = t('No fields have been defined for any content type yet.');
89 }
90 else {
91 // Sort rows by field name.
92 ksort($rows);
93 $output = theme('table', $header, $rows);
94 }
95 return $output;
96 }
97
98 /**
99 * Helper function to display a message about inactive fields.
100 */
101 function cck_inactive_message($bundle) {
102 // TODO : adapt to new D7 APIs
103 $inactive_fields = cck_inactive_fields($bundle);
104 if (!empty($inactive_fields)) {
105 $field_types = _field_field_types();
106 $widget_types = _field_widget_types($bundle);
107 drupal_set_message(t('This bundle has inactive fields. Inactive fields are not included in lists of available fields until their modules are enabled.'), 'error');
108 foreach ($inactive_fields as $field_name => $field) {
109 drupal_set_message(t('!field (!field_name) is an inactive !field_type field that uses a !widget_type widget.', array(
110 '!field' => $field['label'],
111 '!field_name' => $field['field_name'],
112 '!field_type' => array_key_exists($field['type'], $field_types) ? $field_types[$field['type']]['label'] : $field['type'],
113 '!widget_type' => array_key_exists($field['widget']['type'], $widget_types) ? $widget_types[$field['widget']['type']]['label'] : $field['widget']['type'],
114 )));
115 }
116 }
117 }
118
119 /**
120 * Menu callback; listing of fields for a content type.
121 *
122 * Allows fields to be reordered and nested in fieldgroups using
123 * JS drag-n-drop. Non-field form elements can also be moved around.
124 */
125 function cck_field_overview_form(&$form_state, $obj_type, $bundle) {
126 $bundle = field_attach_extract_bundle($obj_type, $bundle);
127
128 cck_inactive_message($bundle);
129 $admin_path = _cck_bundle_admin_path($bundle);
130
131 // When displaying the form, make sure the list of fields
132 // is up-to-date.
133 if (empty($form_state['post'])) {
134 field_cache_clear();
135 }
136
137 // Gather bundle information.
138 $instances = field_info_instances($bundle);
139 $field_types = field_info_field_types();
140 $widget_types = field_info_widget_types();
141
142 $extra = cck_extra_field_values($bundle);
143
144 $groups = $group_options = array();
145 if (module_exists('fieldgroup')) {
146 $groups = fieldgroup_groups($bundle);
147 $group_types = fieldgroup_types();
148 $group_options = _fieldgroup_groups_label($bundle);
149 // Add the ability to group under the newly created row.
150 $group_options['_add_new_group'] = '_add_new_group';
151 }
152
153 // Store the default weights as we meet them, to be able to put the
154 //'add new' rows after them.
155 $weights = array();
156
157 $form = array(
158 '#tree' => TRUE,
159 '#bundle' => $bundle,
160 '#fields' => array_keys($instances),
161 '#groups' => array_keys($groups),
162 '#extra' => array_keys($extra),
163 '#field_rows' => array(),
164 '#group_rows' => array(),
165 );
166
167 // Fields.
168 foreach ($instances as $name => $instance) {
169 $field = field_info_field($instance['field_name']);
170 $admin_field_path = $admin_path .'/fields/'. $instance['field_name'];
171 $weight = $instance['weight'];
172 $form[$name] = array(
173 'label' => array('#markup' => check_plain($instance['label'])),
174 'field_name' => array('#markup' => $instance['field_name']),
175 'type' => array(
176 '#markup' => l(t($field_types[$field['type']]['label']), $admin_field_path .'/field-settings', array(
177 'attributes' => array('title' => t('Edit field settings.'))))),
178 'widget_type' => array(
179 '#markup' => l(t($widget_types[$instance['widget']['type']]['label']), $admin_field_path .'/widget-type', array(
180 'attributes' => array('title' => t('Change widget type.'))))),
181 'configure' => array(
182 '#markup' => l(t('Configure'), $admin_field_path, array(
183 'attributes' => array('title' => t('Edit instance settings.'))))),
184 'remove' => array(
185 '#markup' => l(t('Remove'), $admin_field_path .'/remove', array(
186 'attributes' => array('title' => t('Remove instance.'))))),
187 'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
188 'parent' => array('#type' => 'select', '#options' => $group_options, '#default_value' => ''),
189 'prev_parent' => array('#type' => 'hidden', '#value' => ''),
190 'hidden_name' => array('#type' => 'hidden', '#default_value' => $instance['field_name']),
191 '#leaf' => TRUE,
192 '#row_type' => 'field',
193 // TODO D7 : ??
194 'field' => array('#type' => 'value', '#value' => $field),
195 );
196
197 if (!empty($instance['locked'])) {
198 $form[$name]['configure'] = array('#value' => t('Locked'));
199 $form[$name]['remove'] = array();
200 $form[$name]['#disabled_row'] = TRUE;
201 }
202 $form['#field_rows'][] = $name;
203 $weights[] = $weight;
204 }
205
206 // Groups.
207 foreach ($groups as $name => $group) {
208 $weight = $group['weight'];
209 $form[$name] = array(
210 'label' => array('#markup' => check_plain($group['label'])),
211 'group_name' => array('#markup' => $group['group_name']),
212 'group_type' => array('#markup' => t($group_types[$group['group_type']])),
213 'configure' => array('#markup' => l(t('Configure'), $admin_path .'/groups/'. $group['group_name'])),
214 'remove' => array('#markup' => l(t('Remove'), $admin_path .'/groups/'. $group['group_name'] .'/remove')),
215 'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
216 'parent' => array('#type' => 'hidden', '#default_value' => ''),
217 'hidden_name' => array('#type' => 'hidden', '#default_value' => $group['group_name']),
218 '#root' => TRUE,
219 '#row_type' => 'group',
220 'group' => array('#type' => 'value', '#value' => $group),
221 );
222 // Adjust child fields rows.
223 foreach ($group['fields'] as $field_name => $field) {
224 $form[$field_name]['parent']['#default_value'] = $name;
225 $form[$field_name]['prev_parent']['#value'] = $name;
226 }
227 $form['#group_rows'][] = $name;
228 $weights[] = $weight;
229 }
230
231 // Non-field elements.
232 foreach ($extra as $name => $label) {
233 $weight = $extra[$name]['weight'];
234 $form[$name] = array(
235 'label' => array('#markup' => t($extra[$name]['label'])),
236 'description' => array('#markup' => isset($extra[$name]['description']) ? $extra[$name]['description'] : ''),
237 'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
238 'parent' => array('#type' => 'hidden', '#default_value' => ''),
239 'configure' => array('#value' => isset($extra[$name]['configure']) ? $extra[$name]['configure'] : ''),
240 'remove' => array('#value' => isset($extra[$name]['remove']) ? $extra[$name]['remove'] : ''),
241 'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
242 '#leaf' => TRUE,
243 '#root' => TRUE,
244 '#disabled_row' => TRUE,
245 '#row_type' => 'extra',
246 );
247 $form['#field_rows'][] = $name;
248 $weights[] = $weight;
249 }
250
251 // Additional row : add new field.
252 $weight = !empty($weights) ? max($weights) + 1 : 0;
253 $field_type_options = cck_field_type_options();
254 $widget_type_options = cck_widget_type_options(NULL, TRUE);
255 if ($field_type_options && $widget_type_options) {
256 array_unshift($field_type_options, t('- Select a field type -'));
257 array_unshift($widget_type_options, t('- Select a widget -'));
258 $name = '_add_new_field';
259 $form[$name] = array(
260 'label' => array(
261 '#type' => 'textfield',
262 '#size' => 15,
263 '#description' => t('Label'),
264 ),
265 'field_name' => array(
266 '#type' => 'textfield',
267 // This field should stay LTR even for RTL languages.
268 '#field_prefix' => '<span dir="ltr">field_',
269 '#field_suffix' => '</span>&lrm;',
270 '#attributes' => array('dir'=>'ltr'),
271 '#size' => 15,
272 '#description' => t('Field name (a-z, 0-9, _)'),
273 ),
274 'type' => array(
275 '#type' => 'select',
276 '#options' => $field_type_options,
277 '#description' => theme('advanced_help_topic', 'cck', 'fields') . t('Type of data to store.'),
278 ),
279 'widget_type' => array(
280 '#type' => 'select',
281 '#options' => $widget_type_options,
282 '#description' => t('Form element to edit the data.'),
283 ),
284 'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
285 'parent' => array('#type' => 'select', '#options' => $group_options, '#default_value' => ''),
286 'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
287 '#leaf' => TRUE,
288 '#add_new' => TRUE,
289 '#row_type' => 'add_new_field',
290 );
291 $form['#field_rows'][] = $name;
292 }
293
294 // Additional row : add existing field.
295 $existing_field_options = cck_existing_field_options($bundle);
296 if ($existing_field_options && $widget_type_options) {
297 $weight++;
298 array_unshift($existing_field_options, t('- Select an existing field -'));
299 $name = '_add_existing_field';
300 $form[$name] = array(
301 'label' => array(
302 '#type' => 'textfield',
303 '#size' => 15,
304 '#description' => t('Label'),
305 ),
306 'field_name' => array(
307 '#type' => 'select',
308 '#options' => $existing_field_options,
309 '#description' => t('Field to share'),
310 ),
311 'widget_type' => array(
312 '#type' => 'select',
313 '#options' => $widget_type_options,
314 '#description' => t('Form element to edit the data.'),
315 ),
316 'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
317 'parent' => array('#type' => 'select', '#options' => $group_options, '#default_value' => ''),
318 'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
319 '#leaf' => TRUE,
320 '#add_new' => TRUE,
321 '#row_type' => 'add_existing_field',
322 );
323 $form['#field_rows'][] = $name;
324 }
325
326 // Additional row : add new group.
327 if (module_exists('fieldgroup')) {
328 $weight++;
329 $name = '_add_new_group';
330 $form[$name] = array(
331 'label' => array(
332 '#type' => 'textfield',
333 '#size' => 15,
334 '#description' => t('Label'),
335 ),
336 'group_name' => array(
337 '#type' => 'textfield',
338 // This field should stay LTR even for RTL languages.
339 '#field_prefix' => '<span dir="ltr">group_',
340 '#field_suffix' => '</span>&lrm;',
341 '#attributes' => array('dir'=>'ltr'),
342 '#size' => 15,
343 '#description' => t('Group name (a-z, 0-9, _)'),
344 ),
345 'group_option' => array(
346 '#type' => 'hidden',
347 '#value' => '',
348 ),
349 'group_type' => array(
350 '#type' => 'hidden',
351 '#value' => 'standard',
352 ),
353 'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
354 'parent' => array('#type' => 'hidden', '#default_value' => ''),
355 'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
356 '#root' => TRUE,
357 '#add_new' => TRUE,
358 '#row_type' => 'add_new_group',
359 );
360 $form['#group_rows'][] = $name;
361 }
362
363 $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
364 return $form;
365 }
366
367 function cck_field_overview_form_validate($form, &$form_state) {
368 _cck_field_overview_form_validate_add_new($form, $form_state);
369 _cck_field_overview_form_validate_add_existing($form, $form_state);
370 }
371
372 /**
373 * Helper function for cck_field_overview_form_validate.
374 *
375 * Validate the 'add new field' row.
376 */
377 function _cck_field_overview_form_validate_add_new($form, &$form_state) {
378
379 $field = $form_state['values']['_add_new_field'];
380
381 // Validate if any information was provided in the 'add new field' row.
382 if (array_filter(array($field['label'], $field['field_name'], $field['type'], $field['widget_type']))) {
383 // No label.
384 if (!$field['label']) {
385 form_set_error('_add_new_field][label', t('Add new field: you need to provide a label.'));
386 }
387
388 // No field name.
389 if (!$field['field_name']) {
390 form_set_error('_add_new_field][field_name', t('Add new field: you need to provide a field name.'));
391 }
392 // Field name validation.
393 else {
394 $field_name = $field['field_name'];
395
396 // Add the 'field_' prefix.
397 if (substr($field_name, 0, 6) != 'field_') {
398 $field_name = 'field_'. $field_name;
399 form_set_value($form['_add_new_field']['field_name'], $field_name, $form_state);
400 }
401
402 // Invalid field name.
403 if (!preg_match('!^field_[a-z0-9_]+$!', $field_name)) {
404 form_set_error('_add_new_field][field_name', t('Add new field: the field name %field_name is invalid. The name must include only lowercase unaccentuated letters, numbers, and underscores.', array('%field_name' => $field_name)));
405 }
406 if (strlen($field_name) > 32) {
407 form_set_error('_add_new_field][field_name', t('Add new field: the field name %field_name is too long. The name is limited to 32 characters, including the \'field_\' prefix.', array('%field_name' => $field_name)));
408 }
409 // A field named 'field_instance' would cause a tablename clash with {field_field_instance}
410 if ($field_name == 'field_instance') {
411 form_set_error('_add_new_field][field_name', t("Add new field: the name 'field_instance' is a reserved name."));
412 }
413
414 // Field name already exists.
415 // We need to check inactive fields as well, so we can't use field_fields().
416 module_load_include('inc', 'content', 'includes/content.crud');
417 $fields = field_read_fields(array(), TRUE);
418 $used = FALSE;
419 foreach ($fields as $existing_field) {
420 $used |= ($existing_field['field_name'] == $field_name);
421 }
422 if ($used) {
423 form_set_error('_add_new_field][field_name', t('Add new field: the field name %field_name already exists.', array('%field_name' => $field_name)));
424 }
425 }
426
427 // No field type.
428 if (!$field['type']) {
429 form_set_error('_add_new_field][type', t('Add new field: you need to select a field type.'));
430 }
431
432 // No widget type.
433 if (!$field['widget_type']) {
434 form_set_error('_add_new_field][widget_type', t('Add new field: you need to select a widget.'));
435 }
436 // Wrong widget type.
437 elseif ($field['type']) {
438 $widget_types = cck_widget_type_options($field['type']);
439 if (!isset($widget_types[$field['widget_type']])) {
440 form_set_error('_add_new_field][widget_type', t('Add new field: invalid widget.'));
441 }
442 }
443 }
444 }
445
446 /**
447 * Helper function for cck_field_overview_form_validate.
448 *
449 * Validate the 'add existing field' row.
450 */
451 function _cck_field_overview_form_validate_add_existing($form, &$form_state) {
452
453 // The form element might be absent if no existing fields can be added to
454 // this content type
455 if (isset($form_state['values']['_add_existing_field'])) {
456 $field = $form_state['values']['_add_existing_field'];
457
458 // Validate if any information was provided in the 'add existing field' row.
459 if (array_filter(array($field['label'], $field['field_name'], $field['widget_type']))) {
460 // No label.
461 if (!$field['label']) {
462 form_set_error('_add_existing_field][label', t('Add existing field: you need to provide a label.'));
463 }
464
465 // No existing field.
466 if (!$field['field_name']) {
467 form_set_error('_add_existing_field][field_name', t('Add existing field: you need to select a field.'));
468 }
469
470 // No widget type.
471 if (!$field['widget_type']) {
472 form_set_error('_add_existing_field][widget_type', t('Add existing field: you need to select a widget.'));
473 }
474 // Wrong widget type.
475 elseif ($field['field_name'] && ($existing_field = field_info_field($field['field_name']))) {
476 $widget_types = cck_widget_type_options($existing_field['type']);
477 if (!isset($widget_types[$field['widget_type']])) {
478 form_set_error('_add_existing_field][widget_type', t('Add existing field: invalid widget.'));
479 }
480 }
481 }
482 }
483 }
484
485 function cck_field_overview_form_submit($form, &$form_state) {
486 $form_values = $form_state['values'];
487 $bundle = $form['#bundle'];
488 $admin_path = _cck_bundle_admin_path($bundle);
489
490 // Update field weights.
491 $extra = array();
492 foreach ($form_values as $key => $values) {
493 // Groups are handled in fieldgroup_cck_overview_form_submit().
494 if (in_array($key, $form['#fields'])) {
495 db_query("UPDATE {field_config_instance} SET weight = %d WHERE bundle = '%s' AND field_name = '%s'",
496 $values['weight'], $bundle, $key);
497 }
498 elseif (in_array($key, $form['#extra'])) {
499 $extra[$key] = $values['weight'];
500 }
501 }
502
503 if ($extra) {
504 variable_set('cck_extra_weights_'. $bundle, $extra);
505 }
506 else {
507 variable_del('cck_extra_weights_'. $bundle);
508 }
509
510 $destinations = array();
511
512 // Create new field.
513 $field = array();
514 if (!empty($form_values['_add_new_field']['field_name'])) {
515 $values = $form_values['_add_new_field'];
516
517 $field = array(
518 'field_name' => $values['field_name'],
519 'type' => $values['type'],
520 );
521 $instance = array(
522 'field_name' => $field['field_name'],
523 'bundle' => $bundle,
524 'label' => $values['label'],
525 'weight' => $values['weight'],
526 'widget' => array(
527 'type' => $values['widget_type'],
528 ),
529 );
530
531 // Create the field and instance.
532 try {
533 field_create_field($field);
534 field_create_instance($instance);
535
536 // Rebuild the menu so we can navigate to the field settings screen.
537 //field_clear_type_cache(TRUE);
538 //menu_rebuild();
539 $destinations[] = $admin_path .'/fields/refresh';
540 $destinations[] = $admin_path .'/fields/'. $field['field_name'] .'/field-settings';
541 $destinations[] = $admin_path .'/fields/'. $field['field_name'] .'/edit';
542
543 // Store new field information for fieldgroup submit handler.
544 $form_state['fields_added']['_add_new_field'] = $field['field_name'];
545 }
546 catch (Exception $e) {
547 drupal_set_message(t('There was a problem creating field %label: @message.', array(
548 '%label' => $values['label'], '@message' => $e->getMessage())));
549 }
550 }
551
552 // Add existing field.
553 if (!empty($form_values['_add_existing_field']['field_name'])) {
554 $values = $form_values['_add_existing_field'];
555 $field = field_info_field($values['field_name']);
556 if (!empty($field['locked'])) {
557 drupal_set_message(t('The field %label cannot be added because it is locked.', array('%label' => $field['field_name'])));
558 }
559 else {
560 $instance = array(
561 'field_name' => $field['field_name'],
562 'bundle' => $bundle,
563 'label' => $values['label'],
564 'weight' => $values['weight'],
565 'widget' => array(
566 'type' => $values['widget_type'],
567 ),
568 );
569
570 try {
571 field_create_instance($instance);
572 $destinations[] = $admin_path .'/fields/refresh';
573 $destinations[] = $admin_path .'/fields/'. $instance['field_name'] .'/edit';
574 // Store new field information for fieldgroup submit handler.
575 $form_state['fields_added']['_add_existing_field'] = $instance['field_name'];
576 }
577 catch (Exception $e) {
578 drupal_set_message(t('There was a problem creating field instance %label: @message.', array(
579 '%label' => $field['label'], '@message' => $e->getMessage())));
580 }
581 }
582 }
583
584 if ($destinations) {
585 $destinations[] = urldecode(substr(drupal_get_destination(), 12));
586 unset($_REQUEST['destination']);
587 $form_state['redirect'] = cck_get_destinations($destinations);
588 }
589
590 field_cache_clear();
591 }
592
593 /**
594 * Menu callback; presents a listing of fields display settings for a content type.
595 *
596 * Form includes form widgets to select which fields appear for teaser, full node
597 * and how the field labels should be rendered.
598 */
599 function cck_display_overview_form(&$form_state, $obj_type, $bundle, $contexts_selector = 'basic') {
600 $bundle = field_attach_extract_bundle($obj_type, $bundle);
601
602 cck_inactive_message($bundle);
603 $admin_path = _cck_bundle_admin_path($bundle);
604
605 // Gather type information.
606 $entity = field_info_bundle_entity($bundle);
607 $instances = field_info_instances($bundle);
608 $field_types = field_info_field_types();
609
610 $groups = $group_options = array();
611 if (module_exists('fieldgroup')) {
612 $groups = fieldgroup_groups($bundle);
613 $group_options = _fieldgroup_groups_label($bundle);
614 }
615
616 $contexts = cck_build_modes($entity, $contexts_selector);
617 $form = array(
618 '#tree' => TRUE,
619 '#bundle' => $bundle,
620 '#fields' => array_keys($instances),
621 '#groups' => array_keys($groups),
622 '#contexts' => $contexts_selector,
623 );
624
625 if (empty($instances)) {
626 drupal_set_message(t('There are no fields configured yet. You can add new fields on the <a href="@link">Manage fields</a> page.', array('@link' => url($admin_path .'/fields'))), 'warning');
627 return $form;
628 }
629
630 // Fields.
631 $label_options = array(
632 'above' => t('Above'),
633 'inline' => t('Inline'),
634 'hidden' => t('<Hidden>'),
635 );
636 foreach ($instances as $name => $instance) {
637 $field = field_info_field($instance['field_name']);
638 $field_type = $field_types[$field['type']];
639 $defaults = $instance['display'];
640 $weight = $instance['weight'];
641
642 $form[$name] = array(
643 'human_name' => array('#markup' => check_plain($instance['label'])),
644 'weight' => array('#type' => 'value', '#value' => $weight),
645 'parent' => array('#type' => 'value', '#value' => ''),
646 );
647
648 // Formatters.
649 $options = cck_formatter_options($field['type']);
650 $options['hidden'] = t('<Hidden>');
651
652 foreach ($contexts as $key => $value) {
653 $form[$name][$key]['label'] = array(
654 '#type' => 'select',
655 '#options' => $label_options,
656 '#default_value' => isset($defaults[$key]['label']) ? $defaults[$key]['label'] : 'hidden',
657 );
658 $form[$name][$key]['type'] = array(
659 '#type' => 'select',
660 '#options' => $options,
661 '#default_value' => isset($defaults[$key]['type']) ? $defaults[$key]['type'] : 'default',
662 );
663 }
664 }
665
666 // Groups.
667 $label_options = array(
668 'above' => t('Above'),
669 'hidden' => t('<Hidden>'),
670 );
671 $options = array(
672 'no_style' => t('no styling'),
673 'simple' => t('simple'),
674 'fieldset' => t('fieldset'),
675 'fieldset_collapsible' => t('fieldset - collapsible'),
676 'fieldset_collapsed' => t('fieldset - collapsed'),
677 'hidden' => t('<Hidden>'),
678 );
679 foreach ($groups as $name => $group) {
680 $defaults = $group['settings']['display'];
681 $weight = $group['weight'];
682
683 $form[$name] = array(
684 'human_name' => array('#markup' => check_plain($group['label'])),
685 'weight' => array('#type' => 'value', '#value' => $weight),
686 );
687 foreach ($contexts as $key => $title) {
688 $form[$name][$key]['label'] = array(
689 '#type' => 'select',
690 '#options' => $label_options,
691 '#default_value' => isset($defaults[$key]['label']) ? $defaults[$key]['label'] : 'above',
692 );
693 $form[$name][$key]['format'] = array(
694 '#type' => 'select',
695 '#options' => $options,
696 '#default_value' => isset($defaults[$key]['format']) ? $defaults[$key]['format'] : 'fieldset',
697 );
698 }
699 foreach ($group['fields'] as $field_name => $field) {
700 $form[$field_name]['parent']['#value'] = $name;
701 }
702 }
703
704 $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
705 return $form;
706 }
707
708 /**
709 * Submit handler for the display overview form.
710 */
711 function cck_display_overview_form_submit($form, &$form_state) {
712
713 module_load_include('inc', 'field', 'includes/field.crud');
714 $form_values = $form_state['values'];
715 foreach ($form_values as $key => $values) {
716 // Groups are handled in fieldgroup_display_overview_form_submit().
717 if (in_array($key, $form['#fields'])) {
718 $instance = field_info_instance($key, $form['#bundle']);
719 unset($values['weight'], $values['parent']);
720 $instance['display'] = array_merge($instance['display'], $values);
721 field_update_instance($instance);
722 }
723 }
724 drupal_set_message(t('Your settings have been saved.'));
725 }
726
727 /**
728 * Return an array of field_type options.
729 */
730 function cck_field_type_options() {
731 static $options;
732
733 if (!isset($options)) {
734 $options = array();
735 $field_types = field_info_field_types();
736 $field_type_options = array();
737 foreach ($field_types as $name => $field_type) {
738 // Skip field types which have no widget types.
739 if (cck_widget_type_options($name)) {
740 $options[$name] = t($field_type['label']);
741 }
742 }
743 asort($options);
744 }
745 return $options;
746 }
747
748 /**
749 * Return an array of widget type options for a field type.
750 *
751 * If no field type is provided, returns a nested array of
752 * all widget types, keyed by field type human name.
753 */
754 function cck_widget_type_options($field_type = NULL, $by_label = FALSE) {
755 static $options;
756
757 if (!isset($options)) {
758 $options = array();
759 foreach (field_info_widget_types() as $name => $widget_type) {
760 foreach ($widget_type['field types'] as $widget_field_type) {
761 $options[$widget_field_type][$name] = t($widget_type['label']);
762 }
763 }
764 }
765
766 if ($field_type) {
767 return !empty($options[$field_type]) ? $options[$field_type] : array();
768 }
769 elseif ($by_label) {
770 $field_types = field_info_field_types();
771 $options_by_label = array();
772 foreach ($options as $field_type => $widgets) {
773 $options_by_label[t($field_types[$field_type]['label'])] = $widgets;
774 }
775 return $options_by_label;
776 }
777 else {
778 return $options;
779 }
780 }
781
782 /**
783 * Return an array of formatter options for a field type.
784 *
785 * If no field type is provided, returns a nested array of
786 * all formatters, keyed by field type.
787 */
788 function cck_formatter_options($field_type = NULL) {
789 static $options;
790
791 if (!isset($options)) {
792 $options = array();
793 foreach (field_info_formatter_types() as $name => $formatter) {
794 foreach ($formatter['field types'] as $formatter_field_type) {
795 $options[$formatter_field_type][$name] = t($formatter['label']);
796 }
797 }
798 }
799
800 if ($field_type) {
801 return !empty($options[$field_type]) ? $options[$field_type] : array();
802 }
803 else {
804 return $options;
805 }
806 }
807
808 /**
809 * Return an array of existing field to be added to a node type.
810 */
811 function cck_existing_field_options($bundle) {
812 $bundles = field_info_instances();
813 $options = array();
814 $field_types = field_info_field_types();
815 foreach ($bundles as $bundle_name => $instances) {
816 // No need to look in the currenht bundle.
817 if ($bundle_name != $bundle) {
818 foreach ($instances as $instance) {
819 $field = field_info_field($instance['field_name']);
820 // Don't show locked fields, or fields that are already in the current
821 // bundle.
822 if (empty($field['locked']) && !field_info_instance($field['field_name'], $bundle)) {
823 $text = t('@type: @field (@label)', array('@type' => t($field_types[$field['type']]['label']), '@label' => t($instance['label']), '@field' => $instance['field_name']));
824 $options[$instance['field_name']] = (drupal_strlen($text) > 80) ? truncate_utf8($text, 77) . '...' : $text;
825 }
826 }
827 }
828 }
829 // Sort the list by type, then by field name, then by label.
830 asort($options);
831 return $options;
832 }
833
834 /**
835 * Helper function to determine if a field has data in the database.
836 */
837 function cck_field_has_data($field_name) {
838 $has_data = FALSE;
839 if (drupal_function_exists('field_db_tablename')) {
840 $table = field_db_tablename($field_name);
841 if (db_table_exists($table)) {
842 $query = db_select($table, 'f', array('fetch' => PDO::FETCH_ASSOC));
843 $query->fields('f', array('entity_id'));
844 $query->condition('f.deleted', 0);
845 $results = $query->execute()->fetchAssoc();
846 if (!empty($results)) {
847 $has_data = TRUE;
848 }
849 }
850 }
851 return $has_data;
852 }
853
854 /**
855 * Menu callback; presents the field settings edit page.
856 */
857 function cck_field_settings_form(&$form_state, $obj_type, $bundle, $field_name) {
858 $bundle = field_attach_extract_bundle($obj_type, $bundle);
859
860 $instance = field_info_field($field_name, $bundle);
861 $field = field_info_field($field_name);
862
863 // When a field is first created, we have to get data from the db.
864 if (!isset($instance['label'])) {
865 $instance = field_read_instance($field_name, $bundle);
866 $field = field_read_field($field_name);
867 }
868
869 $field_type = field_info_field_types($field['type']);
870
871 $info_function = $field['module'] .'_field_info';
872 $info = $info_function();
873 $description = '<p><strong>'. $info[$field['type']]['label'] .':</strong> ';
874 $description .= $info[$field['type']]['description'] .'</p>';
875 $form['#prefix'] = '<div class="description">'. $description .'</div>';
876
877 $description = '<p>'. t('These settings apply to the %field field everywhere it is used. These settings impact the way that data is stored in the database and cannot be changed once data has been created.', array(
878 '%field' => $instance['label'])) .'</p>';
879
880 // Create a form structure for the field values.
881 $form['field'] = array(
882 '#type' => 'fieldset',
883 '#title' => t('%field field settings', array('%field' => $instance['label'])),
884 '#description' => $description,
885 '#tree' => TRUE,
886 );
887
888 // See if data already exists for this field.
889 // If so, prevent changes to the field settings.
890 $has_data = cck_field_has_data($field_name);
891 if ($has_data) {
892 $form['field']['#description'] = '<div class=error>'. t('There is data for this field in the database. The field settings can no longer be changed.' .'</div>') . $form['field']['#description'];
893 }
894
895 // Build the non-configurable field values.
896 $form['field']['field_name'] = array('#type' => 'value', '#value' => $field_name);
897 $form['field']['type'] = array('#type' => 'value', '#value' => $field['type']);
898 $form['field']['module'] = array('#type' => 'value', '#value' => $field['module']);
899 $form['field']['active'] = array('#type' => 'value', '#value' => $field['active']);
900
901 // Add settings provided by the field module.
902 $form['field']['settings'] = array();
903 $additions = module_invoke($field_type['module'], 'field_settings_form', $field, $instance);
904 if (is_array($additions)) {
905 $form['field']['settings'] = $additions;
906 // TODO Filter this so only the settings that cannot be changed are shown in this form.
907 // For now, treating all settings as changeable, which means they show up here and in edit form.
908 }
909 if (empty($form['field']['settings'])) {
910 $form['field']['settings'] = array(
911 '#markup' => t('%field has no field settings.', array('%field' => $instance['label'])),
912 );
913 }
914 else {
915 foreach ($form['field']['settings'] as $key => $setting) {
916 if (substr($key, 0, 1) != '#') {
917 $form['field']['settings'][$key]['#disabled'] = $has_data;
918 }
919 }
920 }
921
922 $form['#bundle'] = $bundle;
923
924 $form['submit'] = array(
925 '#type' => 'submit',
926 '#value' => t('Save field settings'),
927 );
928
929 return $form;
930 }
931
932 /**
933 * Save a field's settings after editing.
934 */
935 function cck_field_settings_form_submit($form, &$form_state) {
936 $form_values = $form_state['values'];
937 $field_values = $form_values['field'];
938
939 // Don't allow changes to fields with data.
940 if (cck_field_has_data($field_values['field_name'])) {
941 return;
942 }
943
944 // Merge incoming form values into the existing field.
945 $field = field_info_field($field_values['field_name']);
946 // Remove the 'bundles' element added by field_info_field
947 // TODO: this is ugly, there should be a better way.
948 unset($field['bundles']);
949 $bundle = $form['#bundle'];
950 $instance = field_info_instance($field['field_name'], $bundle);
951
952 // Update the field.
953 $field = array_merge($field, $field_values);
954 cck_field_update_field($field);
955
956 drupal_set_message(t('Updated field %label field settings.', array('%label' => $instance['label'])));
957 $form_state['redirect'] = cck_next_destination($form_state, $bundle);
958 }
959
960 /**
961 * The Field API doesn't allow field updates,
962 * so we create a method here to update field if no data is created yet.
963 *
964 * @see
965 * field_create_field()
966 */
967 function cck_field_update_field($field) {
968 $field_types = field_info_field_types();
969 $module = $field_types[$field['type']]['module'];
970
971 $defaults = field_info_field_settings($field['type']);
972 $field['settings'] = array_merge($defaults, (array) $field['settings']);
973 $data = $field;
974 unset($data['id'], $data['columns'], $data['field_name'], $data['type'], $data['locked'], $data['module'], $data['cardinality'], $data['active'], $data['deleted']);
975 $field['data'] = $data;
976
977 drupal_write_record('field_config', $field, array('field_name'));
978
979 // Clear caches
980 field_cache_clear(TRUE);
981 }
982
983 /**
984 * Menu callback; select a widget for the field.
985 */
986 function cck_widget_type_form(&$form_state, $obj_type, $bundle, $field_name) {
987 $bundle = field_attach_extract_bundle($obj_type, $bundle);
988
989 $instance = field_read_instance($field_name, $bundle);
990 $field = field_read_field($field_name);
991
992 $field_type = field_info_field_types($field['type']);
993 $widget_type = field_info_widget_types($instance['widget']['type']);
994 $bundles = field_info_bundles();
995 $bundle_label = $bundles[$bundle]['label'];
996
997 $form = array();
998 $form['basic'] = array(
999 '#type' => 'fieldset',
1000 '#title' => t('Change widget'),
1001 );
1002 $form['basic']['widget_type'] = array(
1003 '#type' => 'select',
1004 '#title' => t('Widget type'),
1005 '#required' => TRUE,
1006 '#options' => cck_widget_type_options($field['type']),
1007 '#default_value' => $instance['widget']['type'],
1008 '#description' => t('The type of form element you would like to present to the user when creating this field in the %type type.', array('%type' => $bundle_label)),
1009 );
1010
1011 $form['#instance'] = $instance;
1012 $form['submit'] = array(
1013 '#type' => 'submit',
1014 '#value' => t('Continue'),
1015 );
1016
1017 $form['#validate'] = array();
1018 $form['#submit'] = array('cck_widget_type_form_submit');
1019
1020 return $form;
1021 }
1022
1023 /**
1024 * Submit the change in widget type.
1025 */
1026 function cck_widget_type_form_submit($form, &$form_state) {
1027 $form_values = $form_state['values'];
1028 $instance = $form['#instance'];
1029 $bundle = $instance['bundle'];
1030
1031 // Set the right module information
1032 $widget_type = field_info_widget_types($form_values['widget_type']);
1033 $widget_module = $widget_type['module'];
1034
1035 if (drupal_function_exists('field_update_instance')) {
1036 $instance['widget']['type'] = $form_values['widget_type'];
1037 $instance['widget']['module'] = $widget_module;
1038 try {
1039 field_update_instance($instance);
1040 drupal_set_message(t('Changed the widget for field %label.', array(
1041 '%label' => $instance['label'])));
1042 } catch (FieldException $e) {
1043 drupal_set_message(t('There was a problem changing the widget for field %label.', array(
1044 '%label' => $instance['label'])));
1045 }