1 | <?php |
---|
2 | // $Id: content.install,v 1.85.2.33 2009/07/14 22:17:05 yched Exp $ |
---|
3 | |
---|
4 | function content_requirements($phase) { |
---|
5 | $requirements = array(); |
---|
6 | // Ensure translations don't break at install time |
---|
7 | $t = get_t(); |
---|
8 | if (module_exists('views') && (!function_exists('views_api_version') || views_api_version() < 2.0)) { |
---|
9 | $requirements['cck_views'] = array( |
---|
10 | 'title' => $t('CCK - No Views integration'), |
---|
11 | 'description' => $t("CCK integration with Views module requires Views 6.x-2.0-rc2 or greater."), |
---|
12 | 'severity' => REQUIREMENT_ERROR, |
---|
13 | ); |
---|
14 | } |
---|
15 | return $requirements; |
---|
16 | } |
---|
17 | |
---|
18 | /** |
---|
19 | * 'Safe' version of content_types() to use in updates and installs. |
---|
20 | * |
---|
21 | * Can't safely use content_fields() or content_types() in an update to get |
---|
22 | * a fields array, especially without knowing what field modules are enabled, |
---|
23 | * or the current state of the database and cache, so create a fields array |
---|
24 | * from database info that is limited to fields from modules that are |
---|
25 | * currently enabled. |
---|
26 | */ |
---|
27 | function content_types_install() { |
---|
28 | drupal_load('module', 'content'); |
---|
29 | module_load_include('inc', 'content', '/includes/content.crud'); |
---|
30 | $module_field_types = $module_widgets = array(); |
---|
31 | foreach (module_list() as $module) { |
---|
32 | if ($field_type = module_invoke($module, 'field_info')) { |
---|
33 | $module_field_types[$module] = $field_type; |
---|
34 | } |
---|
35 | if ($widget_type = module_invoke($module, 'widget_info')) { |
---|
36 | $module_widgets[$module] = $widget_type; |
---|
37 | } |
---|
38 | } |
---|
39 | $fields = array(); |
---|
40 | $db_result = db_query("SELECT * FROM {". content_instance_tablename() ."} nfi ". |
---|
41 | " LEFT JOIN {". content_field_tablename() ."} nf ON nf.field_name = nfi.field_name"); |
---|
42 | while ($row = db_fetch_array($db_result)) { |
---|
43 | $field = array_merge($row, unserialize($row['global_settings'])); |
---|
44 | unset($field['global_settings']); |
---|
45 | |
---|
46 | // There may be module data available for currently disabled modules, |
---|
47 | // or missing module data for currently enabled modules, so start over |
---|
48 | // to get only field info for enabled modules. |
---|
49 | unset($field['module']); |
---|
50 | unset($field['widget_module']); |
---|
51 | // 'columns' is a reserved word in MySQL4, so our column is named 'db_columns'. |
---|
52 | $field['columns'] = isset($field['db_columns']) ? $field['db_columns'] : array(); |
---|
53 | unset($field['db_columns']); |
---|
54 | |
---|
55 | foreach ($module_field_types as $module => $types) { |
---|
56 | foreach ($types as $type_name => $type) { |
---|
57 | if ($field['type'] == $type_name) { |
---|
58 | $field['module'] = $module; |
---|
59 | } |
---|
60 | } |
---|
61 | } |
---|
62 | foreach ($module_widgets as $module => $types) { |
---|
63 | foreach ($types as $type_name => $type) { |
---|
64 | if ($field['widget_type'] == $type_name) { |
---|
65 | $field['widget_module'] = $module; |
---|
66 | } |
---|
67 | } |
---|
68 | } |
---|
69 | if (!empty($field['module']) && !empty($field['widget_module'])) { |
---|
70 | $field['widget_settings'] = unserialize($field['widget_settings']); |
---|
71 | $field['display_settings'] = unserialize($field['display_settings']); |
---|
72 | $field['columns'] = (array) module_invoke($field['module'], 'field_settings', 'database columns', $field); |
---|
73 | $field = content_field_instance_expand($field); |
---|
74 | $fields[$field['type_name']][$field['field_name']] = $field; |
---|
75 | } |
---|
76 | } |
---|
77 | return $fields; |
---|
78 | } |
---|
79 | |
---|
80 | /** |
---|
81 | * Implementation of hook_install(). |
---|
82 | */ |
---|
83 | function content_install() { |
---|
84 | variable_set('content_schema_version', 6009); |
---|
85 | drupal_install_schema('content'); |
---|
86 | } |
---|
87 | |
---|
88 | |
---|
89 | /** |
---|
90 | * Implementation of hook_uninstall(). |
---|
91 | */ |
---|
92 | function content_uninstall() { |
---|
93 | drupal_uninstall_schema('content'); |
---|
94 | // The variable is used during the uninstall process, |
---|
95 | // so we removed it at the very end. |
---|
96 | variable_del('content_schema_version'); |
---|
97 | // Remove extra weights. |
---|
98 | foreach (node_get_types('names') as $type_name) { |
---|
99 | variable_del("content_extra_weights_$type_name"); |
---|
100 | } |
---|
101 | } |
---|
102 | |
---|
103 | /** |
---|
104 | * Implementation of hook_enable(). |
---|
105 | */ |
---|
106 | function content_enable() { |
---|
107 | // Make sure old data is emptied out of the caches, since it |
---|
108 | // may no longer be valid since the module was last enabled, |
---|
109 | // especially if not all the same field modules are enabled |
---|
110 | // as before. Especially needed during updates. |
---|
111 | cache_clear_all('*', 'cache_content', TRUE); |
---|
112 | content_clear_type_cache(TRUE); |
---|
113 | } |
---|
114 | |
---|
115 | /** |
---|
116 | * Implementation of hook_disable(). |
---|
117 | */ |
---|
118 | function content_disable() { |
---|
119 | // Make sure old data is emptied out of the caches, since it |
---|
120 | // may no longer be valid when the module is re-enabled. |
---|
121 | cache_clear_all('*', 'cache_content', TRUE); |
---|
122 | content_clear_type_cache(TRUE); |
---|
123 | } |
---|
124 | |
---|
125 | /** |
---|
126 | * Implementation of hook_schema. |
---|
127 | */ |
---|
128 | function content_schema() { |
---|
129 | |
---|
130 | // Static (meta) tables. |
---|
131 | |
---|
132 | $schema['content_node_field'] = array( |
---|
133 | 'fields' => array( |
---|
134 | 'field_name' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''), |
---|
135 | 'type' => array('type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => ''), |
---|
136 | 'global_settings' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'serialize' => TRUE), |
---|
137 | 'required' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), |
---|
138 | 'multiple' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), |
---|
139 | 'db_storage' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 1), |
---|
140 | 'module' => array('type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => ''), |
---|
141 | 'db_columns' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'serialize' => TRUE), |
---|
142 | 'active' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), |
---|
143 | 'locked' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), |
---|
144 | ), |
---|
145 | 'primary key' => array('field_name'), |
---|
146 | ); |
---|
147 | $schema['content_node_field_instance'] = array( |
---|
148 | 'fields' => array( |
---|
149 | 'field_name' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''), |
---|
150 | 'type_name' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''), |
---|
151 | 'weight' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), |
---|
152 | 'label' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), |
---|
153 | 'widget_type' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''), |
---|
154 | 'widget_settings' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'serialize' => TRUE), |
---|
155 | 'display_settings' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'serialize' => TRUE), |
---|
156 | 'description' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE), |
---|
157 | 'widget_module' => array('type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => ''), |
---|
158 | 'widget_active' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), |
---|
159 | ), |
---|
160 | 'primary key' => array('field_name', 'type_name'), |
---|
161 | ); |
---|
162 | $schema['cache_content'] = drupal_get_schema_unprocessed('system', 'cache'); |
---|
163 | |
---|
164 | // When the module is first installed, the remaining code in the schema |
---|
165 | // will create errors, since these tables have not yet been created. |
---|
166 | // We don't need to create data tables on initial installation anyway |
---|
167 | // since no fields have been created yet, so just return with this much |
---|
168 | // of the schema. |
---|
169 | |
---|
170 | if (!db_table_exists('content_node_field') || !db_table_exists('content_node_field_instance')) { |
---|
171 | return $schema; |
---|
172 | } |
---|
173 | |
---|
174 | // Dynamic (data) tables. |
---|
175 | |
---|
176 | drupal_load('module', 'content'); |
---|
177 | |
---|
178 | // We can't use many helper functions here, like content_fields() or |
---|
179 | // content_types() or we risk creating a fatal loop from circular |
---|
180 | // logic when they call other functions that use this schema, so create |
---|
181 | // the schema directly from a fresh query of the database. |
---|
182 | |
---|
183 | // content_table_schema() and content_database_info() have no |
---|
184 | // circular logic and are safe to use here. |
---|
185 | |
---|
186 | $db_result = db_query("SELECT * FROM {". content_instance_tablename() ."} nfi ". |
---|
187 | " LEFT JOIN {". content_field_tablename() ."} nf ON nf.field_name = nfi.field_name WHERE nf.active = 1 AND nfi.widget_active = 1"); |
---|
188 | while ($field = db_fetch_array($db_result)) { |
---|
189 | // 'columns' is a reserved word in MySQL4, so our db column is named 'db_columns'. |
---|
190 | $field['columns'] = unserialize($field['db_columns']); |
---|
191 | unset($field['db_columns']); |
---|
192 | |
---|
193 | $content_table = _content_tablename($field['type_name'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE); |
---|
194 | $field_table = _content_tablename($field['field_name'], CONTENT_DB_STORAGE_PER_FIELD); |
---|
195 | |
---|
196 | |
---|
197 | // We always add a 'per content type' table for each content type that |
---|
198 | // has fields. |
---|
199 | if (!isset($schema[$content_table])) { |
---|
200 | $schema[$content_table] = content_table_schema(); |
---|
201 | } |
---|
202 | |
---|
203 | $base_schema = content_table_schema($field); |
---|
204 | if ($field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) { |
---|
205 | // Per-field storage: add the 'per field' table if needed. |
---|
206 | if (!isset($schema[$field_table])) { |
---|
207 | $schema[$field_table] = $base_schema; |
---|
208 | } |
---|
209 | } |
---|
210 | else { |
---|
211 | // Per-type storage: merge the information for the field |
---|
212 | // in the existing table. |
---|
213 | $schema[$content_table]['fields'] = array_merge($schema[$content_table]['fields'], $base_schema['fields']); |
---|
214 | $schema[$content_table]['content fields'] = array_merge($schema[$content_table]['content fields'], $base_schema['content fields']); |
---|
215 | } |
---|
216 | } |
---|
217 | return $schema; |
---|
218 | } |
---|
219 | |
---|
220 | function content_update_last_removed() { |
---|
221 | return 1008; |
---|
222 | } |
---|
223 | |
---|
224 | /** |
---|
225 | * Helper function for module updates : |
---|
226 | * - checks no updates are pending for content.module |
---|
227 | * - checks content module and the module being updated are both enabled. |
---|
228 | * |
---|
229 | * @param $module |
---|
230 | * The name of the module being updated. |
---|
231 | */ |
---|
232 | function content_check_update($module = NULL) { |
---|
233 | $ret = array(); |
---|
234 | // Check that modules are enabled before running their updates. |
---|
235 | if (!module_exists('content') || ($module && !module_exists($module))) { |
---|
236 | drupal_set_message(t("Updates for CCK-related modules are not run until the modules are enabled on the <a href=\"@admin-modules-path\">administer modules page</a>. When you enable them, you'll need to return to <a href=\"@update-php\">update.php</a> and run the remaining updates.", array('@admin-modules-path' => url('admin/build/modules'), '@update-php' => base_path() .'update.php?op=selection')), 'warning', FALSE); |
---|
237 | // The content module is not enabled, nothing else can happen. |
---|
238 | if ($module && !module_exists('content') && module_exists($module)) { |
---|
239 | $query_message = t('!module.module has updates but cannot be updated because content.module is not enabled.<br />If and when content.module is enabled, you will need to re-run the update script. You will continue to see this message until the module is enabled and updates are run.', array('!module' => $module)); |
---|
240 | } |
---|
241 | // The requested module is not enabled, which may be intentional. |
---|
242 | // Just let the user know there are updates to be processed if enabled later. |
---|
243 | else { |
---|
244 | $query_message = t('!module.module has updates and is available in the modules folder but is not enabled.<br />If and when it is enabled, you will need to re-run the update script. You will continue to see this message until the module is enabled and updates are run.', array('!module' => $module ? $module : 'content')); |
---|
245 | } |
---|
246 | $ret['#abort'] = array('success' => FALSE, 'query' => $query_message); |
---|
247 | return $ret; |
---|
248 | } |
---|
249 | // Check that content.module is up-to-date before running field module updates. |
---|
250 | if ($module && (drupal_get_installed_schema_version('content', TRUE) < max(drupal_get_schema_versions('content')))) { |
---|
251 | drupal_set_message(t('Some updates are still pending. Please return to <a href="@update-php">update.php</a> and run the remaining updates.', array('@update-php' => base_path() .'update.php?op=selection')), 'warning', FALSE); |
---|
252 | $ret['#abort'] = array('success' => FALSE, 'query' => t('Some updates are still pending.<br/>Please re-run the update script.')); |
---|
253 | return $ret; |
---|
254 | } |
---|
255 | // If everything is OK and updates are not aborted, make sure |
---|
256 | // content_associate_fields() gets run. With all the complexity of |
---|
257 | // the dependent updates, it can get missed when an update is aborted. |
---|
258 | // It won't hurt anything to do this more than once in order to be sure |
---|
259 | // it doesn't get skipped. Without this step, we can end up with |
---|
260 | // field modules that are enabled and updated, but not marked as active |
---|
261 | // in the content_node_field table. |
---|
262 | if ($module and module_exists($module)) { |
---|
263 | content_associate_fields($module); |
---|
264 | } |
---|
265 | } |
---|
266 | |
---|
267 | /** |
---|
268 | * Add module name to fields table to make it easier to identify the fields to delete when a module |
---|
269 | * is uninstalled. |
---|
270 | * |
---|
271 | * Needed because the value drops out of content_info() when module is disabled, so there |
---|
272 | * is no other way to find the associated fields. |
---|
273 | */ |
---|
274 | function content_update_6000() { |
---|
275 | if ($abort = content_check_update()) { |
---|
276 | return $abort; |
---|
277 | } |
---|
278 | |
---|
279 | $ret = array(); |
---|
280 | |
---|
281 | drupal_load('module', 'content'); |
---|
282 | if (db_column_exists(content_field_tablename(), 'active')) { |
---|
283 | return $ret; |
---|
284 | } |
---|
285 | db_add_field($ret, content_field_tablename(), 'module', array('type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => '')); |
---|
286 | db_add_field($ret, content_field_tablename(), 'db_columns', array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'initial' => '')); |
---|
287 | db_add_field($ret, content_field_tablename(), 'active', array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0)); |
---|
288 | db_add_field($ret, content_instance_tablename(), 'widget_module', array('type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => '')); |
---|
289 | db_add_field($ret, content_instance_tablename(), 'widget_active', array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0)); |
---|
290 | |
---|
291 | // This will update the table for any modules enabled at this time. |
---|
292 | foreach (module_list() as $module) { |
---|
293 | content_associate_fields($module); |
---|
294 | } |
---|
295 | |
---|
296 | // Fix the cache_content schema |
---|
297 | if (db_table_exists('cache_content')) { |
---|
298 | db_drop_table($ret, 'cache_content'); |
---|
299 | } |
---|
300 | db_create_table($ret, 'cache_content', drupal_get_schema_unprocessed('system', 'cache')); |
---|
301 | variable_set('content_schema_version', 6000); |
---|
302 | |
---|
303 | // The cache table had to be used to store data until this update ran, |
---|
304 | // so clear cache out now that we're switching back to the cache_content table. |
---|
305 | $ret[] = update_sql('DELETE FROM {cache}'); |
---|
306 | |
---|
307 | return $ret; |
---|
308 | } |
---|
309 | |
---|
310 | /** |
---|
311 | * Rename node_field and node_field_instance tables. |
---|
312 | * |
---|
313 | * This is a carryover from when the data tables were renamed, |
---|
314 | * postponed so we wouldn't create any more havoc than necessary |
---|
315 | * until a major version change. |
---|
316 | * |
---|
317 | * Using 'content_node_field' instead of 'content_field' |
---|
318 | * to avoid conflicts with field tables that will be prefixed |
---|
319 | * with 'content_field'. |
---|
320 | */ |
---|
321 | function content_update_6001() { |
---|
322 | if ($abort = content_check_update()) { |
---|
323 | return $abort; |
---|
324 | } |
---|
325 | |
---|
326 | $ret = array(); |
---|
327 | drupal_load('module', 'content'); |
---|
328 | if (db_table_exists('content_node_field')) { |
---|
329 | return $ret; |
---|
330 | } |
---|
331 | db_rename_table($ret, 'node_field', 'content_node_field'); |
---|
332 | db_rename_table($ret, 'node_field_instance', 'content_node_field_instance'); |
---|
333 | variable_set('content_schema_version', 6001); |
---|
334 | content_clear_type_cache(TRUE); |
---|
335 | return $ret; |
---|
336 | } |
---|
337 | |
---|
338 | /** |
---|
339 | * Get rid of automatic per content tables for content types that have no fields. |
---|
340 | * Switching to adding those tables only when needed. |
---|
341 | */ |
---|
342 | function content_update_6002() { |
---|
343 | if ($abort = content_check_update()) { |
---|
344 | return $abort; |
---|
345 | } |
---|
346 | |
---|
347 | $ret = array(); |
---|
348 | |
---|
349 | drupal_load('module', 'content'); |
---|
350 | $db_types = content_types_install(); |
---|
351 | $field_types = array(); |
---|
352 | |
---|
353 | $result = db_query("SELECT DISTINCT type_name FROM {". content_instance_tablename() ."}"); |
---|
354 | while ($type = db_fetch_array($result)) { |
---|
355 | $field_types[] = $type['type_name']; |
---|
356 | } |
---|
357 | |
---|
358 | foreach ($db_types as $content_type => $content_info) { |
---|
359 | if (!in_array($content_type, $field_types)) { |
---|
360 | $table = _content_tablename($content_type, CONTENT_DB_STORAGE_PER_CONTENT_TYPE); |
---|
361 | if (db_table_exists($table)) { |
---|
362 | db_drop_table($ret, $table); |
---|
363 | } |
---|
364 | } |
---|
365 | } |
---|
366 | variable_set('content_schema_version', 6002); |
---|
367 | content_clear_type_cache(TRUE); |
---|
368 | return $ret; |
---|
369 | } |
---|
370 | |
---|
371 | /** |
---|
372 | * 'db_columns' column 1st got introduced as 'columns', which is forbidden in MySQL 4. |
---|
373 | * This update function will only be useful for early D6 testers... |
---|
374 | */ |
---|
375 | function content_update_6003() { |
---|
376 | if ($abort = content_check_update()) { |
---|
377 | return $abort; |
---|
378 | } |
---|
379 | |
---|
380 | $ret = array(); |
---|
381 | if (db_column_exists('content_node_field', 'columns')) { |
---|
382 | db_change_field($ret, 'content_node_field', 'columns', 'db_columns', array('type' => 'text', 'size' => 'medium', 'not null' => TRUE)); |
---|
383 | } |
---|
384 | variable_set('content_schema_version', 6003); |
---|
385 | return $ret; |
---|
386 | } |
---|
387 | |
---|
388 | /** |
---|
389 | * Index the 'nid' column on data tables to optimize node deletion. |
---|
390 | * Large tables might deserve a multipass update. |
---|
391 | */ |
---|
392 | function content_update_6004(&$sandbox) { |
---|
393 | if ($abort = content_check_update()) { |
---|
394 | return $abort; |
---|
395 | } |
---|
396 | |
---|
397 | $ret = array(); |
---|
398 | |
---|
399 | // Do nothing if the indexes were already created by D5's content_update_1009. |
---|
400 | if (variable_get('content_update_1009', FALSE)) { |
---|
401 | return $ret; |
---|
402 | } |
---|
403 | |
---|
404 | // Gather list of tables. |
---|
405 | if (!isset($sandbox['tables'])) { |
---|
406 | drupal_load('module', 'content'); |
---|
407 | $sandbox['tables'] = array(); |
---|
408 | $result = db_query('SELECT * FROM {'. content_instance_tablename() .'} nfi '. |
---|
409 | ' LEFT JOIN {'. content_field_tablename() .'} nf ON nf.field_name = nfi.field_name'); |
---|
410 | while ($field = db_fetch_array($result)) { |
---|
411 | if ($field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) { |
---|
412 | $table = _content_tablename($field['field_name'], CONTENT_DB_STORAGE_PER_FIELD); |
---|
413 | } |
---|
414 | else { |
---|
415 | $table = _content_tablename($field['type_name'], CONTENT_DB_STORAGE_PER_CONTENT_TYPE); |
---|
416 | } |
---|
417 | $sandbox['tables'][$table] = $table; |
---|
418 | } |
---|
419 | $sandbox['count'] = count($sandbox['tables']); |
---|
420 | } |
---|
421 | |
---|
422 | // One pass : add index on one table. |
---|
423 | if ($table = array_shift($sandbox['tables'])) { |
---|
424 | db_add_index($ret, $table, 'nid', array('nid')); |
---|
425 | } |
---|
426 | |
---|
427 | if ($sandbox['count']) { |
---|
428 | $ret['#finished'] = 1 - count($sandbox['tables']) / $sandbox['count']; |
---|
429 | } |
---|
430 | variable_set('content_schema_version', 6004); |
---|
431 | return $ret; |
---|
432 | } |
---|
433 | |
---|
434 | /** |
---|
435 | * Add 'locked' property for fields. |
---|
436 | */ |
---|
437 | function content_update_6005() { |
---|
438 | if ($abort = content_check_update()) { |
---|
439 | return $abort; |
---|
440 | } |
---|
441 | |
---|
442 | $ret = array(); |
---|
443 | drupal_load('module', 'content'); |
---|
444 | db_add_field($ret, content_field_tablename(), 'locked', array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0)); |
---|
445 | variable_set('content_schema_version', 6005); |
---|
446 | return $ret; |
---|
447 | } |
---|
448 | |
---|
449 | /** |
---|
450 | * Make sure the 'locked' column is NOT NULL (error in previous content_update_6005(). |
---|
451 | */ |
---|
452 | function content_update_6006() { |
---|
453 | if ($abort = content_check_update()) { |
---|
454 | return $abort; |
---|
455 | } |
---|
456 | |
---|
457 | $ret = array(); |
---|
458 | drupal_load('module', 'content'); |
---|
459 | db_change_field($ret, content_field_tablename(), 'locked', 'locked', array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0)); |
---|
460 | variable_set('content_schema_version', 6006); |
---|
461 | return $ret; |
---|
462 | } |
---|
463 | |
---|
464 | /** |
---|
465 | * Dummy update function to make sure the theme registry and css / JS aggregated files |
---|
466 | * are updated. |
---|
467 | */ |
---|
468 | function content_update_6007() { |
---|
469 | if ($abort = content_check_update()) { |
---|
470 | return $abort; |
---|
471 | } |
---|
472 | |
---|
473 | variable_set('content_schema_version', 6007); |
---|
474 | return array(); |
---|
475 | } |
---|
476 | |
---|
477 | /** |
---|
478 | * Dummy update function to make sure schema version gets updated. |
---|
479 | */ |
---|
480 | function content_update_6008() { |
---|
481 | if ($abort = content_check_update()) { |
---|
482 | return $abort; |
---|
483 | } |
---|
484 | |
---|
485 | variable_set('content_schema_version', 6008); |
---|
486 | return array(); |
---|
487 | } |
---|
488 | |
---|
489 | /** |
---|
490 | * Add the 'exclude from $content' display setting to all existing field instances. |
---|
491 | */ |
---|
492 | function content_update_6009() { |
---|
493 | if ($abort = content_check_update()) { |
---|
494 | return $abort; |
---|
495 | } |
---|
496 | |
---|
497 | $ret = array(); |
---|
498 | $result = db_query("SELECT * FROM {content_node_field_instance}"); |
---|
499 | while ($type = db_fetch_array($result)) { |
---|
500 | $new_settings = array(); |
---|
501 | $display_settings = unserialize($type['display_settings']); |
---|
502 | if (!empty($display_settings)) { |
---|
503 | foreach ($display_settings as $key => $val) { |
---|
504 | $new_settings[$key] = $val; |
---|
505 | if ($key !== 'label' && is_array($val)) { |
---|
506 | $new_settings[$key]['exclude'] = 0; |
---|
507 | } |
---|
508 | } |
---|
509 | } |
---|
510 | else { |
---|
511 | $new_settings = array( |
---|
512 | 'label' => array('format' => 'above'), |
---|
513 | 'full' => array('format' => 'default', 'exclude' => 0), |
---|
514 | 'teaser' => array('format' => 'default', 'exclude' => 0), |
---|
515 | ); |
---|
516 | } |
---|
517 | db_query("UPDATE {content_node_field_instance} SET display_settings='%s' WHERE field_name='%s' AND type_name='%s'", serialize($new_settings), $type['field_name'], $type['type_name']); |
---|
518 | } |
---|
519 | variable_set('content_schema_version', 6009); |
---|
520 | return $ret; |
---|
521 | } |
---|
522 | |
---|
523 | /** |
---|
524 | * Fix multiple serialization caused by per-field to per-type migration. |
---|
525 | * See http://drupal.org/node/407446. |
---|
526 | */ |
---|
527 | function content_update_6010(&$sandbox) { |
---|
528 | if ($abort = content_check_update()) { |
---|
529 | return $abort; |
---|
530 | } |
---|
531 | $ret = array(); |
---|
532 | |
---|
533 | drupal_load('module', 'content'); |
---|
534 | |
---|
535 | // Gather list of tables and columns that need to be updated. |
---|
536 | if (!isset($sandbox['tables'])) { |
---|
537 | $sandbox['tables'] = array(); |
---|
538 | $fields = content_fields(); |
---|
539 | foreach ($fields as $name => $field) { |
---|
540 | $db_info = content_database_info($field); |
---|
541 | foreach ($db_info['columns'] as $column => $attributes) { |
---|
542 | if (isset($attributes['serialize']) && $attributes['serialize']) { |
---|
543 | $sandbox['tables'][$db_info['table']]['table'] = $db_info['table']; |
---|
544 | $sandbox['tables'][$db_info['table']]['columns'][] = $attributes['column']; |
---|
545 | $sandbox['tables'][$db_info['table']]['multiple'] = $field['multiple']; |
---|
546 | } |
---|
547 | } |
---|
548 | } |
---|
549 | $sandbox['count'] = count($sandbox['tables']); |
---|
550 | $sandbox['current_vid'] = 0; |
---|
551 | $sandbox['current_delta'] = 0; |
---|
552 | } |
---|
553 | |
---|
554 | // Number of rows to fix in one pass. |
---|
555 | $limit = 500; |
---|
556 | // Start correcting data. |
---|
557 | if ($table_info = array_shift($sandbox['tables'])) { |
---|
558 | $table = $table_info['table']; |
---|
559 | $columns = $table_info['columns']; |
---|
560 | |
---|
561 | if ($table_info['multiple']) { |
---|
562 | $query = "SELECT * FROM {" . $table . "} WHERE (vid = %d AND delta > %d) OR (vid > %d) ORDER BY vid ASC, delta ASC"; |
---|
563 | $args = array($sandbox['current_vid'], $sandbox['current_delta'], $sandbox['current_vid']); |
---|
564 | } |
---|
565 | else { |
---|
566 | $query = "SELECT * FROM {" . $table . "} WHERE vid > %d ORDER BY vid ASC"; |
---|
567 | $args = array($sandbox['current_vid']); |
---|
568 | } |
---|
569 | $result = db_query_range($query, $args, 0, $limit); |
---|
570 | $count = 0; |
---|
571 | while ($row = db_fetch_array($result)) { |
---|
572 | $update_query = $update_args = array(); |
---|
573 | foreach ($columns as $column) { |
---|
574 | $data = $row[$column]; |
---|
575 | // No need to do anything if the data is NULL. |
---|
576 | if (!empty($data)) { |
---|
577 | // Unserialize until we get something that is not a string |
---|
578 | while (is_string($data)) { |
---|
579 | $unserialized = @unserialize($data); |
---|
580 | if ($unserialized !== FALSE) { |
---|
581 | $data = $unserialized; |
---|
582 | } |
---|
583 | else { |
---|
584 | // TODO : test with a serialized string, just in case... |
---|
585 | break; |
---|
586 | } |
---|
587 | } |
---|
588 | // Re-serialize once. |
---|
589 | $data = serialize($data); |
---|
590 | // If we end up with something different than what we started with, update. |
---|
591 | if ($data !== $row[$column]) { |
---|
592 | $update_query[] = "$column = '%s'"; |
---|
593 | $update_args[] = $data; |
---|
594 | } |
---|
595 | } |
---|
596 | } |
---|
597 | if ($update_query) { |
---|
598 | $update_args[] = $row['vid']; |
---|
599 | db_query("UPDATE {" . $table . "} SET ". implode(', ', $update_query) ." WHERE vid = %d", $update_args); |
---|
600 | } |
---|
601 | $sandbox['current_vid'] = $row['vid']; |
---|
602 | $sandbox['current_delta'] = isset($row['delta']) ? $row['delta'] : 0; |
---|
603 | $count++; |
---|
604 | } |
---|
605 | if ($count == $limit) { |
---|
606 | // Add the table back into the list of tables to be processed if rows remain. |
---|
607 | array_unshift($sandbox['tables'], $table_info); |
---|
608 | } |
---|
609 | else { |
---|
610 | // Done with this table: reset vid and delta markers. |
---|
611 | $sandbox['current_vid'] = 0; |
---|
612 | $sandbox['current_delta'] = 0; |
---|
613 | $ret[] = array('success' => TRUE, 'query' => "Fixed serialized values in table $table"); |
---|
614 | } |
---|
615 | } |
---|
616 | |
---|
617 | if ($sandbox['count']) { |
---|
618 | $ret['#finished'] = 1 - count($sandbox['tables']) / $sandbox['count']; |
---|
619 | } |
---|
620 | return $ret; |
---|
621 | } |
---|