| Commit | Line | Data |
|---|---|---|
| 1e3636cf YC |
1 | <?php |
| 2 | // $Id$ | |
| af299c99 | 3 | |
| d48f2c6d YC |
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'), | |
| cc179e42 | 11 | 'description' => $t("CCK integration with Views module requires Views 6.x-2.0-rc2 or greater."), |
| 7633f5a9 | 12 | 'severity' => REQUIREMENT_ERROR, |
| d48f2c6d YC |
13 | ); |
| 14 | } | |
| 15 | return $requirements; | |
| 16 | } | |
| 17 | ||
| 2cd2740e | 18 | /** |
| cf81474b KS |
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 | */ | |
| 4f059953 | 27 | function content_types_install() { |
| 35c21ac8 YC |
28 | drupal_load('module', 'content'); |
| 29 | module_load_include('inc', 'content', '/includes/content.crud'); | |
| 3052e4fd | 30 | $module_field_types = $module_widgets = array(); |
| cf81474b KS |
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 ". | |
| b1a4d486 | 41 | " LEFT JOIN {". content_field_tablename() ."} nf ON nf.field_name = nfi.field_name"); |
| 8338e868 KS |
42 | while ($row = db_fetch_array($db_result)) { |
| 43 | $field = array_merge($row, unserialize($row['global_settings'])); | |
| 44 | unset($field['global_settings']); | |
| f0dbc087 | 45 | |
| b1a4d486 KS |
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']); | |
| 3ada1e96 | 51 | // 'columns' is a reserved word in MySQL4, so our column is named 'db_columns'. |
| fa518e8b | 52 | $field['columns'] = isset($field['db_columns']) ? $field['db_columns'] : array(); |
| 3ada1e96 YC |
53 | unset($field['db_columns']); |
| 54 | ||
| b1a4d486 KS |
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'])) { | |
| cf81474b KS |
70 | $field['widget_settings'] = unserialize($field['widget_settings']); |
| 71 | $field['display_settings'] = unserialize($field['display_settings']); | |
| da76b44c | 72 | $field['columns'] = (array) module_invoke($field['module'], 'field_settings', 'database columns', $field); |
| 8338e868 | 73 | $field = content_field_instance_expand($field); |
| cf81474b KS |
74 | $fields[$field['type_name']][$field['field_name']] = $field; |
| 75 | } | |
| 76 | } | |
| 77 | return $fields; | |
| 78 | } | |
| 79 | ||
| 80 | /** | |
| 2cd2740e JC |
81 | * Implementation of hook_install(). |
| 82 | */ | |
| af299c99 | 83 | function content_install() { |
| 37916f9a | 84 | variable_set('content_schema_version', 6009); |
| b01b0973 KS |
85 | drupal_install_schema('content'); |
| 86 | } | |
| 87 | ||
| 88 | ||
| 89 | /** | |
| 90 | * Implementation of hook_uninstall(). | |
| 91 | */ | |
| 92 | function content_uninstall() { | |
| b01b0973 | 93 | drupal_uninstall_schema('content'); |
| 0a6fdfb7 YC |
94 | // The variable is used during the uninstall process, |
| 95 | // so we removed it at the very end. | |
| 96 | variable_del('content_schema_version'); | |
| 78ad64a6 YC |
97 | // Remove extra weights. |
| 98 | foreach (node_get_types('names') as $type_name) { | |
| 99 | variable_del("content_extra_weights_$type_name"); | |
| 100 | } | |
| af299c99 JC |
101 | } |
| 102 | ||
| 38181f13 | 103 | /** |
| 6ddb7830 | 104 | * Implementation of hook_enable(). |
| b4ad53bb KS |
105 | */ |
| 106 | function content_enable() { | |
| cf81474b KS |
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); | |
| b4ad53bb KS |
113 | } |
| 114 | ||
| 115 | /** | |
| 116 | * Implementation of hook_disable(). | |
| 117 | */ | |
| 118 | function content_disable() { | |
| cf81474b KS |
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); | |
| b4ad53bb KS |
123 | } |
| 124 | ||
| 125 | /** | |
| f4ecb6d2 KS |
126 | * Implementation of hook_schema. |
| 127 | */ | |
| 128 | function content_schema() { | |
| 129 | ||
| 130 | // Static (meta) tables. | |
| 131 | ||
| 6ddb7830 | 132 | $schema['content_node_field'] = array( |
| f4ecb6d2 KS |
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' => ''), | |
| bde457f2 | 136 | 'global_settings' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'serialize' => TRUE), |
| f4ecb6d2 KS |
137 | 'required' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), |
| 138 | 'multiple' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), | |
| b4ad53bb | 139 | 'db_storage' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 1), |
| 096ce45e | 140 | 'module' => array('type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => ''), |
| 3ada1e96 | 141 | 'db_columns' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'serialize' => TRUE), |
| a207fcc6 | 142 | 'active' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), |
| 80a19c40 | 143 | 'locked' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), |
| f4ecb6d2 KS |
144 | ), |
| 145 | 'primary key' => array('field_name'), | |
| 146 | ); | |
| 6ddb7830 | 147 | $schema['content_node_field_instance'] = array( |
| f4ecb6d2 KS |
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' => ''), | |
| bde457f2 YC |
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), | |
| 00720402 | 156 | 'description' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE), |
| b4ad53bb | 157 | 'widget_module' => array('type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => ''), |
| a207fcc6 | 158 | 'widget_active' => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0), |
| f4ecb6d2 KS |
159 | ), |
| 160 | 'primary key' => array('field_name', 'type_name'), | |
| 161 | ); | |
| 162 | $schema['cache_content'] = drupal_get_schema_unprocessed('system', 'cache'); | |
| 163 | ||
| f89ff6c4 KS |
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. | |
| ddf5dfca | 166 | // We don't need to create data tables on initial installation anyway |
| f89ff6c4 KS |
167 | // since no fields have been created yet, so just return with this much |
| 168 | // of the schema. | |
| 169 | ||
| 401bf766 | 170 | if (!db_table_exists('content_node_field') || !db_table_exists('content_node_field_instance')) { |
| f89ff6c4 KS |
171 | return $schema; |
| 172 | } | |
| 173 | ||
| ddf5dfca | 174 | // Dynamic (data) tables. |
| ddf5dfca | 175 | |
| 6a05942a YC |
176 | drupal_load('module', 'content'); |
| 177 | ||
| ddf5dfca | 178 | // We can't use many helper functions here, like content_fields() or |
| b4ad53bb KS |
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. | |
| f4ecb6d2 | 182 | |
| 401bf766 | 183 | // content_table_schema() and content_database_info() have no |
| b4ad53bb | 184 | // circular logic and are safe to use here. |
| f4ecb6d2 | 185 | |
| 6e0b21c2 | 186 | $db_result = db_query("SELECT * FROM {". content_instance_tablename() ."} nfi ". |
| a207fcc6 | 187 | " LEFT JOIN {". content_field_tablename() ."} nf ON nf.field_name = nfi.field_name WHERE nf.active = 1 AND nfi.widget_active = 1"); |
| b4ad53bb | 188 | while ($field = db_fetch_array($db_result)) { |
| 3ada1e96 YC |
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 | ||
| b4ad53bb KS |
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); | |
| f4ecb6d2 | 195 | |
| cf7fe907 YC |
196 | |
| 197 | // We always add a 'per content type' table for each content type that | |
| 198 | // has fields. | |
| 401bf766 KS |
199 | if (!isset($schema[$content_table])) { |
| 200 | $schema[$content_table] = content_table_schema(); | |
| 201 | } | |
| 202 | ||
| cf7fe907 YC |
203 | $base_schema = content_table_schema($field); |
| 204 | if ($field['db_storage'] == CONTENT_DB_STORAGE_PER_FIELD) { | |
| 3a2d35f5 | 205 | // Per-field storage: add the 'per field' table if needed. |
| cf7fe907 YC |
206 | if (!isset($schema[$field_table])) { |
| 207 | $schema[$field_table] = $base_schema; | |
| 208 | } | |
| b4ad53bb | 209 | } |
| 6ddb7830 | 210 | else { |
| 3a2d35f5 | 211 | // Per-type storage: merge the information for the field |
| cf7fe907 YC |
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']); | |
| f4ecb6d2 KS |
215 | } |
| 216 | } | |
| f4ecb6d2 KS |
217 | return $schema; |
| 218 | } | |
| 219 | ||
| 4308fdd4 KS |
220 | function content_update_last_removed() { |
| 221 | return 1008; | |
| 222 | } | |
| 223 | ||
| f4ecb6d2 | 224 | /** |
| 70122e77 | 225 | * Helper function for module updates : |
| a552ad15 YC |
226 | * - checks no updates are pending for content.module |
| 227 | * - checks content module and the module being updated are both enabled. | |
| 70122e77 YC |
228 | * |
| 229 | * @param $module | |
| 230 | * The name of the module being updated. | |
| 70122e77 YC |
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))) { | |
| ee6daf56 KS |
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)) { | |
| 1d165517 | 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)); |
| ee6daf56 KS |
240 | } |
| 241 | // The requested module is not enabled, which may be intentional. | |
| 9a8ca827 | 242 | // Just let the user know there are updates to be processed if enabled later. |
| 4378da32 YC |
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')); | |
| ee6daf56 | 245 | } |
| 70122e77 YC |
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. | |
| e46fd7a2 | 250 | if ($module && (drupal_get_installed_schema_version('content', TRUE) < max(drupal_get_schema_versions('content')))) { |
| 70122e77 | 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); |
| ee6daf56 | 252 | $ret['#abort'] = array('success' => FALSE, 'query' => t('Some updates are still pending.<br/>Please re-run the update script.')); |
| 70122e77 YC |
253 | return $ret; |
| 254 | } | |
| 969ed4fd | 255 | // If everything is OK and updates are not aborted, make sure |
| c21d8aa7 | 256 | // content_associate_fields() gets run. With all the complexity of |
| 969ed4fd | 257 | // the dependent updates, it can get missed when an update is aborted. |
| a48f1469 KS |
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. | |
| c21d8aa7 KS |
262 | if ($module and module_exists($module)) { |
| 263 | content_associate_fields($module); | |
| 264 | } | |
| 70122e77 YC |
265 | } |
| 266 | ||
| 267 | /** | |
| 096ce45e KS |
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() { | |
| 70122e77 YC |
275 | if ($abort = content_check_update()) { |
| 276 | return $abort; | |
| 277 | } | |
| 278 | ||
| 6ddb7830 | 279 | $ret = array(); |
| 35c21ac8 YC |
280 | |
| 281 | drupal_load('module', 'content'); | |
| a207fcc6 | 282 | if (db_column_exists(content_field_tablename(), 'active')) { |
| 6ddb7830 | 283 | return $ret; |
| 096ce45e | 284 | } |
| 6ddb7830 | 285 | db_add_field($ret, content_field_tablename(), 'module', array('type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => '')); |
| e38a7682 | 286 | db_add_field($ret, content_field_tablename(), 'db_columns', array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'initial' => '')); |
| a207fcc6 | 287 | db_add_field($ret, content_field_tablename(), 'active', array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0)); |
| 6ddb7830 | 288 | db_add_field($ret, content_instance_tablename(), 'widget_module', array('type' => 'varchar', 'length' => 127, 'not null' => TRUE, 'default' => '')); |
| a207fcc6 | 289 | db_add_field($ret, content_instance_tablename(), 'widget_active', array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0)); |
| 6ddb7830 | 290 | |
| b1a4d486 | 291 | // This will update the table for any modules enabled at this time. |
| b4ad53bb | 292 | foreach (module_list() as $module) { |
| cf81474b | 293 | content_associate_fields($module); |
| 096ce45e | 294 | } |
| d1539c09 KS |
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 | ||
| 096ce45e | 307 | return $ret; |
| b8e0c85a KS |
308 | } |
| 309 | ||
| b4ad53bb KS |
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. | |
| 6ddb7830 KS |
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'. | |
| b4ad53bb | 320 | */ |
| b8e0c85a | 321 | function content_update_6001() { |
| 70122e77 YC |
322 | if ($abort = content_check_update()) { |
| 323 | return $abort; | |
| 324 | } | |
| 325 | ||
| b8e0c85a | 326 | $ret = array(); |
| 35c21ac8 | 327 | drupal_load('module', 'content'); |
| 6ddb7830 KS |
328 | if (db_table_exists('content_node_field')) { |
| 329 | return $ret; | |
| c6e6349f | 330 | } |
| 6ddb7830 KS |
331 | db_rename_table($ret, 'node_field', 'content_node_field'); |
| 332 | db_rename_table($ret, 'node_field_instance', 'content_node_field_instance'); | |
| f4db2820 | 333 | variable_set('content_schema_version', 6001); |
| b4ad53bb | 334 | content_clear_type_cache(TRUE); |
| b8e0c85a | 335 | return $ret; |
| 6ddb7830 KS |
336 | } |
| 337 | ||
| 338 | /** | |
| 401bf766 | 339 | * Get rid of automatic per content tables for content types that have no fields. |
| 6ddb7830 KS |
340 | * Switching to adding those tables only when needed. |
| 341 | */ | |
| 342 | function content_update_6002() { | |
| 70122e77 YC |
343 | if ($abort = content_check_update()) { |
| 344 | return $abort; | |
| 345 | } | |
| 346 | ||
| bbaf839c KS |
347 | $ret = array(); |
| 348 | ||
| 35c21ac8 | 349 | drupal_load('module', 'content'); |
| 4f059953 | 350 | $db_types = content_types_install(); |
| bbaf839c | 351 | $field_types = array(); |
| 6ddb7830 KS |
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 | ||
| bbaf839c | 358 | foreach ($db_types as $content_type => $content_info) { |
| 6ddb7830 KS |
359 | if (!in_array($content_type, $field_types)) { |
| 360 | $table = _content_tablename($content_type, CONTENT_DB_STORAGE_PER_CONTENT_TYPE); | |
| bbaf839c KS |
361 | if (db_table_exists($table)) { |
| 362 | db_drop_table($ret, $table); | |
| 363 | } | |
| 6ddb7830 KS |
364 | } |
| 365 | } | |
| 870a7dc2 | 366 | variable_set('content_schema_version', 6002); |
| 6ddb7830 | 367 | content_clear_type_cache(TRUE); |
| bbaf839c | 368 | return $ret; |
| 96f4215e YC |
369 | } |
| 370 | ||
| 371 | /** | |
| 372 | * 'db_columns' column 1st got introduced as 'columns', which is forbidden in MySQL 4. | |
| f0dbc087 | 373 | * This update function will only be useful for early D6 testers... |
| 96f4215e YC |
374 | */ |
| 375 | function content_update_6003() { | |
| 70122e77 YC |
376 | if ($abort = content_check_update()) { |
| 377 | return $abort; | |
| 378 | } | |
| 379 | ||
| 96f4215e YC |
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 | } | |
| 88741c1b | 384 | variable_set('content_schema_version', 6003); |
| 96f4215e | 385 | return $ret; |
| c9cc355c YC |
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) { | |
| 70122e77 YC |
393 | if ($abort = content_check_update()) { |
| 394 | return $abort; | |
| 395 | } | |
| 396 | ||
| c9cc355c YC |
397 | $ret = array(); |
| 398 | ||
| 5466662b YC |
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 | ||
| c9cc355c YC |
404 | // Gather list of tables. |
| 405 | if (!isset($sandbox['tables'])) { | |
| c5ce919e | 406 | drupal_load('module', 'content'); |
| c9cc355c YC |
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. | |
| c5ce919e YC |
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 | } | |
| 88741c1b | 430 | variable_set('content_schema_version', 6004); |
| c9cc355c YC |
431 | return $ret; |
| 432 | } | |
| 80a19c40 YC |
433 | |
| 434 | /** | |
| 435 | * Add 'locked' property for fields. | |
| 436 | */ | |
| 437 | function content_update_6005() { | |
| 70122e77 YC |
438 | if ($abort = content_check_update()) { |
| 439 | return $abort; | |
| 440 | } | |
| 441 | ||
| 80a19c40 | 442 | $ret = array(); |
| 35c21ac8 | 443 | drupal_load('module', 'content'); |
| 73478af8 | 444 | db_add_field($ret, content_field_tablename(), 'locked', array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0)); |
| 88741c1b | 445 | variable_set('content_schema_version', 6005); |
| 73478af8 YC |
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() { | |
| 70122e77 YC |
453 | if ($abort = content_check_update()) { |
| 454 | return $abort; | |
| 455 | } | |
| 456 | ||
| 73478af8 YC |
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)); | |
| 88741c1b | 460 | variable_set('content_schema_version', 6006); |
| 80a19c40 YC |
461 | return $ret; |
| 462 | } | |
| 04106cf3 YC |
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() { | |
| 70122e77 YC |
469 | if ($abort = content_check_update()) { |
| 470 | return $abort; | |
| 471 | } | |
| 472 | ||
| 88741c1b | 473 | variable_set('content_schema_version', 6007); |
| 04106cf3 YC |
474 | return array(); |
| 475 | } | |
| 88741c1b KS |
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(); | |
| 37916f9a KS |
487 | } |
| 488 | ||
| 969ed4fd YC |
489 | /** |
| 490 | * Add the 'exclude from $content' display setting to all existing field instances. | |
| 491 | */ | |
| 37916f9a | 492 | function content_update_6009() { |
| 2dc0bd0a KS |
493 | if ($abort = content_check_update()) { |
| 494 | return $abort; | |
| 495 | } | |
| 496 | ||
| 497 | $ret = array(); | |
| 498 | $result = db_query("SELECT * FROM {content_node_field_instance}"); | |
| 37916f9a KS |
499 | while ($type = db_fetch_array($result)) { |
| 500 | $new_settings = array(); | |
| 969ed4fd | 501 | $display_settings = unserialize($type['display_settings']); |
| 37916f9a KS |
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 | } | |
| 2dc0bd0a | 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']); |
| 37916f9a KS |
518 | } |
| 519 | variable_set('content_schema_version', 6009); | |
| 2dc0bd0a | 520 | return $ret; |
| 348f237d YC |
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) { | |
| 75b68284 YC |
528 | if ($abort = content_check_update()) { |
| 529 | return $abort; | |
| 530 | } | |
| 348f237d YC |
531 | $ret = array(); |
| 532 | ||
| 75b68284 YC |
533 | drupal_load('module', 'content'); |
| 534 | ||
| 348f237d YC |
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; | |
| 88741c1b | 621 | } |