9 * Overview over all tables.
11 function data_ui_overview() {
12 $tables = data_get_all_tables();
14 foreach ($tables as
$table) {
15 // Build operations depending on configuration status.
16 $operations = array();
17 if ($table->get('export_type') == EXPORT_IN_CODE
) {
18 $status = t('Default');
19 $operations[] = l(t('Override'), 'admin/content/data/edit/'.
$table->get('name'));
21 else if ($table->get('export_type') == (EXPORT_IN_CODE
| EXPORT_IN_DATABASE
)) {
22 $status = t('Overridden');
23 $operations[] = l(t('Edit'), 'admin/content/data/edit/'.
$table->get('name'));
24 $operations[] = l(t('Revert'), 'admin/content/data/revert/'.
$table->get('name'));
27 $status = t('Normal');
28 $operations[] = l(t('Edit'), 'admin/content/data/edit/'.
$table->get('name'));
29 $operations[] = l(t('Drop'), 'admin/content/data/drop/'.
$table->get('name'));
31 if (module_exists('ctools')) {
32 $operations[] = l(t('Export'), 'admin/content/data/export/'.
$table->get('name'));
36 $row[] = $table->get('name');
38 $row[] = implode(' | ', $operations);
43 l(t('Create new table'), 'admin/content/data/create'),
47 $header = array(t('Name'), t('Status'), t('Operations'));
48 return theme('table', $header, $rows);
54 function data_ui_compare() {
56 $tables = data_get_all_tables();
57 foreach ($tables as
$table) {
59 $comp = $table->compareSchema();
60 $row[] = $table->get('name');
61 $status = $comp['status'];
62 if ($status != 'same') {
63 $status .
= ' - '.
l(t('adjust'), 'admin/content/data/compare/'.
$table->get('name'));
66 $row[] = empty($comp['warning']) ?
'-' : $comp['warning'];
69 $header = array(t('Name'), t('Status'), t('Warnings'));
70 return theme('table', $header, $rows);
74 * Adjust table schema form: Present the user with the difference between schema information and
75 * the actual schema in the Database and offer three options:
77 * - Adjust schema info,
78 * - adjust database or
81 function data_ui_adjust_form(&$form_state, $table) {
82 drupal_set_title(t('Adjust !table', array('!table' => $table->get('name'))));
83 $comparison = $table->compareSchema();
86 $form['#redirect'] = 'admin/content/data/compare';
87 $form['#table'] = $table;
88 $form['#comparison'] = $comparison;
89 $form['comparison'] = array(
90 '#type' => 'fieldset',
91 '#title' => t('Comparison'),
93 $form['comparison']['comparison']['#value'] = theme('data_ui_schema_compare_table', $comparison);
95 if ($comparison['status'] == 'different') {
96 $form['update_schema'] = array(
97 '#type' => 'fieldset',
98 '#title' => t('Option 1: Update schema information'),
100 $form['update_schema']['description'] = array(
101 '#value' => t('<p>This option will update the schema information about this table.</p>'),
103 $form['update_schema']['submit'] = array(
105 '#submit' => array('data_ui_adjust_form_submit_update_schema'),
106 '#value' => t('Update schema information'),
108 $form['alter_table'] = array(
109 '#type' => 'fieldset',
110 '#title' => t('Option 2: Alter table'),
112 $form['alter_table']['description'] = array(
113 '#value' => t('<p>Review the changes above carefully!
114 This option will alter the database table and can very
115 easily cause data loss.</p>'),
117 $form['alter_table']['submit'] = array(
119 '#submit' => array('data_ui_adjust_form_submit_alter_table'),
120 '#value' => t('Alter table'),
123 elseif ($comparison['status'] == 'missing') {
124 $form['alter_table'] = array(
125 '#type' => 'fieldset',
126 '#title' => t('Create table'),
128 $form['alter_table']['description'] = array(
129 '#value' => t('<p>Create a new table from schema information.</p>'),
131 $form['alter_table']['submit'] = array(
133 '#submit' => array('data_ui_adjust_form_submit_create_table'),
134 '#value' => t('Create table'),
137 $form['cancel'] = array(
138 '#type' => 'fieldset',
139 '#title' => t('Don\'t change anything'),
141 $form['cancel']['cancel'] = array(
143 '#value' => t('Cancel'),
149 * Submit handler for data_ui_adjust_form().
151 function data_ui_adjust_form_submit_update_schema($form, &$form_state) {
152 $table = $form['#table'];
153 $schema = schema_invoke('inspect');
154 if (isset($schema[$table->get('name')])) {
155 $table->update(array('table_schema' => $schema[$table->get('name')]));
156 drupal_set_message(t('Updated schema for !table', array('!table' => $table->get('name'))));
159 drupal_set_message(t('Error updating schema'), 'error');
164 * Submit handler for data_ui_adjust_form().
166 function data_ui_adjust_form_submit_alter_table($form, &$form_state) {
167 $resolved = $resolved = array();
168 if (isset($form['#comparison']['reasons'])) {
169 foreach ($form['#comparison']['reasons'] as
$field_reason) {
170 if (_data_ui_alter_table($form['#table'], $field_reason)) {
171 $resolved[] = $field_reason;
174 $unresolved[] = $field_reason;
178 if (count($resolved)) {
179 drupal_set_message(t('Resolved') .
theme_item_list($resolved));
181 if (count($unresolved)) {
182 drupal_set_message(t('Could not resolve') .
theme_item_list($unresolved), 'error');
187 * Submit handler for data_ui_adjust_form().
189 function data_ui_adjust_form_submit_create_table($form, &$form_state) {
190 $table = $form['#table'];
192 db_create_table($ret, $table->get('name'), $table->get('table_schema'));
193 drupal_get_schema($table->get('name'), TRUE
);
194 if ($ret[0]['success']) {
195 drupal_set_message(t('Created table !table', array('!table' => $table->get('name'))));
198 drupal_set_message(t('Error creating table'), 'error');
203 * Form callback for create table form.
205 function data_ui_create_form(&$form_state) {
207 if (!$form_state['storage']['field_num']) {
208 $form['name'] = array(
209 '#type' => 'textfield',
210 '#title' => t('Table name'),
211 '#description' => t('Machine readable name of the table - e. g. "my_table". Must only contain lower case letters and _.'),
214 $form['title'] = array(
215 '#type' => 'textfield',
216 '#title' => t('Table title'),
217 '#description' => t('Natural name of the table - e. g. "My Table".'),
219 $form['field_num'] = array(
220 '#type' => 'textfield',
221 '#title' => t('Number of fields'),
222 '#description' => t('The number of fields this table should contain.'),
223 '#default_value' => 1,
226 $form['submit'] = array(
228 '#value' => t('Next'),
232 $form['help']['#value'] = t('Define the fields of the new table.');
233 $form['fields'] = array(
236 for ($i = 0; $i < $form_state['storage']['field_num']; $i++) {
237 $form['fields']['field_'.
$i] = _data_ui_field_form(TRUE
);
239 $form['submit'] = array(
241 '#value' => t('Create'),
248 * Validate handler for create table form.
250 function data_ui_create_form_validate($form, &$form_state) {
251 if (data_get_table(data_name($form_state['values']['name']))) {
252 form_set_error('name', t('Name is already taken.'));
254 if (isset($form_state['values']['field_num'])) {
255 if (is_numeric($form_state['values']['field_num'])) {
256 if ($form_state['values']['field_num'] < 1) {
257 form_set_error('field_num', t('At least one field must be created.'));
261 form_set_error('field_num', t('Enter a number greater than 0.'));
265 if (isset($form_state['values']['fields'])) {
267 foreach ($form_state['values']['fields'] as
$field) {
268 if (is_numeric($names[$field['name']])) {
269 form_set_error('name', t('Names can\'t be numbers.'));
271 if (!isset($names[$field['name']])) {
272 $names[$field['name']] = $field['name'];
275 form_set_error('name', t('Names must be unique.'));
282 * Submit handler for create table form.
284 function data_ui_create_form_submit($form, &$form_state) {
286 if (isset($form_state['values']['field_num'])) {
287 $form_state['storage'] = $form_state['values'];
289 elseif (isset($form_state['values']['fields'])) {
291 // Create a schema from user input.
292 $schema = $index = $primary = $meta = array();
293 foreach ($form_state['values']['fields'] as
$field) {
294 $schema['fields'][$field['name']] = data_build_field_definition($field);
295 $meta['fields'][$field['name']]['label'] = $field['label'];
297 // Limit index if field type is text.
298 if (!empty($field['index'])) {
299 $index[$field['name']] = data_get_index_definition($field['name'], $field['type']);
301 if (!empty($field['primary'])) {
302 $primary[] = data_get_pk_definition($field['name'], $field['type']);
305 $schema['indexes'] = $index;
306 $schema['primary key'] = $primary;
309 if ($table = data_create_table(data_name(trim($form_state['storage']['name'])), $schema, trim($form_state['storage']['title']))) {
310 $meta = $table->update(array('meta' => $meta));
311 drupal_set_message(t('Created table !table', array('!table' => $table->get('name'))));
314 drupal_set_message(t('Error creating table'), 'error');
317 // Unset storage to enable redirect.
318 unset($form_state['storage']);
319 $form_state['redirect'] = 'admin/content/data';
324 * Form callback for revert table form.
326 function data_ui_revert_form(&$form_state, $table) {
328 $form['#redirect'] = 'admin/content/data';
329 $form['#table'] = $table;
331 return confirm_form($form,
332 t('Revert this table?'),
333 'admin/content/data',
334 t('Are you sure you would like to revert table !table? This will reset all information about this table its definition in code. This action cannot be undone.', array('!table' => $table->get('name'))),
335 t('Revert'), t('Cancel')
340 * Submit handler for data_ui_revert_form().
342 function data_ui_revert_form_submit($form, &$form_state) {
343 $table = $form['#table'];
348 * Form callback for drop table form.
350 function data_ui_drop_form(&$form_state, $table) {
352 $form['#redirect'] = 'admin/content/data';
353 $form['#table'] = $table;
355 return confirm_form($form,
356 t('Drop this table?'),
357 'admin/content/data',
358 t('Are you sure you would like to drop table !table? This action cannot be undone.', array('!table' => $table->get('name'))),
359 t('Drop'), t('Cancel')
364 * Submit handler for data_ui_drop_form().
366 function data_ui_drop_form_submit($form, &$form_state) {
367 $table = $form['#table'];
368 data_drop_table($table->get('name'));
372 * Form callback for editing a table.
374 function data_ui_edit_form(&$form_state, $table) {
375 drupal_set_title(t('Data table !table', array('!table' => $table->get('name'))));
376 $schema = $table->get('table_schema');
377 $meta = $table->get('meta');
381 $form['table'] = array(
387 $form['fields'] = array('#tree' => TRUE
);
388 if (isset($schema['fields'])) {
389 foreach ($schema['fields'] as
$field_name => $field) {
390 $form['fields'][$field_name] = array();
391 $form['fields'][$field_name]['selected'] = array(
392 '#type' => 'checkbox',
394 $form['fields'][$field_name]['name'] = array('#value' => $field_name);
395 $form['fields'][$field_name]['label'] = array(
396 '#type' => 'textfield',
398 '#default_value' => $meta['fields'][$field_name]['label'],
400 $form['fields'][$field_name]['type'] = array(
402 '#options' => data_get_field_types(),
403 '#default_value' => $field['type'],
405 $form['fields'][$field_name]['unsigned'] = array(
406 '#type' => 'checkbox',
407 '#default_value' => $field['unsigned'],
409 $form['fields'][$field_name]['index'] = array(
410 '#type' => 'checkbox',
411 '#default_value' => isset($schema['indexes'][$field_name]),
413 $form['fields'][$field_name]['primary'] = array(
414 '#type' => 'checkbox',
415 '#default_value' => isset($schema['primary key']) ?
in_array($field_name, $schema['primary key']) : FALSE
,
417 if ($join = _data_ui_get_join($meta['join'], $field_name)) {
418 $join = $join['left_table'] .
'.'.
$join['left_field'];
423 $join = l($join, 'admin/content/data/edit/'.
$table->get('name') .
'/join/'.
$field_name);
424 $form['fields'][$field_name]['join']['#value'] = $join;
429 $form['new'] = _data_ui_field_form();
430 $form['new']['primary'] = array(
432 '#value' => ' ',
434 $form['new']['join'] = array(
436 '#value' => ' ',
438 $form['new']['add'] = array(
440 '#value' => t('Add new'),
445 t('Bulk operations'),
446 'delete' => t('Delete all selected'),
448 $form['bulk_operation'] = array(
450 '#options' => $options,
452 $form['submit'] = array(
454 '#value' => t('Save'),
463 function data_ui_edit_form_submit($form, &$form_state) {
464 $table = $form_state['values']['table'];
465 $schema = $table->get('table_schema');
467 if ($form_state['clicked_button']['#value'] == t('Save')) {
468 $fields = $schema['fields'];
469 $new_fields = $form_state['values']['fields'];
471 $new_index = array();
472 $new_primary_key = array();
474 if (empty($form_state['values']['bulk_operation']) && isset($fields)) {
477 foreach ($fields as
$field_name => $field) {
478 if ($new_spec = _data_ui_changed($new_fields[$field_name], $field)) {
479 $table->changeField($field_name, $new_spec);
480 drupal_set_message(t('Changed field !field_name', array('!field_name' => $field_name)));
482 if ($new_fields[$field_name]['index']) {
483 $new_index[] = $field_name;
485 if ($new_fields[$field_name]['primary']) {
486 $new_primary_key[] = $field_name;
489 $table->changeIndex($new_index);
490 $table->changePrimaryKey($new_primary_key);
493 $meta = $table->get('meta');
494 foreach ($new_fields as
$field_name => $field) {
495 $meta['fields'][$field_name]['label'] = $field['label'];
497 $table->update(array('meta' => $meta));
501 switch ($form_state['values']['bulk_operation']) {
503 foreach ($new_fields as
$field_name => $field) {
504 if (!empty($field['selected'])) {
505 // One field must stay.
506 $schema = $table->get('table_schema');
507 if (count($schema['fields']) > 1) {
508 $table->dropField($field_name);
509 drupal_set_message(t('Deleted field !field_name', array('!field_name' => $field_name)));
512 drupal_set_message('You cannot delete all fields from a table, drop the table instead.', 'error');
520 elseif ($form_state['clicked_button']['#value'] == t('Add new')) {
521 $new = $form_state['values']['new'];
522 $spec = data_build_field_definition($new);
523 $table->addField($new['name'], $spec);
524 if (!empty($new['index'])) {
525 $table->addIndex($new['name']);
527 $meta = $table->get('meta');
528 $meta['fields'][$new['name']]['label'] = $new['label'];
529 $table->update(array('meta' => $meta));
536 function data_ui_join_form(&$form_state, $table, $field_name) {
537 // drupal_set_title(t('Join field'));
539 $schema = $table->get('table_schema');
540 $meta = $table->get('meta');
543 if (!isset($field_name) || !isset($schema['fields'][$field_name])) {
544 drupal_set_message(t('Invalid field.'), 'error');
545 drupal_goto('admin/content/data/edit/'.
$table->get('name'));
548 // List all tables that schema API knows about as optoins.
549 // @todo: This is a looong list - needs some AHAH to scale better.
550 $table_schemas = drupal_get_schema();
551 ksort($table_schemas);
553 foreach ($table_schemas as
$table_name => $schema) {
554 if ($table->get('name') != $table_name) {
555 foreach ($schema['fields'] as
$name => $info) {
556 $options[$table_name][$table_name .
'.'.
$name] = $table_name .
'.'.
$name;
563 $form['#table'] = $table;
564 $form['#field_name'] = $field_name;
565 $form['#redirect'] = 'admin/content/data/edit/'.
$table->get('name');
566 $join = _data_ui_get_join($meta['join'], $field_name);
567 $form['#original_join'] = $join;
568 $form['left'] = array(
570 '#title' => t('Join !table_field to', array('!table_field' => $table->get('name') .
'.'.
$field_name)),
571 '#options' => $options,
572 '#default_value' => $join['left_table'] .
'.'.
$join['left_field'],
574 $form['inner_join'] = array(
576 '#title' => t('Join type'),
577 '#options' => array(t('Left join'), t('Inner join')),
578 '#default_value' => $join['inner_join'] ?
$join['inner_join'] : 0,
581 // Use confirm form for its formatting.
582 $form = confirm_form($form,
584 'admin/content/data/edit/'.
$table->get('name'),
586 t('Save'), t('Cancel')
588 $form['actions']['delete'] = array(
590 '#value' => t('Delete'),
591 '#submit' => array('data_ui_join_form_submit_delete'),
593 krsort($form['actions']);
599 * Submit handler for data_ui_join_form().
601 function data_ui_join_form_submit($form, &$form_state) {
602 list($left_table, $left_field) = explode('.', $form_state['values']['left']);
603 $form['#table']->link($left_table, $left_field, $form['#field_name'], $form_state['values']['inner_join']);
604 drupal_set_message(t('Updated join information.'));
608 * Submit handler for data_ui_join_form() - handles deletion.
610 function data_ui_join_form_submit_delete($form, &$form_state) {
611 // Use the original join information.
612 $form['#table']->unlink($form['#original_join']['left_table']);
613 drupal_set_message(t('Removed join information.'));
619 function data_ui_export_form(&$form_state, $table) {
620 $code = data_export($table->get('name'));
622 $form['export'] = array(
623 '#title' => t('Export table definition'),
624 '#type' => 'textarea',
626 '#rows' => substr_count($code, "\n"),
632 * Theme data_ui_create_form.
634 function theme_data_ui_create_form($form) {
636 // Render field definition form elements in a table.
637 if (isset($form['fields'])) {
638 $output = drupal_render($form['help']);
641 foreach (element_children($form['fields']) as
$e) {
643 foreach (element_children($form['fields'][$e]) as
$f) {
644 $row[] = drupal_render($form['fields'][$e][$f]);
648 $header = array(t('Name *'), t('Label'), t('Type'), t('Unsigned'), t('Index'), t('Primary key'));
649 $output .
= theme('table', $header, $rows);
651 $output .
= drupal_render($form);
654 return drupal_render($form);
658 * Theme data_ui_admin_form.
660 function theme_data_ui_edit_form($form) {
662 // Format existing fields.
664 foreach (element_children($form['fields']) as
$e) {
666 foreach (element_children($form['fields'][$e]) as
$f) {
667 $row[] = drupal_render($form['fields'][$e][$f]);
674 $row = array(' ');
675 foreach (element_children($form['new']) as
$e) {
676 $row[] = drupal_render($form['new'][$e]);
680 $header = array(t('Select'), t('Name'), t('Label'), t('Type'), t('Unsigned'), t('Index'), t('Primary key'), t('Joins'));
681 $output .
= theme('table', $header, $rows);
682 $output .
= drupal_render($form);
687 * Theme a schema module comparison result. Ie. the result of schema_compare_table().
689 * @todo: move to schema module - write a patch.
691 function theme_data_ui_schema_compare_table($comparison) {
693 foreach ($comparison as
$k => $v) {
697 $output .
= '<dt>'.
ucfirst($k) .
':</dt>';
702 elseif (is_array($v)) {
703 $output .
= theme('item_list', $v);
714 * Magic helper function. Detect changed between keys in $new and $field
715 * and return a new field spec based on $field IF there are differences.
717 * Otherwise return FALSE.
719 * Currently checked: type, unsigned
721 function _data_ui_changed($new, $field) {
723 if ($field['type'] != $new['type']) {
724 $field['type'] = $new['type'];
727 if ($field['unsigned'] != $new['unsigned']) {
728 $field['unsigned'] = $new['unsigned'];
738 * Helper function that generates a form snippet for defining a field.
740 function _data_ui_field_form($required = FALSE
) {
742 $form['#tree'] = TRUE
;
743 $form['name'] = array(
744 '#type' => 'textfield',
746 '#required' => $required,
748 $form['label'] = array(
749 '#type' => 'textfield',
752 $form['type'] = array(
754 '#options' => data_get_field_types(),
756 $form['unsigned'] = array(
757 '#type' => 'checkbox',
759 $form['index'] = array(
760 '#type' => 'checkbox',
762 $form['primary'] = array(
763 '#type' => 'checkbox',
769 * Helper function to get link information for a specific field.
771 function _data_ui_get_join($join, $field) {
772 if (is_array($join)) {
773 foreach ($join as
$left_table => $info) {
774 if ($info['field'] == $field) {
775 $info['left_table'] = $left_table;
784 * Helper function for adjusting a table's real schema.
785 * @todo: this should live in schema module and should use better defined $reason keys.
787 function _data_ui_alter_table($table, $field_reason) {
788 list($field, $reason) = explode(': ', $field_reason);
789 $schema = $table->get('table_schema');
792 case
'not in database':
793 if (isset($schema['fields'][$field])) {
794 return $table->addField($field, $schema['fields'][$field]);
798 case
'missing in database':
799 list($type, $field) = explode(' ', $field);
800 // @todo: support multiple keys.
801 if ($type == 'indexes') {
802 return $table->addIndex($field);
804 elseif ($type == 'unique keys') {
805 return $table->addUniqueKey($field);
807 elseif ($type == 'primary key') {
808 return $table->addPrimaryKey($schema['primary keys']);
812 case
'primary key:<br />declared': // @todo: yikes!
813 $table->dropPrimaryKey();
814 return $table->changePrimaryKey($schema['primary keys']);
815 case
'missing in schema':
816 if ($field == 'primary key') {
817 return $table->dropPrimaryKey();
821 case
'unexpected column in database':
822 return $this->dropField($field);