Mercurial > hg > rr-repo
comparison modules/taxonomy/taxonomy.install @ 0:ff03f76ab3fe
initial version
author | danieleb <danielebarchiesi@me.com> |
---|---|
date | Wed, 21 Aug 2013 18:51:11 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:ff03f76ab3fe |
---|---|
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 'widget' => array( | |
496 'type' => 'taxonomy_autocomplete', | |
497 'module' => 'taxonomy', | |
498 'settings' => array(), | |
499 ), | |
500 'display' => array( | |
501 'default' => array( | |
502 'type' => 'taxonomy_term_reference_link', | |
503 'weight' => 10, | |
504 ), | |
505 'teaser' => array( | |
506 'type' => 'taxonomy_term_reference_link', | |
507 'weight' => 10, | |
508 ), | |
509 ), | |
510 ); | |
511 _update_7000_field_create_instance($field, $instance); | |
512 } | |
513 | |
514 $fields = array('help', 'multiple', 'required', 'tags'); | |
515 foreach ($fields as $field) { | |
516 db_drop_field('taxonomy_vocabulary', $field); | |
517 } | |
518 } | |
519 | |
520 /** | |
521 * Migrate {taxonomy_term_node} table to field storage. | |
522 * | |
523 * @todo: This function can possibly be made much faster by wrapping a | |
524 * transaction around all the inserts. | |
525 */ | |
526 function taxonomy_update_7005(&$sandbox) { | |
527 // $sandbox contents: | |
528 // - total: The total number of term_node relationships to migrate. | |
529 // - count: The number of term_node relationships that have been | |
530 // migrated so far. | |
531 // - last: The db_query_range() offset to use when querying | |
532 // term_node; this field is incremented in quantities of $batch | |
533 // (1000) but at the end of each call to this function, last and | |
534 // count are the same. | |
535 // - vocabularies: An associative array mapping vocabulary id and node | |
536 // type to field name. If a voc id/node type pair does not appear | |
537 // in this array but a term_node relationship exists mapping a | |
538 // term in voc id to node of that type, the relationship is | |
539 // assigned to the taxonomymyextra field which allows terms of all | |
540 // vocabularies. | |
541 // - cursor[values], cursor[deltas]: The contents of $values and | |
542 // $deltas at the end of the previous call to this function. These | |
543 // need to be preserved across calls because a single batch of | |
544 // 1000 rows from term_node may end in the middle of the terms for | |
545 // a single node revision. | |
546 // | |
547 // $values is the array of values about to be/most recently inserted | |
548 // into the SQL data table for the taxonomy_term_reference | |
549 // field. Before $values is constructed for each record, the | |
550 // $values from the previous insert is checked to see if the two | |
551 // records are for the same node revision id; this enables knowing | |
552 // when to reset the delta counters which are incremented across all | |
553 // terms for a single field on a single revision, but reset for each | |
554 // new field and revision. | |
555 // | |
556 // $deltas is an associative array mapping field name to the number | |
557 // of term references stored so far for the current revision, which | |
558 // provides the delta value for each term reference data insert. The | |
559 // deltas are reset for each new revision. | |
560 | |
561 $conditions = array( | |
562 'type' => 'taxonomy_term_reference', | |
563 'deleted' => 0, | |
564 ); | |
565 $field_info = _update_7000_field_read_fields($conditions, 'field_name'); | |
566 | |
567 // This is a multi-pass update. On the first call we need to initialize some | |
568 // variables. | |
569 if (!isset($sandbox['total'])) { | |
570 $sandbox['last'] = 0; | |
571 $sandbox['count'] = 0; | |
572 | |
573 // Run the same joins as the query that is used later to retrieve the | |
574 // term_node data, this ensures that bad records in that table - for | |
575 // tids which aren't in taxonomy_term_data or nids which aren't in {node} | |
576 // are not included in the count. | |
577 $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(); | |
578 | |
579 // Use an inline version of Drupal 6 taxonomy_get_vocabularies() here since | |
580 // we can no longer rely on $vocabulary->nodes from the API function. | |
581 $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'); | |
582 $vocabularies = array(); | |
583 foreach ($result as $record) { | |
584 | |
585 // If no node types are associated with a vocabulary, the LEFT JOIN will | |
586 // return a NULL value for type. | |
587 if (isset($record->type)) { | |
588 $vocabularies[$record->vid][$record->type] = 'taxonomy_'. $record->machine_name; | |
589 } | |
590 } | |
591 | |
592 if (!empty($vocabularies)) { | |
593 $sandbox['vocabularies'] = $vocabularies; | |
594 } | |
595 | |
596 db_create_table('taxonomy_update_7005', array( | |
597 'description' => 'Stores temporary data for taxonomy_update_7005.', | |
598 'fields' => array( | |
599 'n' => array( | |
600 'description' => 'Preserve order.', | |
601 'type' => 'serial', | |
602 'unsigned' => TRUE, | |
603 'not null' => TRUE, | |
604 ), | |
605 'vocab_id' => array( | |
606 'type' => 'int', | |
607 'unsigned' => TRUE, | |
608 'not null' => TRUE, | |
609 'default' => 0, | |
610 ), | |
611 'tid' => array( | |
612 'type' => 'int', | |
613 'unsigned' => TRUE, | |
614 'not null' => TRUE, | |
615 ), | |
616 'nid' => array( | |
617 'type' => 'int', | |
618 'unsigned' => TRUE, | |
619 'not null' => TRUE, | |
620 ), | |
621 'vid' => array( | |
622 'type' => 'int', | |
623 'unsigned' => TRUE, | |
624 'not null' => FALSE, | |
625 'default' => NULL, | |
626 ), | |
627 'type' => array( | |
628 'type' => 'varchar', | |
629 'length' => 32, | |
630 'not null' => TRUE, | |
631 'default' => '', | |
632 ), | |
633 'created' => array( | |
634 'type' => 'int', | |
635 'not null' => FALSE, | |
636 ), | |
637 'sticky' => array( | |
638 'type' => 'int', | |
639 'not null' => FALSE, | |
640 ), | |
641 'is_current' => array( | |
642 'type' => 'int', | |
643 'unsigned' => TRUE, | |
644 'not null' => FALSE, | |
645 ), | |
646 ), | |
647 'primary key' => array('n'), | |
648 )); | |
649 | |
650 // Query selects all revisions at once and processes them in revision and | |
651 // term weight order. | |
652 $query = db_select('taxonomy_term_data', 'td'); | |
653 // We are migrating term-node relationships. If there are none for a | |
654 // term, we do not need the term_data row. | |
655 $query->join('taxonomy_term_node', 'tn', 'td.tid = tn.tid'); | |
656 // If a term-node relationship exists for a nid that does not exist, we | |
657 // cannot migrate it as we have no node to relate it to; thus we do not | |
658 // need that row from term_node. | |
659 $query->join('node', 'n', 'tn.nid = n.nid'); | |
660 // If the current term-node relationship is for the current revision of | |
661 // the node, this left join will match and is_current will be non-NULL | |
662 // (we also get the current sticky and created in this case). This | |
663 // tells us whether to insert into the current data tables in addition | |
664 // to the revision data tables. | |
665 $query->leftJoin('node', 'n2', 'tn.vid = n2.vid'); | |
666 $query->addField('td', 'vid', 'vocab_id'); | |
667 $query->addField('td', 'tid'); | |
668 $query->addField('tn', 'nid'); | |
669 $query->addField('tn', 'vid'); | |
670 $query->addField('n', 'type'); | |
671 $query->addField('n2', 'created'); | |
672 $query->addField('n2', 'sticky'); | |
673 $query->addField('n2', 'nid', 'is_current'); | |
674 // This query must return a consistent ordering across multiple calls. | |
675 // We need them ordered by node vid (since we use that to decide when | |
676 // to reset the delta counters) and by term weight so they appear | |
677 // within each node in weight order. However, tn.vid,td.weight is not | |
678 // guaranteed to be unique, so we add tn.tid as an additional sort key | |
679 // because tn.tid,tn.vid is the primary key of the D6 term_node table | |
680 // and so is guaranteed unique. Unfortunately it also happens to be in | |
681 // the wrong order which is less efficient, but c'est la vie. | |
682 $query->orderBy('tn.vid'); | |
683 $query->orderBy('td.weight'); | |
684 $query->orderBy('tn.tid'); | |
685 | |
686 // Work around a bug in the PostgreSQL driver that would result in fatal | |
687 // errors when this subquery is used in the insert query below. See | |
688 // https://drupal.org/node/2057693. | |
689 $fields = &$query->getFields(); | |
690 unset($fields['td.weight']); | |
691 unset($fields['tn.tid']); | |
692 | |
693 db_insert('taxonomy_update_7005') | |
694 ->from($query) | |
695 ->execute(); | |
696 } | |
697 else { | |
698 // We do each pass in batches of 1000. | |
699 $batch = 1000; | |
700 | |
701 $result = db_query_range('SELECT vocab_id, tid, nid, vid, type, created, sticky, is_current FROM {taxonomy_update_7005} ORDER BY n', $sandbox['last'], $batch); | |
702 if (isset($sandbox['cursor'])) { | |
703 $values = $sandbox['cursor']['values']; | |
704 $deltas = $sandbox['cursor']['deltas']; | |
705 } | |
706 else { | |
707 $deltas = array(); | |
708 } | |
709 foreach ($result as $record) { | |
710 $sandbox['count'] += 1; | |
711 | |
712 // Use the valid field for this vocabulary and node type or use the | |
713 // overflow vocabulary if there is no valid field. | |
714 $field_name = isset($sandbox['vocabularies'][$record->vocab_id][$record->type]) ? $sandbox['vocabularies'][$record->vocab_id][$record->type] : 'taxonomyextra'; | |
715 $field = $field_info[$field_name]; | |
716 | |
717 // Start deltas from 0, and increment by one for each term attached to a | |
718 // node. | |
719 if (!isset($deltas[$field_name])) { | |
720 $deltas[$field_name] = 0; | |
721 } | |
722 | |
723 if (isset($values)) { | |
724 | |
725 // If the last inserted revision_id is the same as the current record, | |
726 // use the previous deltas to calculate the next delta. | |
727 if ($record->vid == $values[2]) { | |
728 | |
729 // For limited cardinality fields, the delta must not be allowed to | |
730 // exceed the cardinality during the update. So ensure that the | |
731 // delta about to be inserted is within this limit. | |
732 // @see field_default_validate(). | |
733 if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED && ($deltas[$field_name] + 1) > $field['cardinality']) { | |
734 | |
735 // For excess values of a single-term vocabulary, switch over to | |
736 // the overflow field. | |
737 $field_name = 'taxonomyextra'; | |
738 $field = $field_info[$field_name]; | |
739 if (!isset($deltas[$field_name])) { | |
740 $deltas[$field_name] = 0; | |
741 } | |
742 } | |
743 } | |
744 else { | |
745 | |
746 // When the record is a new revision, empty the deltas array. | |
747 $deltas = array($field_name => 0); | |
748 } | |
749 } | |
750 | |
751 // Table and column found in the field's storage details. During upgrades, | |
752 // it's always SQL. | |
753 $table_name = "field_data_{$field_name}"; | |
754 $revision_name = "field_revision_{$field_name}"; | |
755 $value_column = $field_name . '_tid'; | |
756 | |
757 // Column names and values in field storage are the same for current and | |
758 // revision. | |
759 $columns = array('entity_type', 'entity_id', 'revision_id', 'bundle', 'language', 'delta', $value_column); | |
760 $values = array('node', $record->nid, $record->vid, $record->type, LANGUAGE_NONE, $deltas[$field_name]++, $record->tid); | |
761 | |
762 // Insert rows into the revision table. | |
763 db_insert($revision_name)->fields($columns)->values($values)->execute(); | |
764 | |
765 // is_current column is a node ID if this revision is also current. | |
766 if ($record->is_current) { | |
767 db_insert($table_name)->fields($columns)->values($values)->execute(); | |
768 | |
769 // Update the {taxonomy_index} table. | |
770 db_insert('taxonomy_index') | |
771 ->fields(array('nid', 'tid', 'sticky', 'created',)) | |
772 ->values(array($record->nid, $record->tid, $record->sticky, $record->created)) | |
773 ->execute(); | |
774 } | |
775 } | |
776 | |
777 // Store the set of inserted values and the current revision's deltas in the | |
778 // sandbox. | |
779 $sandbox['cursor'] = array( | |
780 'values' => $values, | |
781 'deltas' => $deltas, | |
782 ); | |
783 $sandbox['last'] += $batch; | |
784 } | |
785 | |
786 if ($sandbox['count'] < $sandbox['total']) { | |
787 $sandbox['#finished'] = FALSE; | |
788 } | |
789 else { | |
790 db_drop_table('taxonomy_vocabulary_node_type'); | |
791 db_drop_table('taxonomy_term_node'); | |
792 | |
793 // If there are no vocabs, we're done. | |
794 db_drop_table('taxonomy_update_7005'); | |
795 $sandbox['#finished'] = TRUE; | |
796 | |
797 // Determine necessity of taxonomyextras field. | |
798 $field = $field_info['taxonomyextra']; | |
799 $revision_name = 'field_revision_' . $field['field_name']; | |
800 $node_types = db_select($revision_name)->distinct()->fields($revision_name, array('bundle')) | |
801 ->execute()->fetchCol(); | |
802 | |
803 if (empty($node_types)) { | |
804 // Delete the overflow field if there are no rows in the revision table. | |
805 _update_7000_field_delete_field('taxonomyextra'); | |
806 } | |
807 else { | |
808 // Remove instances which are not actually used. | |
809 $bundles = db_query('SELECT bundle FROM {field_config_instance} WHERE field_name = :field_name', array(':field_name' => 'taxonomyextra'))->fetchCol(); | |
810 $bundles = array_diff($bundles, $node_types); | |
811 foreach ($bundles as $bundle) { | |
812 _update_7000_field_delete_instance('taxonomyextra', 'node', $bundle); | |
813 } | |
814 } | |
815 } | |
816 } | |
817 | |
818 /** | |
819 * Add {taxonomy_term_data}.format column. | |
820 */ | |
821 function taxonomy_update_7006() { | |
822 db_add_field('taxonomy_term_data', 'format', array( | |
823 'type' => 'int', | |
824 'unsigned' => TRUE, | |
825 'not null' => FALSE, | |
826 'description' => 'The {filter_format}.format of the description.', | |
827 )); | |
828 } | |
829 | |
830 /** | |
831 * Add index on {taxonomy_term_data}.name column to speed up taxonomy_get_term_by_name(). | |
832 */ | |
833 function taxonomy_update_7007() { | |
834 db_add_index('taxonomy_term_data', 'name', array('name')); | |
835 } | |
836 | |
837 /** | |
838 * Change the weight columns to normal int. | |
839 */ | |
840 function taxonomy_update_7008() { | |
841 db_drop_index('taxonomy_term_data', 'taxonomy_tree'); | |
842 db_change_field('taxonomy_term_data', 'weight', 'weight', array( | |
843 'type' => 'int', | |
844 'not null' => TRUE, | |
845 'default' => 0, | |
846 'description' => 'The weight of this term in relation to other terms.', | |
847 ), array( | |
848 'indexes' => array( | |
849 'taxonomy_tree' => array('vid', 'weight', 'name'), | |
850 ), | |
851 )); | |
852 | |
853 db_drop_index('taxonomy_vocabulary', 'list'); | |
854 db_change_field('taxonomy_vocabulary', 'weight', 'weight', array( | |
855 'type' => 'int', | |
856 'not null' => TRUE, | |
857 'default' => 0, | |
858 'description' => 'The weight of this vocabulary in relation to other vocabularies.', | |
859 ), array( | |
860 'indexes' => array( | |
861 'list' => array('weight', 'name'), | |
862 ), | |
863 )); | |
864 } | |
865 | |
866 /** | |
867 * Change {taxonomy_term_data}.format into varchar. | |
868 */ | |
869 function taxonomy_update_7009() { | |
870 db_change_field('taxonomy_term_data', 'format', 'format', array( | |
871 'type' => 'varchar', | |
872 'length' => 255, | |
873 'not null' => FALSE, | |
874 'description' => 'The {filter_format}.format of the description.', | |
875 )); | |
876 } | |
877 | |
878 /** | |
879 * Change {taxonomy_index}.created to support signed int. | |
880 */ | |
881 function taxonomy_update_7010() { | |
882 db_change_field('taxonomy_index', 'created', 'created', array( | |
883 'description' => 'The Unix timestamp when the node was created.', | |
884 'type' => 'int', | |
885 'unsigned' => FALSE, | |
886 'not null' => TRUE, | |
887 'default'=> 0, | |
888 )); | |
889 } | |
890 |