|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Install, update and uninstall functions for the taxonomy module. |
|
6 */ |
|
7 |
|
8 /** |
|
9 * Implements hook_uninstall(). |
|
10 */ |
|
11 function taxonomy_uninstall() { |
|
12 // Remove variables. |
|
13 variable_del('taxonomy_override_selector'); |
|
14 variable_del('taxonomy_terms_per_page_admin'); |
|
15 // Remove taxonomy_term bundles. |
|
16 $vocabularies = db_query("SELECT machine_name FROM {taxonomy_vocabulary}")->fetchCol(); |
|
17 foreach ($vocabularies as $vocabulary) { |
|
18 field_attach_delete_bundle('taxonomy_term', $vocabulary); |
|
19 } |
|
20 } |
|
21 |
|
22 /** |
|
23 * Implements hook_schema(). |
|
24 */ |
|
25 function taxonomy_schema() { |
|
26 $schema['taxonomy_term_data'] = array( |
|
27 'description' => 'Stores term information.', |
|
28 'fields' => array( |
|
29 'tid' => array( |
|
30 'type' => 'serial', |
|
31 'unsigned' => TRUE, |
|
32 'not null' => TRUE, |
|
33 'description' => 'Primary Key: Unique term ID.', |
|
34 ), |
|
35 'vid' => array( |
|
36 'type' => 'int', |
|
37 'unsigned' => TRUE, |
|
38 'not null' => TRUE, |
|
39 'default' => 0, |
|
40 'description' => 'The {taxonomy_vocabulary}.vid of the vocabulary to which the term is assigned.', |
|
41 ), |
|
42 'name' => array( |
|
43 'type' => 'varchar', |
|
44 'length' => 255, |
|
45 'not null' => TRUE, |
|
46 'default' => '', |
|
47 'description' => 'The term name.', |
|
48 'translatable' => TRUE, |
|
49 ), |
|
50 'description' => array( |
|
51 'type' => 'text', |
|
52 'not null' => FALSE, |
|
53 'size' => 'big', |
|
54 'description' => 'A description of the term.', |
|
55 'translatable' => TRUE, |
|
56 ), |
|
57 'format' => array( |
|
58 'type' => 'varchar', |
|
59 'length' => 255, |
|
60 'not null' => FALSE, |
|
61 'description' => 'The {filter_format}.format of the description.', |
|
62 ), |
|
63 'weight' => array( |
|
64 'type' => 'int', |
|
65 'not null' => TRUE, |
|
66 'default' => 0, |
|
67 'description' => 'The weight of this term in relation to other terms.', |
|
68 ), |
|
69 ), |
|
70 'primary key' => array('tid'), |
|
71 'foreign keys' => array( |
|
72 'vocabulary' => array( |
|
73 'table' => 'taxonomy_vocabulary', |
|
74 'columns' => array('vid' => 'vid'), |
|
75 ), |
|
76 ), |
|
77 'indexes' => array( |
|
78 'taxonomy_tree' => array('vid', 'weight', 'name'), |
|
79 'vid_name' => array('vid', 'name'), |
|
80 'name' => array('name'), |
|
81 ), |
|
82 ); |
|
83 |
|
84 $schema['taxonomy_term_hierarchy'] = array( |
|
85 'description' => 'Stores the hierarchical relationship between terms.', |
|
86 'fields' => array( |
|
87 'tid' => array( |
|
88 'type' => 'int', |
|
89 'unsigned' => TRUE, |
|
90 'not null' => TRUE, |
|
91 'default' => 0, |
|
92 'description' => 'Primary Key: The {taxonomy_term_data}.tid of the term.', |
|
93 ), |
|
94 'parent' => array( |
|
95 'type' => 'int', |
|
96 'unsigned' => TRUE, |
|
97 'not null' => TRUE, |
|
98 'default' => 0, |
|
99 'description' => "Primary Key: The {taxonomy_term_data}.tid of the term's parent. 0 indicates no parent.", |
|
100 ), |
|
101 ), |
|
102 'indexes' => array( |
|
103 'parent' => array('parent'), |
|
104 ), |
|
105 'foreign keys' => array( |
|
106 'taxonomy_term_data' => array( |
|
107 'table' => 'taxonomy_term_data', |
|
108 'columns' => array('tid' => 'tid'), |
|
109 ), |
|
110 ), |
|
111 'primary key' => array('tid', 'parent'), |
|
112 ); |
|
113 |
|
114 $schema['taxonomy_vocabulary'] = array( |
|
115 'description' => 'Stores vocabulary information.', |
|
116 'fields' => array( |
|
117 'vid' => array( |
|
118 'type' => 'serial', |
|
119 'unsigned' => TRUE, |
|
120 'not null' => TRUE, |
|
121 'description' => 'Primary Key: Unique vocabulary ID.', |
|
122 ), |
|
123 'name' => array( |
|
124 'type' => 'varchar', |
|
125 'length' => 255, |
|
126 'not null' => TRUE, |
|
127 'default' => '', |
|
128 'description' => 'Name of the vocabulary.', |
|
129 'translatable' => TRUE, |
|
130 ), |
|
131 'machine_name' => array( |
|
132 'type' => 'varchar', |
|
133 'length' => 255, |
|
134 'not null' => TRUE, |
|
135 'default' => '', |
|
136 'description' => 'The vocabulary machine name.', |
|
137 ), |
|
138 'description' => array( |
|
139 'type' => 'text', |
|
140 'not null' => FALSE, |
|
141 'size' => 'big', |
|
142 'description' => 'Description of the vocabulary.', |
|
143 'translatable' => TRUE, |
|
144 ), |
|
145 'hierarchy' => array( |
|
146 'type' => 'int', |
|
147 'unsigned' => TRUE, |
|
148 'not null' => TRUE, |
|
149 'default' => 0, |
|
150 'size' => 'tiny', |
|
151 'description' => 'The type of hierarchy allowed within the vocabulary. (0 = disabled, 1 = single, 2 = multiple)', |
|
152 ), |
|
153 'module' => array( |
|
154 'type' => 'varchar', |
|
155 'length' => 255, |
|
156 'not null' => TRUE, |
|
157 'default' => '', |
|
158 'description' => 'The module which created the vocabulary.', |
|
159 ), |
|
160 'weight' => array( |
|
161 'type' => 'int', |
|
162 'not null' => TRUE, |
|
163 'default' => 0, |
|
164 'description' => 'The weight of this vocabulary in relation to other vocabularies.', |
|
165 ), |
|
166 ), |
|
167 'primary key' => array('vid'), |
|
168 'indexes' => array( |
|
169 'list' => array('weight', 'name'), |
|
170 ), |
|
171 'unique keys' => array( |
|
172 'machine_name' => array('machine_name'), |
|
173 ), |
|
174 ); |
|
175 |
|
176 $schema['taxonomy_index'] = array( |
|
177 'description' => 'Maintains denormalized information about node/term relationships.', |
|
178 'fields' => array( |
|
179 'nid' => array( |
|
180 'description' => 'The {node}.nid this record tracks.', |
|
181 'type' => 'int', |
|
182 'unsigned' => TRUE, |
|
183 'not null' => TRUE, |
|
184 'default' => 0, |
|
185 ), |
|
186 'tid' => array( |
|
187 'description' => 'The term ID.', |
|
188 'type' => 'int', |
|
189 'unsigned' => TRUE, |
|
190 'not null' => TRUE, |
|
191 'default' => 0, |
|
192 ), |
|
193 'sticky' => array( |
|
194 'description' => 'Boolean indicating whether the node is sticky.', |
|
195 'type' => 'int', |
|
196 'not null' => FALSE, |
|
197 'default' => 0, |
|
198 'size' => 'tiny', |
|
199 ), |
|
200 'created' => array( |
|
201 'description' => 'The Unix timestamp when the node was created.', |
|
202 'type' => 'int', |
|
203 'not null' => TRUE, |
|
204 'default'=> 0, |
|
205 ), |
|
206 ), |
|
207 'indexes' => array( |
|
208 'term_node' => array('tid', 'sticky', 'created'), |
|
209 'nid' => array('nid'), |
|
210 ), |
|
211 'foreign keys' => array( |
|
212 'tracked_node' => array( |
|
213 'table' => 'node', |
|
214 'columns' => array('nid' => 'nid'), |
|
215 ), |
|
216 'term' => array( |
|
217 'table' => 'taxonomy_term_data', |
|
218 'columns' => array('tid' => 'tid'), |
|
219 ), |
|
220 ), |
|
221 ); |
|
222 |
|
223 return $schema; |
|
224 } |
|
225 |
|
226 /** |
|
227 * Implements hook_field_schema(). |
|
228 */ |
|
229 function taxonomy_field_schema($field) { |
|
230 return array( |
|
231 'columns' => array( |
|
232 'tid' => array( |
|
233 'type' => 'int', |
|
234 'unsigned' => TRUE, |
|
235 'not null' => FALSE, |
|
236 ), |
|
237 ), |
|
238 'indexes' => array( |
|
239 'tid' => array('tid'), |
|
240 ), |
|
241 'foreign keys' => array( |
|
242 'tid' => array( |
|
243 'table' => 'taxonomy_term_data', |
|
244 'columns' => array('tid' => 'tid'), |
|
245 ), |
|
246 ), |
|
247 ); |
|
248 } |
|
249 |
|
250 /** |
|
251 * Implements hook_update_dependencies(). |
|
252 */ |
|
253 function taxonomy_update_dependencies() { |
|
254 // taxonomy_update_7004() migrates taxonomy term data to fields and therefore |
|
255 // must run after all Field modules have been enabled, which happens in |
|
256 // system_update_7027(). |
|
257 $dependencies['taxonomy'][7004] = array( |
|
258 'system' => 7027, |
|
259 ); |
|
260 |
|
261 return $dependencies; |
|
262 } |
|
263 |
|
264 /** |
|
265 * Utility function: get the list of vocabularies directly from the database. |
|
266 * |
|
267 * This function is valid for a database schema version 7002. |
|
268 * |
|
269 * @ingroup update_api |
|
270 */ |
|
271 function _update_7002_taxonomy_get_vocabularies() { |
|
272 return db_query('SELECT v.* FROM {taxonomy_vocabulary} v ORDER BY v.weight, v.name')->fetchAllAssoc('vid', PDO::FETCH_OBJ); |
|
273 } |
|
274 |
|
275 /** |
|
276 * Rename taxonomy tables. |
|
277 */ |
|
278 function taxonomy_update_7001() { |
|
279 db_rename_table('term_data', 'taxonomy_term_data'); |
|
280 db_rename_table('term_hierarchy', 'taxonomy_term_hierarchy'); |
|
281 db_rename_table('term_node', 'taxonomy_term_node'); |
|
282 db_rename_table('term_relation', 'taxonomy_term_relation'); |
|
283 db_rename_table('term_synonym', 'taxonomy_term_synonym'); |
|
284 db_rename_table('vocabulary', 'taxonomy_vocabulary'); |
|
285 db_rename_table('vocabulary_node_types', 'taxonomy_vocabulary_node_type'); |
|
286 } |
|
287 |
|
288 /** |
|
289 * Add {vocabulary}.machine_name column. |
|
290 */ |
|
291 function taxonomy_update_7002() { |
|
292 $field = array( |
|
293 'type' => 'varchar', |
|
294 'length' => 255, |
|
295 'not null' => TRUE, |
|
296 'default' => '', |
|
297 'description' => 'The vocabulary machine name.', |
|
298 ); |
|
299 |
|
300 db_add_field('taxonomy_vocabulary', 'machine_name', $field); |
|
301 |
|
302 // Do a direct query here, rather than calling taxonomy_get_vocabularies(), |
|
303 // in case Taxonomy module is disabled. |
|
304 $vids = db_query('SELECT vid FROM {taxonomy_vocabulary}')->fetchCol(); |
|
305 foreach ($vids as $vid) { |
|
306 $machine_name = 'vocabulary_' . $vid; |
|
307 db_update('taxonomy_vocabulary') |
|
308 ->fields(array('machine_name' => $machine_name)) |
|
309 ->condition('vid', $vid) |
|
310 ->execute(); |
|
311 } |
|
312 |
|
313 // The machine_name unique key can only be added after we ensure the |
|
314 // machine_name column contains unique values. |
|
315 db_add_unique_key('taxonomy_vocabulary', 'machine_name', array('machine_name')); |
|
316 } |
|
317 |
|
318 /** |
|
319 * Remove the related terms setting from vocabularies. |
|
320 * |
|
321 * This setting has not been used since Drupal 6. The {taxonomy_relations} table |
|
322 * itself is retained to allow for data to be upgraded. |
|
323 */ |
|
324 function taxonomy_update_7003() { |
|
325 db_drop_field('taxonomy_vocabulary', 'relations'); |
|
326 } |
|
327 |
|
328 /** |
|
329 * Move taxonomy vocabulary associations for nodes to fields and field instances. |
|
330 */ |
|
331 function taxonomy_update_7004() { |
|
332 $taxonomy_index = array( |
|
333 'description' => 'Maintains denormalized information about node/term relationships.', |
|
334 'fields' => array( |
|
335 'nid' => array( |
|
336 'description' => 'The {node}.nid this record tracks.', |
|
337 'type' => 'int', |
|
338 'unsigned' => TRUE, |
|
339 'not null' => TRUE, |
|
340 'default' => 0, |
|
341 ), |
|
342 'tid' => array( |
|
343 'description' => 'The term ID.', |
|
344 'type' => 'int', |
|
345 'unsigned' => TRUE, |
|
346 'not null' => TRUE, |
|
347 'default' => 0, |
|
348 ), |
|
349 'sticky' => array( |
|
350 'description' => 'Boolean indicating whether the node is sticky.', |
|
351 'type' => 'int', |
|
352 'not null' => FALSE, |
|
353 'default' => 0, |
|
354 'size' => 'tiny', |
|
355 ), |
|
356 'created' => array( |
|
357 'description' => 'The Unix timestamp when the node was created.', |
|
358 'type' => 'int', |
|
359 'unsigned' => TRUE, |
|
360 'not null' => TRUE, |
|
361 'default'=> 0, |
|
362 ), |
|
363 ), |
|
364 'indexes' => array( |
|
365 'term_node' => array('tid', 'sticky', 'created'), |
|
366 'nid' => array('nid'), |
|
367 ), |
|
368 'foreign keys' => array( |
|
369 'tracked_node' => array( |
|
370 'table' => 'node', |
|
371 'columns' => array('nid' => 'nid'), |
|
372 ), |
|
373 'term' => array( |
|
374 'table' => 'taxonomy_term_data', |
|
375 'columns' => array('tid' => 'tid'), |
|
376 ), |
|
377 ), |
|
378 ); |
|
379 db_create_table('taxonomy_index', $taxonomy_index); |
|
380 |
|
381 // Use an inline version of Drupal 6 taxonomy_get_vocabularies() here since |
|
382 // we can no longer rely on $vocabulary->nodes from the API function. |
|
383 $result = db_query('SELECT v.*, n.type FROM {taxonomy_vocabulary} v LEFT JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid ORDER BY v.weight, v.name'); |
|
384 $vocabularies = array(); |
|
385 foreach ($result as $record) { |
|
386 // If no node types are associated with a vocabulary, the LEFT JOIN will |
|
387 // return a NULL value for type. |
|
388 if (isset($record->type)) { |
|
389 $node_types[$record->vid][$record->type] = $record->type; |
|
390 unset($record->type); |
|
391 $record->nodes = $node_types[$record->vid]; |
|
392 } |
|
393 elseif (!isset($record->nodes)) { |
|
394 $record->nodes = array(); |
|
395 } |
|
396 $vocabularies[$record->vid] = $record; |
|
397 } |
|
398 |
|
399 foreach ($vocabularies as $vocabulary) { |
|
400 $field_name = 'taxonomy_' . $vocabulary->machine_name; |
|
401 $field = array( |
|
402 'field_name' => $field_name, |
|
403 'module' => 'taxonomy', |
|
404 'type' => 'taxonomy_term_reference', |
|
405 'cardinality' => $vocabulary->multiple || $vocabulary->tags ? FIELD_CARDINALITY_UNLIMITED : 1, |
|
406 'settings' => array( |
|
407 'required' => $vocabulary->required ? TRUE : FALSE, |
|
408 'allowed_values' => array( |
|
409 array( |
|
410 'vocabulary' => $vocabulary->machine_name, |
|
411 'parent' => 0, |
|
412 ), |
|
413 ), |
|
414 ), |
|
415 ); |
|
416 _update_7000_field_create_field($field); |
|
417 |
|
418 foreach ($vocabulary->nodes as $bundle) { |
|
419 $instance = array( |
|
420 'label' => $vocabulary->name, |
|
421 'field_name' => $field_name, |
|
422 'bundle' => $bundle, |
|
423 'entity_type' => 'node', |
|
424 'settings' => array(), |
|
425 'description' => $vocabulary->help, |
|
426 'required' => $vocabulary->required, |
|
427 'widget' => array(), |
|
428 'display' => array( |
|
429 'default' => array( |
|
430 'type' => 'taxonomy_term_reference_link', |
|
431 'weight' => 10, |
|
432 ), |
|
433 'teaser' => array( |
|
434 'type' => 'taxonomy_term_reference_link', |
|
435 'weight' => 10, |
|
436 ), |
|
437 ), |
|
438 ); |
|
439 if ($vocabulary->tags) { |
|
440 $instance['widget'] = array( |
|
441 'type' => 'taxonomy_autocomplete', |
|
442 'module' => 'taxonomy', |
|
443 'settings' => array( |
|
444 'size' => 60, |
|
445 'autocomplete_path' => 'taxonomy/autocomplete', |
|
446 ), |
|
447 ); |
|
448 } |
|
449 else { |
|
450 $instance['widget'] = array( |
|
451 'type' => 'select', |
|
452 'module' => 'options', |
|
453 'settings' => array(), |
|
454 ); |
|
455 } |
|
456 _update_7000_field_create_instance($field, $instance); |
|
457 } |
|
458 } |
|
459 |
|
460 // Some contrib projects stored term node associations without regard for the |
|
461 // selections in the taxonomy_vocabulary_node_types table, or have more terms |
|
462 // for a single node than the vocabulary allowed. We construct the |
|
463 // taxonomyextra field to store all the extra stuff. |
|
464 |
|
465 // Allowed values for this extra vocabs field is every vocabulary. |
|
466 $allowed_values = array(); |
|
467 foreach (_update_7002_taxonomy_get_vocabularies() as $vocabulary) { |
|
468 $allowed_values[] = array( |
|
469 'vocabulary' => $vocabulary->machine_name, |
|
470 'parent' => 0, |
|
471 ); |
|
472 } |
|
473 |
|
474 $field_name = 'taxonomyextra'; |
|
475 $field = array( |
|
476 'field_name' => $field_name, |
|
477 'module' => 'taxonomy', |
|
478 'type' => 'taxonomy_term_reference', |
|
479 'cardinality' => FIELD_CARDINALITY_UNLIMITED, |
|
480 'settings' => array( |
|
481 'required' => FALSE, |
|
482 'allowed_values' => $allowed_values, |
|
483 ), |
|
484 ); |
|
485 _update_7000_field_create_field($field); |
|
486 |
|
487 foreach (_update_7000_node_get_types() as $bundle) { |
|
488 $instance = array( |
|
489 'label' => 'Taxonomy upgrade extras', |
|
490 'field_name' => $field_name, |
|
491 'entity_type' => 'node', |
|
492 'bundle' => $bundle->type, |
|
493 'settings' => array(), |
|
494 'description' => 'Debris left over after upgrade from Drupal 6', |
|
495 'required' => FALSE, |
|
496 'widget' => array( |
|
497 'type' => 'taxonomy_autocomplete', |
|
498 'module' => 'taxonomy', |
|
499 'settings' => array(), |
|
500 ), |
|
501 'display' => array( |
|
502 'default' => array( |
|
503 'type' => 'taxonomy_term_reference_link', |
|
504 'weight' => 10, |
|
505 ), |
|
506 'teaser' => array( |
|
507 'type' => 'taxonomy_term_reference_link', |
|
508 'weight' => 10, |
|
509 ), |
|
510 ), |
|
511 ); |
|
512 _update_7000_field_create_instance($field, $instance); |
|
513 } |
|
514 |
|
515 $fields = array('help', 'multiple', 'required', 'tags'); |
|
516 foreach ($fields as $field) { |
|
517 db_drop_field('taxonomy_vocabulary', $field); |
|
518 } |
|
519 } |
|
520 |
|
521 /** |
|
522 * Migrate {taxonomy_term_node} table to field storage. |
|
523 * |
|
524 * @todo: This function can possibly be made much faster by wrapping a |
|
525 * transaction around all the inserts. |
|
526 */ |
|
527 function taxonomy_update_7005(&$sandbox) { |
|
528 // $sandbox contents: |
|
529 // - total: The total number of term_node relationships to migrate. |
|
530 // - count: The number of term_node relationships that have been |
|
531 // migrated so far. |
|
532 // - last: The db_query_range() offset to use when querying |
|
533 // term_node; this field is incremented in quantities of $batch |
|
534 // (1000) but at the end of each call to this function, last and |
|
535 // count are the same. |
|
536 // - vocabularies: An associative array mapping vocabulary id and node |
|
537 // type to field name. If a voc id/node type pair does not appear |
|
538 // in this array but a term_node relationship exists mapping a |
|
539 // term in voc id to node of that type, the relationship is |
|
540 // assigned to the taxonomymyextra field which allows terms of all |
|
541 // vocabularies. |
|
542 // - cursor[values], cursor[deltas]: The contents of $values and |
|
543 // $deltas at the end of the previous call to this function. These |
|
544 // need to be preserved across calls because a single batch of |
|
545 // 1000 rows from term_node may end in the middle of the terms for |
|
546 // a single node revision. |
|
547 // |
|
548 // $values is the array of values about to be/most recently inserted |
|
549 // into the SQL data table for the taxonomy_term_reference |
|
550 // field. Before $values is constructed for each record, the |
|
551 // $values from the previous insert is checked to see if the two |
|
552 // records are for the same node revision id; this enables knowing |
|
553 // when to reset the delta counters which are incremented across all |
|
554 // terms for a single field on a single revision, but reset for each |
|
555 // new field and revision. |
|
556 // |
|
557 // $deltas is an associative array mapping field name to the number |
|
558 // of term references stored so far for the current revision, which |
|
559 // provides the delta value for each term reference data insert. The |
|
560 // deltas are reset for each new revision. |
|
561 |
|
562 $conditions = array( |
|
563 'type' => 'taxonomy_term_reference', |
|
564 'deleted' => 0, |
|
565 ); |
|
566 $field_info = _update_7000_field_read_fields($conditions, 'field_name'); |
|
567 |
|
568 // This is a multi-pass update. On the first call we need to initialize some |
|
569 // variables. |
|
570 if (!isset($sandbox['total'])) { |
|
571 $sandbox['last'] = 0; |
|
572 $sandbox['count'] = 0; |
|
573 |
|
574 // Run the same joins as the query that is used later to retrieve the |
|
575 // term_node data, this ensures that bad records in that table - for |
|
576 // tids which aren't in taxonomy_term_data or nids which aren't in {node} |
|
577 // are not included in the count. |
|
578 $sandbox['total'] = db_query('SELECT COUNT(*) FROM {taxonomy_term_data} td INNER JOIN {taxonomy_term_node} tn ON td.tid = tn.tid INNER JOIN {node} n ON tn.nid = n.nid LEFT JOIN {node} n2 ON tn.vid = n2.vid')->fetchField(); |
|
579 |
|
580 // Use an inline version of Drupal 6 taxonomy_get_vocabularies() here since |
|
581 // we can no longer rely on $vocabulary->nodes from the API function. |
|
582 $result = db_query('SELECT v.vid, v.machine_name, n.type FROM {taxonomy_vocabulary} v INNER JOIN {taxonomy_vocabulary_node_type} n ON v.vid = n.vid'); |
|
583 $vocabularies = array(); |
|
584 foreach ($result as $record) { |
|
585 |
|
586 // If no node types are associated with a vocabulary, the LEFT JOIN will |
|
587 // return a NULL value for type. |
|
588 if (isset($record->type)) { |
|
589 $vocabularies[$record->vid][$record->type] = 'taxonomy_'. $record->machine_name; |
|
590 } |
|
591 } |
|
592 |
|
593 if (!empty($vocabularies)) { |
|
594 $sandbox['vocabularies'] = $vocabularies; |
|
595 } |
|
596 |
|
597 db_create_table('taxonomy_update_7005', array( |
|
598 'description' => 'Stores temporary data for taxonomy_update_7005.', |
|
599 'fields' => array( |
|
600 'n' => array( |
|
601 'description' => 'Preserve order.', |
|
602 'type' => 'serial', |
|
603 'unsigned' => TRUE, |
|
604 'not null' => TRUE, |
|
605 ), |
|
606 'vocab_id' => array( |
|
607 'type' => 'int', |
|
608 'unsigned' => TRUE, |
|
609 'not null' => TRUE, |
|
610 'default' => 0, |
|
611 ), |
|
612 'tid' => array( |
|
613 'type' => 'int', |
|
614 'unsigned' => TRUE, |
|
615 'not null' => TRUE, |
|
616 ), |
|
617 'nid' => array( |
|
618 'type' => 'int', |
|
619 'unsigned' => TRUE, |
|
620 'not null' => TRUE, |
|
621 ), |
|
622 'vid' => array( |
|
623 'type' => 'int', |
|
624 'unsigned' => TRUE, |
|
625 'not null' => FALSE, |
|
626 'default' => NULL, |
|
627 ), |
|
628 'type' => array( |
|
629 'type' => 'varchar', |
|
630 'length' => 32, |
|
631 'not null' => TRUE, |
|
632 'default' => '', |
|
633 ), |
|
634 'created' => array( |
|
635 'type' => 'int', |
|
636 'not null' => FALSE, |
|
637 ), |
|
638 'sticky' => array( |
|
639 'type' => 'int', |
|
640 'not null' => FALSE, |
|
641 ), |
|
642 'status' => array( |
|
643 'type' => 'int', |
|
644 'not null' => FALSE, |
|
645 ), |
|
646 'is_current' => array( |
|
647 'type' => 'int', |
|
648 'unsigned' => TRUE, |
|
649 'not null' => FALSE, |
|
650 ), |
|
651 ), |
|
652 'primary key' => array('n'), |
|
653 )); |
|
654 |
|
655 // Query selects all revisions at once and processes them in revision and |
|
656 // term weight order. |
|
657 $query = db_select('taxonomy_term_data', 'td'); |
|
658 // We are migrating term-node relationships. If there are none for a |
|
659 // term, we do not need the term_data row. |
|
660 $query->join('taxonomy_term_node', 'tn', 'td.tid = tn.tid'); |
|
661 // If a term-node relationship exists for a nid that does not exist, we |
|
662 // cannot migrate it as we have no node to relate it to; thus we do not |
|
663 // need that row from term_node. |
|
664 $query->join('node', 'n', 'tn.nid = n.nid'); |
|
665 // If the current term-node relationship is for the current revision of |
|
666 // the node, this left join will match and is_current will be non-NULL |
|
667 // (we also get the current sticky and created in this case). This |
|
668 // tells us whether to insert into the current data tables in addition |
|
669 // to the revision data tables. |
|
670 $query->leftJoin('node', 'n2', 'tn.vid = n2.vid'); |
|
671 $query->addField('td', 'vid', 'vocab_id'); |
|
672 $query->addField('td', 'tid'); |
|
673 $query->addField('tn', 'nid'); |
|
674 $query->addField('tn', 'vid'); |
|
675 $query->addField('n', 'type'); |
|
676 $query->addField('n2', 'created'); |
|
677 $query->addField('n2', 'sticky'); |
|
678 $query->addField('n2', 'status'); |
|
679 $query->addField('n2', 'nid', 'is_current'); |
|
680 // This query must return a consistent ordering across multiple calls. |
|
681 // We need them ordered by node vid (since we use that to decide when |
|
682 // to reset the delta counters) and by term weight so they appear |
|
683 // within each node in weight order. However, tn.vid,td.weight is not |
|
684 // guaranteed to be unique, so we add tn.tid as an additional sort key |
|
685 // because tn.tid,tn.vid is the primary key of the D6 term_node table |
|
686 // and so is guaranteed unique. Unfortunately it also happens to be in |
|
687 // the wrong order which is less efficient, but c'est la vie. |
|
688 $query->orderBy('tn.vid'); |
|
689 $query->orderBy('td.weight'); |
|
690 $query->orderBy('tn.tid'); |
|
691 |
|
692 // Work around a bug in the PostgreSQL driver that would result in fatal |
|
693 // errors when this subquery is used in the insert query below. See |
|
694 // https://drupal.org/node/2057693. |
|
695 $fields = &$query->getFields(); |
|
696 unset($fields['td.weight']); |
|
697 unset($fields['tn.tid']); |
|
698 |
|
699 db_insert('taxonomy_update_7005') |
|
700 ->from($query) |
|
701 ->execute(); |
|
702 } |
|
703 else { |
|
704 // We do each pass in batches of 1000. |
|
705 $batch = 1000; |
|
706 |
|
707 $result = db_query_range('SELECT vocab_id, tid, nid, vid, type, created, sticky, status, is_current FROM {taxonomy_update_7005} ORDER BY n', $sandbox['last'], $batch); |
|
708 if (isset($sandbox['cursor'])) { |
|
709 $values = $sandbox['cursor']['values']; |
|
710 $deltas = $sandbox['cursor']['deltas']; |
|
711 } |
|
712 else { |
|
713 $deltas = array(); |
|
714 } |
|
715 foreach ($result as $record) { |
|
716 $sandbox['count'] += 1; |
|
717 |
|
718 // Use the valid field for this vocabulary and node type or use the |
|
719 // overflow vocabulary if there is no valid field. |
|
720 $field_name = isset($sandbox['vocabularies'][$record->vocab_id][$record->type]) ? $sandbox['vocabularies'][$record->vocab_id][$record->type] : 'taxonomyextra'; |
|
721 $field = $field_info[$field_name]; |
|
722 |
|
723 // Start deltas from 0, and increment by one for each term attached to a |
|
724 // node. |
|
725 if (!isset($deltas[$field_name])) { |
|
726 $deltas[$field_name] = 0; |
|
727 } |
|
728 |
|
729 if (isset($values)) { |
|
730 |
|
731 // If the last inserted revision_id is the same as the current record, |
|
732 // use the previous deltas to calculate the next delta. |
|
733 if ($record->vid == $values[2]) { |
|
734 |
|
735 // For limited cardinality fields, the delta must not be allowed to |
|
736 // exceed the cardinality during the update. So ensure that the |
|
737 // delta about to be inserted is within this limit. |
|
738 // @see field_default_validate(). |
|
739 if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ($deltas[$field_name] + 1) > $field['cardinality']) { |
|
740 |
|
741 // For excess values of a single-term vocabulary, switch over to |
|
742 // the overflow field. |
|
743 $field_name = 'taxonomyextra'; |
|
744 $field = $field_info[$field_name]; |
|
745 if (!isset($deltas[$field_name])) { |
|
746 $deltas[$field_name] = 0; |
|
747 } |
|
748 } |
|
749 } |
|
750 else { |
|
751 |
|
752 // When the record is a new revision, empty the deltas array. |
|
753 $deltas = array($field_name => 0); |
|
754 } |
|
755 } |
|
756 |
|
757 // Table and column found in the field's storage details. During upgrades, |
|
758 // it's always SQL. |
|
759 $table_name = "field_data_{$field_name}"; |
|
760 $revision_name = "field_revision_{$field_name}"; |
|
761 $value_column = $field_name . '_tid'; |
|
762 |
|
763 // Column names and values in field storage are the same for current and |
|
764 // revision. |
|
765 $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'language', 'delta', $value_column); |
|
766 $values = array('node', $record->nid, $record->vid, $record->type, LANGUAGE_NONE, $deltas[$field_name]++, $record->tid); |
|
767 |
|
768 // Insert rows into the revision table. |
|
769 db_insert($revision_name)->fields($columns)->values($values)->execute(); |
|
770 |
|
771 // is_current column is a node ID if this revision is also current. |
|
772 if ($record->is_current) { |
|
773 db_insert($table_name)->fields($columns)->values($values)->execute(); |
|
774 // Only insert a record in the taxonomy index if the node is published. |
|
775 if ($record->status) { |
|
776 // Update the {taxonomy_index} table. |
|
777 db_insert('taxonomy_index') |
|
778 ->fields(array('nid', 'tid', 'sticky', 'created',)) |
|
779 ->values(array($record->nid, $record->tid, $record->sticky, $record->created)) |
|
780 ->execute(); |
|
781 } |
|
782 } |
|
783 } |
|
784 |
|
785 // Store the set of inserted values and the current revision's deltas in the |
|
786 // sandbox. |
|
787 $sandbox['cursor'] = array( |
|
788 'values' => $values, |
|
789 'deltas' => $deltas, |
|
790 ); |
|
791 $sandbox['last'] += $batch; |
|
792 } |
|
793 |
|
794 if ($sandbox['count'] < $sandbox['total']) { |
|
795 $sandbox['#finished'] = FALSE; |
|
796 } |
|
797 else { |
|
798 db_drop_table('taxonomy_vocabulary_node_type'); |
|
799 db_drop_table('taxonomy_term_node'); |
|
800 |
|
801 // If there are no vocabs, we're done. |
|
802 db_drop_table('taxonomy_update_7005'); |
|
803 $sandbox['#finished'] = TRUE; |
|
804 |
|
805 // Determine necessity of taxonomyextras field. |
|
806 $field = $field_info['taxonomyextra']; |
|
807 $revision_name = 'field_revision_' . $field['field_name']; |
|
808 $node_types = db_select($revision_name)->distinct()->fields($revision_name, array('bundle')) |
|
809 ->execute()->fetchCol(); |
|
810 |
|
811 if (empty($node_types)) { |
|
812 // Delete the overflow field if there are no rows in the revision table. |
|
813 _update_7000_field_delete_field('taxonomyextra'); |
|
814 } |
|
815 else { |
|
816 // Remove instances which are not actually used. |
|
817 $bundles = db_query('SELECT bundle FROM {field_config_instance} WHERE field_name = :field_name', array(':field_name' => 'taxonomyextra'))->fetchCol(); |
|
818 $bundles = array_diff($bundles, $node_types); |
|
819 foreach ($bundles as $bundle) { |
|
820 _update_7000_field_delete_instance('taxonomyextra', 'node', $bundle); |
|
821 } |
|
822 } |
|
823 } |
|
824 } |
|
825 |
|
826 /** |
|
827 * Add {taxonomy_term_data}.format column. |
|
828 */ |
|
829 function taxonomy_update_7006() { |
|
830 db_add_field('taxonomy_term_data', 'format', array( |
|
831 'type' => 'int', |
|
832 'unsigned' => TRUE, |
|
833 'not null' => FALSE, |
|
834 'description' => 'The {filter_format}.format of the description.', |
|
835 )); |
|
836 } |
|
837 |
|
838 /** |
|
839 * Add index on {taxonomy_term_data}.name column to speed up taxonomy_get_term_by_name(). |
|
840 */ |
|
841 function taxonomy_update_7007() { |
|
842 db_add_index('taxonomy_term_data', 'name', array('name')); |
|
843 } |
|
844 |
|
845 /** |
|
846 * Change the weight columns to normal int. |
|
847 */ |
|
848 function taxonomy_update_7008() { |
|
849 db_drop_index('taxonomy_term_data', 'taxonomy_tree'); |
|
850 db_change_field('taxonomy_term_data', 'weight', 'weight', array( |
|
851 'type' => 'int', |
|
852 'not null' => TRUE, |
|
853 'default' => 0, |
|
854 'description' => 'The weight of this term in relation to other terms.', |
|
855 ), array( |
|
856 'indexes' => array( |
|
857 'taxonomy_tree' => array('vid', 'weight', 'name'), |
|
858 ), |
|
859 )); |
|
860 |
|
861 db_drop_index('taxonomy_vocabulary', 'list'); |
|
862 db_change_field('taxonomy_vocabulary', 'weight', 'weight', array( |
|
863 'type' => 'int', |
|
864 'not null' => TRUE, |
|
865 'default' => 0, |
|
866 'description' => 'The weight of this vocabulary in relation to other vocabularies.', |
|
867 ), array( |
|
868 'indexes' => array( |
|
869 'list' => array('weight', 'name'), |
|
870 ), |
|
871 )); |
|
872 } |
|
873 |
|
874 /** |
|
875 * Change {taxonomy_term_data}.format into varchar. |
|
876 */ |
|
877 function taxonomy_update_7009() { |
|
878 db_change_field('taxonomy_term_data', 'format', 'format', array( |
|
879 'type' => 'varchar', |
|
880 'length' => 255, |
|
881 'not null' => FALSE, |
|
882 'description' => 'The {filter_format}.format of the description.', |
|
883 )); |
|
884 } |
|
885 |
|
886 /** |
|
887 * Change {taxonomy_index}.created to support signed int. |
|
888 */ |
|
889 function taxonomy_update_7010() { |
|
890 db_change_field('taxonomy_index', 'created', 'created', array( |
|
891 'description' => 'The Unix timestamp when the node was created.', |
|
892 'type' => 'int', |
|
893 'unsigned' => FALSE, |
|
894 'not null' => TRUE, |
|
895 'default'=> 0, |
|
896 )); |
|
897 } |
|
898 |
|
899 /** |
|
900 * @addtogroup updates-7.x-extra |
|
901 * @{ |
|
902 */ |
|
903 |
|
904 /** |
|
905 * Drop unpublished nodes from the index. |
|
906 */ |
|
907 function taxonomy_update_7011(&$sandbox) { |
|
908 // Initialize information needed by the batch update system. |
|
909 if (!isset($sandbox['progress'])) { |
|
910 $sandbox['progress'] = 0; |
|
911 $sandbox['max'] = db_query('SELECT COUNT(DISTINCT n.nid) FROM {node} n INNER JOIN {taxonomy_index} t ON n.nid = t.nid WHERE n.status = :status', array(':status' => NODE_NOT_PUBLISHED))->fetchField(); |
|
912 // If there's no data, don't bother with the extra work. |
|
913 if (empty($sandbox['max'])) { |
|
914 return; |
|
915 } |
|
916 } |
|
917 |
|
918 // Process records in groups of 5000. |
|
919 $limit = 5000; |
|
920 $nids = db_query_range('SELECT DISTINCT n.nid FROM {node} n INNER JOIN {taxonomy_index} t ON n.nid = t.nid WHERE n.status = :status', 0, $limit, array(':status' => NODE_NOT_PUBLISHED))->fetchCol(); |
|
921 if (!empty($nids)) { |
|
922 db_delete('taxonomy_index') |
|
923 ->condition('nid', $nids) |
|
924 ->execute(); |
|
925 } |
|
926 |
|
927 // Update our progress information for the batch update. |
|
928 $sandbox['progress'] += $limit; |
|
929 |
|
930 // Indicate our current progress to the batch update system, if the update is |
|
931 // not yet complete. |
|
932 if ($sandbox['progress'] < $sandbox['max']) { |
|
933 $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max']; |
|
934 } |
|
935 } |
|
936 |
|
937 /** |
|
938 * @} End of "addtogroup updates-7.x-extra". |
|
939 */ |