/[drupal]/contributions/sandbox/deekayen/modules/cck_table_despliter/cck_table_despliter.module
ViewVC logotype

Contents of /contributions/sandbox/deekayen/modules/cck_table_despliter/cck_table_despliter.module

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


Revision 1.1 - (show annotations) (download) (as text)
Fri Oct 19 14:30:59 2007 UTC (2 years, 1 month ago) by deekayen
Branch: MAIN
CVS Tags: HEAD
File MIME type: text/x-php
initial commit for Drupal 4.7; known bugs commented in source
1 <?php
2 // $Id:$
3
4 /**
5 * @file
6 * You've just created a new content type and re-used some of
7 * the existing fields from an existing content type for your
8 * new content type. Shortly thereafter, you've discovered
9 * the custom reporting queries to built based on your old
10 * content type don't work anymore. That's because CCK moved
11 * them to a new table. It's more efficient, right? Maybe not
12 * if you have go to go mod all your existing queries in the
13 * sake of not duping a field in your database.
14 *
15 * This mod helps automate the reversal of the CCKism
16 * that splits fields into a separate table
17 * when you re-use an existing field.
18 *
19 * Here is your second chance to move the fields back to
20 * their original table and re-create the fields on the new
21 * content type anew, like you should have in the first place.
22 *
23 * Module development sponsored by Classic Graphics for Drupal 4.7.
24 *
25 * @todo some insert variables as part of the sql string
26 * instead of using the more proper replacement notation
27 * the DB abstraction layer can filter in part because at the
28 * time of writing this, David didn't know if the replacement
29 * of variables or table names for prefixes happened first
30 * and part of the whole point of this script is to dynamically
31 * work with different tables.
32 * @todo support tables and fields with long names that CCK normally
33 * truncates
34 * @author David Kent Norman
35 * @link http://deekayen.net/
36 * @link http://www.cgraphics.com/ Classic Graphics
37 */
38
39 function cck_table_despliter_help($section) {
40 switch ($section) {
41 case 'admin/modules#description':
42 return t('<strong>CCK:</strong> <strong>DEVELOPMENT CODE ONLY!</STRONG> Merges node_data_field_* tables back into fields on the node_content_* tables. This module was written for two specific situations. If you use this module outside its intended use, you could make a huge mess of your data. You should review the PHP source before using. This module is not maintained, so <strong>you are on your own</strong>.');
43 case 'admin/node/types/table_despliter':
44 return t('This process attempts to preserve the data from the old and new table, but if you made more than one new content type with the same field, this script will probably make a big mess. The new content types and their permissions will remain, but the fields will change when attempting the preserve option.');
45 }
46 } // */
47
48 /**
49 * hook_menu()
50 *
51 * @return array
52 */
53 function cck_table_despliter_menu($may_cache) {
54 $items = array();
55 $access = user_access('administer content types');
56
57 if ($may_cache) {
58 $items[] = array(
59 'path' => 'admin/node/types/table_despliter',
60 'title' => t('table despliter'),
61 'callback' => 'cck_table_despliter_edit',
62 'access' => $access,
63 'type' => MENU_LOCAL_TASK,
64 );
65 }
66
67 return $items;
68 } // */
69
70 function cck_table_despliter_edit() {
71 $form = array();
72 $node_types = array();
73 $field_names = array();
74
75 $result = db_query('SELECT DISTINCT(n.type_name) FROM {node_field_instance} n ORDER BY n.type_name');
76 while ($type = db_fetch_object($result)) {
77 $node_types[$type->type_name] = $type->type_name;
78 }
79 unset($type, $result);
80
81 // field_name is the PK of node_field
82 $result = db_query('SELECT n.field_name FROM {node_field} n ORDER BY n.field_name');
83 while ($field = db_fetch_object($result)) {
84 $field_names[$field->field_name] = $field->field_name;
85 }
86 unset($field, $result);
87
88 $form['current_field_name'] = array(
89 '#title' => t('Current field name'),
90 '#type' => 'select',
91 '#options' => $field_names,
92 '#required' => true,
93 '#description' => t('This content type will get the field name added back to the original node_content_* table.')
94 );
95 $form['original_content_type'] = array(
96 '#title' => t('Original content type'),
97 '#type' => 'select',
98 '#options' => $node_types,
99 '#required' => true,
100 '#description' => t('Original content "owner" of the field you want to merge back from the node_data_field_* table it was split to.')
101 );
102 $form['new_content_type'] = array(
103 '#title' => t('New content type'),
104 '#type' => 'select',
105 '#options' => $node_types,
106 '#required' => false,
107 '#description' => t('This table will get the original field, but with a _# on the end, which is standard CCK notation for similarly named fields in different tables.')
108 );
109 $form['numerical_increment'] = array(
110 '#title' => t('Numerical increment'),
111 '#type' => 'textfield',
112 '#default_value' => 0,
113 '#required' => false,
114 '#size' => 1,
115 '#maxlength' => 1,
116 '#description' => t('If you know _0 is used already, change this to a higher number. This script is not smart enough (yet) to detect which number to use on its own.')
117 );
118 $form['use_new_content_type'] = array(
119 '#title' => t('Preserve new content type'),
120 '#type' => 'checkbox',
121 '#description' => t('Attempt to recreate the new field, but with the _# on the end, and its data. Leave unchecked to ignore new content type.')
122 );
123 $form['submit'] = array(
124 '#value' => t('Reverse field split'),
125 '#type' => 'submit',
126 '#submit' => true
127 );
128 return drupal_get_form('cck_table_despliter_edit', $form);
129 } // */
130
131 /**
132 * Moves the data from the node_data_field_* table
133 * back to the original table
134 *
135 * tables that have to update in some way:
136 * node_field: copy row based on field_name
137 * node_field_instance: update/rename the field_name for the newer content_type - MUST MATCH node_field entry
138 * node_group_fields: update/rename the field_name for the newer type_name
139 */
140 function cck_table_despliter_edit_submit($form_id, $form_values) {
141
142 // should pull Field, Type, Null, Key, Default, Extra
143 $result = db_query("SHOW COLUMNS FROM {node_data_{$form_values['current_field_name']}} WHERE field != 'vid' AND field != 'nid'");
144 $field = db_fetch_object($result);
145 unset($result);
146
147 // use $field->Field because it will have the added _value part to the field name
148 // that's needed when the field is in the content type's table
149 db_query("ALTER TABLE {node_{$form_values['original_content_type']}} ADD {$field->Field} {$field->Type} %s DEFAULT '%s'", $field->Null == 'NO' ? 'NOT NULL' : '', $field->Default);
150
151 if (!empty($form_values['use_new_content_type'])) {
152 $new_field = $field->Field;
153 $field_len = strlen($new_field);
154 // 100% BUGGY if true - doesn't insert the _# in the middle like it does if false
155 if ($field_len > 30) {
156 // replacement of the last 2 chars is different from the
157 // addition to which is possible if it's less than 31 chars
158 $new_field{$field_len-1} = $form_values['numerical_increment'];
159 $new_field{$field_len-2} = _;
160 }
161 else {
162 $new_field = substr($new_field, 0, strrpos($new_field, '_')) .'_' . $form_values['numerical_increment'] . substr($new_field, strrpos($new_field, '_'));
163 }
164 unset($field_len);
165 db_query("ALTER TABLE {node_{$form_values['new_content_type']}} ADD $new_field {$field->Type} %s DEFAULT '%s'", $field->Null == 'NO' ? 'NOT NULL' : '', $field->Default);
166 }
167
168 $result = db_query("SELECT n.vid, n.nid, n.{$field->Field} AS field FROM {node_data_{$form_values['current_field_name']}} n");
169 while ($field_value = db_fetch_object($result)) {
170 db_query("UPDATE {node_{$form_values['original_content_type']}} SET {$field->Field} = '%s' WHERE vid = %d AND nid = %d", $field_value->field, $field_value->vid, $field_value->nid);
171 if (!empty($form_values['use_new_content_type'])) {
172 db_query("UPDATE {node_{$form_values['new_content_type']}} SET $new_field = '%s' WHERE vid = %d AND nid = %d", $field_value->field, $field_value->vid, $field_value->nid);
173 }
174 }
175 unset($result);
176
177 // clean up the map of where fields are stored
178 if (!empty($form_values['use_new_content_type'])) {
179 db_query("UPDATE {node_field_instance} SET field_name = '%s' WHERE field_name = '%s' AND type_name = '%s'", "{$form_values['current_field_name']}_{$form_values['numerical_increment']}", $form_values['current_field_name'], $form_values['new_content_type']);
180
181 // tells CCK the field is in the content type's table (node_content_*), not a table of a field (node_data_field_*)
182 // it's set to 0 when the field is moved to a node_data_field_* table
183 db_query("UPDATE {node_field} SET db_storage = 1 WHERE field_name = '%s'", $form_values['current_field_name']);
184
185 $result = db_query("SELECT field_name, type, global_settings, required, multiple, db_storage FROM {node_field} WHERE field_name = '%s'", $form_values['current_field_name']);
186 // should return exactly one result, but just in case it doesn't
187 // the while statement will keep the query from throwing warnings
188 while ($field = db_fetch_object($result)) {
189 db_query("INSERT INTO {node_field} (field_name, type, global_settings, required, multiple, db_storage) VALUES ('%s', '%s', '%s', %d, %d, %d)", "{$field->field_name}_{$form_values['numerical_increment']}", $field->type, $field->global_settings, $field->required, $field->multiple, 1);
190 drupal_set_message(t('Inserted !new in the content type map', array('!new' => "{$field->field_name}_{$form_values['numerical_increment']}")), 'status');
191 }
192
193 // THIS QUERY COULD MAKE A MESS if you use it on a field_name that exists on more than one content type
194 db_query("UPDATE {node_group_fields} SET field_name = '%s_%d' WHERE field_name = '%s' AND type_name != '%s'", $form_values['current_field_name'], $form_values['numerical_increment'], $form_values['current_field_name'], $form_values['original_content_type']);
195 }
196 else {
197 db_query("DELETE FROM {node_field_instance} WHERE field_name = '%s' AND type_name != '%s'", $form_values['current_field_name'], $form_values['original_content_type']);
198 drupal_set_message(t('Deleted field instances where other content types shared the same field name.'), 'status');
199 }
200
201 db_query("DROP TABLE {node_data_{$form_values['current_field_name']}}");
202
203 } // */

  ViewVC Help
Powered by ViewVC 1.1.2