Projet

Général

Profil

Paste
Télécharger (21,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / field_collection / field_collection.install @ 5e632cae

1
<?php
2

    
3
/**
4
 * @file
5
 * Install, update and uninstall functions for the field_collection module.
6
 */
7

    
8
/**
9
 * Implements hook_schema().
10
 */
11
function field_collection_schema() {
12

    
13
  $schema['field_collection_item'] = array(
14
    'description' => 'Stores information about field collection items.',
15
    'fields' => array(
16
      'item_id' => array(
17
        'type' => 'serial',
18
        'not null' => TRUE,
19
        'description' => 'Primary Key: Unique field collection item ID.',
20
      ),
21
      'revision_id' => array(
22
        'type' => 'int',
23
        'not null' => TRUE,
24
        'description' => 'Default revision ID.',
25
      ),
26
      'field_name' => array(
27
        'description' => 'The name of the field on the host entity embedding this entity.',
28
        'type' => 'varchar',
29
        'length' => 32,
30
        'not null' => TRUE,
31
      ),
32
      'archived' => array(
33
        'description' => 'Boolean indicating whether the field collection item is archived.',
34
        'type' => 'int',
35
        'not null' => TRUE,
36
        'default' => 0,
37
      ),
38
    ),
39
    'primary key' => array('item_id'),
40
  );
41
  $schema['field_collection_item_revision'] = array(
42
    'description' => 'Stores revision information about field collection items.',
43
    'fields' => array(
44
      'revision_id' => array(
45
        'type' => 'serial',
46
        'not null' => TRUE,
47
        'description' => 'Primary Key: Unique revision ID.',
48
      ),
49
      'item_id' => array(
50
        'type' => 'int',
51
        'not null' => TRUE,
52
        'description' => 'Field collection item ID.',
53
      ),
54
    ),
55
    'primary key' => array('revision_id'),
56
    'indexes' => array(
57
      'item_id' => array('item_id'),
58
    ),
59
    'foreign keys' => array(
60
      'versioned_field_collection_item' => array(
61
        'table' => 'field_collection_item',
62
        'columns' => array('item_id' => 'item_id'),
63
      ),
64
    ),
65
  );
66

    
67
  if (module_exists('entitycache')) {
68
    $schema['cache_entity_field_collection_item'] = drupal_get_schema_unprocessed('system', 'cache');
69
    $schema['cache_entity_field_collection_item']['description'] = 'Cache table used to store field_collection_item entity records.';
70
  }
71
  
72
  return $schema;
73
}
74

    
75
/**
76
 * Implements hook_field_schema().
77
 */
78
function field_collection_field_schema($field) {
79
  $columns = array(
80
    'value' => array(
81
      'type' => 'int',
82
      'not null' => FALSE,
83
      'description' => 'The field collection item id.',
84
    ),
85
    'revision_id' => array(
86
      'type' => 'int',
87
      'not null' => FALSE,
88
      'description' => 'The field collection item revision id.',
89
    ),
90
  );
91
  return array(
92
    'columns' => $columns,
93
    'indexes' => array(
94
      'value' => array('value'),
95
      'revision_id' => array('revision_id'),
96
    ),
97
  );
98
}
99

    
100
/**
101
 * Update the administer field collection permission machine name.
102
 */
103
function field_collection_update_7000() {
104
  db_update('role_permission')
105
    ->fields(array('permission' => 'administer field collections'))
106
    ->condition('permission', 'administer field-collections')
107
    ->execute();
108
}
109

    
110
/**
111
 * Add revision support.
112
 */
113
function field_collection_update_7001() {
114

    
115
  // Add revision_id column to field_collection_item table.
116
  $revision_id_spec = array(
117
    'type' => 'int',
118
    'not null' => TRUE,
119
    'description' => 'Default revision ID.',
120
    // Set default to 0 temporarily.
121
    'initial' => 0,
122
  );
123
  // Field may already exist due to bug in 7.x-1.0-beta5.
124
  if (!db_field_exists('field_collection_item', 'revision_id')) {
125
    db_add_field('field_collection_item', 'revision_id', $revision_id_spec);
126
  }
127

    
128
  // Initialize the revision_id to be the same as the item_id.
129
  db_update('field_collection_item')
130
    ->expression('revision_id', 'item_id')
131
    ->execute();
132

    
133
  // Add the archived column.
134
  $archived_spec = array(
135
    'description' => 'Boolean indicating whether the field collection item is archived.',
136
    'type' => 'int',
137
    'not null' => TRUE,
138
    'default' => 0,
139
  );
140
  // Field may already exist due to bug in 7.x-1.0-beta5.
141
  if (!db_field_exists('field_collection_item', 'archived')) {
142
    db_add_field('field_collection_item', 'archived', $archived_spec);
143
  }
144

    
145
  // Create the new table. It is important to explicitly define the schema here
146
  // rather than use the hook_schema definition: http://drupal.org/node/150220.
147
  $schema['field_collection_item_revision'] = array(
148
    'description' => 'Stores revision information about field collection items.',
149
    'fields' => array(
150
      'revision_id' => array(
151
        'type' => 'serial',
152
        'not null' => TRUE,
153
        'description' => 'Primary Key: Unique revision ID.',
154
      ),
155
      'item_id' => array(
156
        'type' => 'int',
157
        'not null' => TRUE,
158
        'description' => 'Field collection item ID.',
159
      ),
160
    ),
161
    'primary key' => array('revision_id'),
162
    'indexes' => array(
163
      'item_id' => array('item_id'),
164
    ),
165
    'foreign keys' => array(
166
      'versioned_field_collection_item' => array(
167
        'table' => 'field_collection_item',
168
        'columns' => array('item_id' => 'item_id'),
169
      ),
170
    ),
171
  );
172
  // Table may already exist due to bug in 7.x-1.0-beta5.
173
  if (db_table_exists('field_collection_item_revision')) {
174
    db_drop_table('field_collection_item_revision');
175
  }
176
  db_create_table('field_collection_item_revision', $schema['field_collection_item_revision']);
177

    
178
  // Fill the new table with the correct data.
179
  $items = db_select('field_collection_item', 'fci')
180
    ->fields('fci')
181
    ->execute();
182
  foreach ($items as $item) {
183
    // Update field_collection_item_revision table.
184
    db_insert('field_collection_item_revision')
185
      ->fields(array(
186
        'revision_id' => $item->item_id,
187
        'item_id' => $item->item_id,
188
      ))
189
      ->execute();
190
  }
191

    
192
  // Update the field_collection_field_schema columns for all tables.
193
  // Add a revision_id column.
194
  $revision_id_spec['description'] = 'The field collection item revision id.';
195
  // Because $value_column below can be null, so must $revision_id_column.
196
  $revision_id_spec['not null'] = FALSE;
197
  foreach (field_read_fields(array('type' => 'field_collection')) as $field_name => $field) {
198
    $table_prefixes = array('field_data', 'field_revision');
199
    foreach ($table_prefixes as $table_prefix) {
200

    
201
      $table = sprintf('%s_%s', $table_prefix, $field_name);
202
      $value_column = sprintf('%s_value', $field_name);
203
      $revision_id_column = sprintf('%s_revision_id', $field_name);
204

    
205
      // Field may already exist due to bug in 7.x-1.0-beta5.
206
      if (!db_field_exists($table, $revision_id_column)) {
207
        db_add_field($table, $revision_id_column, $revision_id_spec);
208
      }
209
      else {
210
        db_change_field($table, $revision_id_column, $revision_id_column, $revision_id_spec);
211
      }
212

    
213
      // Initialize the revision_id to be the same as the item_id.
214
      db_update($table)
215
        ->expression($revision_id_column, $value_column)
216
        ->execute();
217
    }
218
  }
219

    
220
  // Need to get the system up-to-date so drupal_schema_fields_sql() will work.
221
  $schema = drupal_get_schema('field_collection_item_revision', TRUE);
222
}
223

    
224
/**
225
 * Remove orphaned field collection item entities.
226
 */
227
function field_collection_update_7002() {
228
  // Loop over all fields and delete any orphaned field collection items.
229
  foreach (field_read_fields(array('type' => 'field_collection')) as $field_name => $field) {
230

    
231
    $select = db_select('field_collection_item', 'fci')
232
      ->fields('fci', array('item_id'))
233
      ->condition('field_name', $field_name)
234
      ->condition('archived', 0);
235
    $select->leftJoin('field_data_' . $field_name, 'field', "field.{$field_name}_value = fci.item_id ");
236
    $select->isNull('field.entity_id');
237
    $ids = $select->execute()->fetchCol();
238

    
239
    entity_delete_multiple('field_collection_item', $ids);
240
    drupal_set_message(t('Deleted @count orphaned field collection items.', array('@count' => count($ids))));
241
  }
242
}
243

    
244
/**
245
 * Update field_collection_field_schema columns for all tables.
246
 */
247
function field_collection_update_7003() {
248
  // Revision_id column.
249
  $revision_id_spec = array(
250
    'type' => 'int',
251
    'not null' => FALSE,
252
    'description' => 'The field collection item revision id.',
253
    'initial' => 0,
254
  );
255

    
256
  // Update the field_collection_field_schema columns for all tables,
257
  // in case the buggy beta5 version of field_collection_update_7001()
258
  // completed without complaint.
259
  foreach (field_read_fields(array('type' => 'field_collection')) as $field_name => $field) {
260
    $table_prefixes = array('field_data', 'field_revision');
261
    foreach ($table_prefixes as $table_prefix) {
262
      $table = sprintf('%s_%s', $table_prefix, $field_name);
263
      $value_column = sprintf('%s_value', $field_name);
264
      $revision_id_column = sprintf('%s_revision_id', $field_name);
265
      db_change_field($table, $revision_id_column, $revision_id_column, $revision_id_spec);
266
    }
267
  }
268

    
269
  // Need to get the system up-to-date so drupal_schema_fields_sql() will work.
270
  $schema = drupal_get_schema('field_collection_item_revision', TRUE);
271
}
272

    
273
/**
274
 * Add index on {$field_collection_field}_revision_id column for all tables.
275
 */
276
function field_collection_update_7004() {
277
  // Update the field_collection_field_schema columns for all tables.
278
  foreach (field_read_fields(array('type' => 'field_collection')) as $field_name => $field) {
279
    $table_prefixes = array('field_data', 'field_revision');
280
    foreach ($table_prefixes as $table_prefix) {
281

    
282
      $table = sprintf('%s_%s', $table_prefix, $field_name);
283
      $revision_id_column = sprintf('%s_revision_id', $field_name);
284

    
285
      // Add index on revision_id column.
286
      if (!db_index_exists($table, $revision_id_column)) {
287
        db_add_index($table, $revision_id_column, array($revision_id_column));
288
      }
289
    }
290
  }
291
}
292

    
293
/**
294
 * Force the creation of the table cache_entity_field_collection_item.
295
 *
296
 * entity_update_7003 will attempt to install entitycache tables for existing
297
 * modules, but it uses module_list() to get the list of available modules,
298
 * which, when called from a database update, may not return field_collection
299
 * since drupal is bootstrapped at a lower level.
300
 */
301
function field_collection_update_7005() {
302
  if (module_exists('entitycache')) {
303
    $entity_type = 'field_collection_item';
304
    $table = 'cache_entity_' . $entity_type;
305
    if (!db_table_exists($table)) {
306
      $schema = drupal_get_schema_unprocessed('system', 'cache');
307
      $schema['description'] = 'Cache table used to store' . $entity_type . ' entity records.';
308
      db_create_table($table, $schema);
309
    }
310
  }
311
}
312

    
313
/**
314
 * Ensures revision_id indexes are present at field_config table.
315
 */
316
function field_collection_update_7006() {
317
  $result = db_query("SELECT id, field_name, data FROM {field_config} WHERE type = 'field_collection'");
318
  foreach ($result as $field_config) {
319
    $data = unserialize($field_config->data);
320
    // Skip this record if the revision_id index is already present.
321
    if (isset($data['indexes']['revision_id'])) {
322
      continue;
323
    }
324
    // Otherwise, add the revision_id index and update the record.
325
    $data['indexes']['revision_id'] = array('revision_id');
326
    $data = serialize($data);
327
    $num_updated = db_update('field_config')
328
      ->fields(array('data' => $data))
329
      ->condition('id', $field_config->id)
330
      ->execute();
331
    // If for some reason the update failed, throw an exception.
332
    if ($num_updated != 1) {
333
      $t_args['@field'] = $field_config->field_name;
334
      throw new DrupalUpdateException(t('An error was detected when attempting to update field configuration for field @field.', $t_args));
335
    }
336
  }
337
}
338

    
339
/**
340
 * Add index on {$field_collection_field}_value column for all tables.
341
 */
342
function field_collection_update_7007() {
343
  foreach (field_read_fields(array('type' => 'field_collection')) as $field_name => $field) {
344
    if (!isset($field['indexes']['value'])) {
345
      // Add index on the value column and update the field.
346
      $field['indexes']['value'] = array('value');
347
      field_update_field($field);
348
    }
349

    
350
    $table_prefixes = array('field_data', 'field_revision');
351
    foreach ($table_prefixes as $table_prefix) {
352
      $table = "{$table_prefix}_{$field_name}";
353
      $value_column = "{$field_name}_value";
354
      if (!db_index_exists($table, $value_column)) {
355
        // Add index on the value column.
356
        db_add_index($table, $value_column, array($value_column));
357
      }
358
    }
359
  }
360
}
361

    
362
/**
363
 * Update fields in field collections already set to use Entity Translation.
364
 */
365
function field_collection_update_7008() {
366
  // Include FieldCollectionItemEntity class.
367
  module_load_include('inc', 'field_collection', 'field_collection.entity');
368

    
369
  $results = array();
370
  foreach (field_info_fields() as $f_name => $field) {
371
    if ($field['translatable'] == 1 && isset($field['bundles']['field_collection_item'])) {
372
      $query = new EntityFieldQuery();
373
      $query->entityCondition('entity_type', 'field_collection_item')
374
        ->fieldLanguageCondition($f_name, LANGUAGE_NONE);
375
      $query_result = $query->execute();
376
      if (isset($query_result['field_collection_item'])) {
377
        $results += $query_result['field_collection_item'];
378
      }
379
    }
380
  }
381
  if (count($results)) {
382
    $orphans = array();
383
    $ids = array_keys($results);
384
    $field_collection_items = entity_load('field_collection_item', $ids);
385
    foreach ($field_collection_items as $item) {
386
      /** @var FieldCollectionItemEntity $item */
387
      if ($item->hostEntity()) {
388
        $item->copyTranslations(LANGUAGE_NONE);
389
        $item->save(TRUE);
390
      }
391
      else {
392
        $orphans[] = $item->identifier();
393
      }
394
    }
395
    if ($orphans) {
396
      $count = count($orphans);
397
      entity_delete_multiple('field_collection_item', $orphans);
398
      drupal_set_message("Deleted $count orphaned field collection items.");
399
    }
400
  }
401
}
402

    
403
/**
404
 * Update revisions created before revision support was implemented.
405
 */
406
function field_collection_update_7009(&$sandbox) {
407
  $items_per_pass = 10;
408
  $field_collection_fields = field_read_fields(array('type' => 'field_collection'));
409

    
410
  // If you don't have any field_collecton fields then skip this update.
411
  if (empty($field_collection_fields)) {
412
    return;
413
  }
414

    
415
  if (!isset($sandbox['current_field'])) {
416
    $sandbox['field_collection_fields'] = array_keys($field_collection_fields);
417
    $sandbox['current_field'] = 0;
418
    $sandbox['current_field_collection_item'] = 0;
419
    $sandbox['field_name'] = $sandbox['field_collection_fields'][$sandbox['current_field']];
420
    $sandbox['inner_fields'] = field_read_instances(array('entity_type' => 'field_collection_item', 'bundle' => $sandbox['field_name']));
421
  }
422

    
423
  // Find field collection items with duplicate revision ids.
424
  $query = db_select("field_revision_{$sandbox['field_name']}", 't')
425
    ->fields('t', array("{$sandbox['field_name']}_revision_id"))
426
    ->range($sandbox['current_field_collection_item'], $items_per_pass)
427
    ->groupBy("t.{$sandbox['field_name']}_revision_id");
428
  $query->having("COUNT(t.{$sandbox['field_name']}_revision_id) >= 2");
429
  $vids = $query->execute()->fetchCol();
430

    
431
  // Each revision ID that occurs more than once.
432
  foreach ($vids as $field_collection_duplicated_revision_id) {
433
    // Find every instance of this revision ID.
434
    $copies = db_select("field_revision_{$sandbox['field_name']}", 't')
435
      ->fields('t')
436
      ->condition("{$sandbox['field_name']}_revision_id", $field_collection_duplicated_revision_id)
437
      ->execute()
438
      ->fetchAllAssoc('revision_id');
439

    
440
    $first_copy = reset($copies);
441
    $field_collection_item_id = $first_copy->{"{$sandbox['field_name']}_value"};
442

    
443
    // Find the currently used revision of this field collection item.
444
    $field_collection_item_current_revision = db_select('field_collection_item', 'fci')
445
      ->fields('fci', array('revision_id'))
446
      ->condition('item_id', $field_collection_item_id)
447
      ->execute()
448
      ->fetchField();
449

    
450
    // Find new revisions of this field collection item that were made after
451
    // revisions were enabled in update_7003.
452
    $modern_revisions = db_select("field_revision_{$sandbox['field_name']}", 't')
453
      ->fields('t')
454
      ->condition("{$sandbox['field_name']}_revision_id", $field_collection_duplicated_revision_id, '<>')
455
      ->condition("{$sandbox['field_name']}_value", $field_collection_item_id)
456
      ->orderBy('revision_id')
457
      ->execute()
458
      ->fetchAllAssoc('revision_id');
459

    
460
    // Intentionally skip the first instance as it doesn't need to be modified.
461
    while (FALSE !== ($row_to_replace = next($copies))) {
462
      $new_revision_id = _field_collection_update_7009_new_revision($field_collection_item_id, $row_to_replace, $sandbox['inner_fields'], $sandbox['field_name']);
463

    
464
      // Create copies of inner fields with new revision number.
465
      foreach ($sandbox['inner_fields'] as $field) {
466
        // Get the data to copy.
467
        $data_rows = db_select("field_revision_{$field['field_name']}", 't')
468
          ->fields('t')
469
          ->condition('entity_type', 'field_collection_item')
470
          ->condition('revision_id', $field_collection_duplicated_revision_id)
471
          ->execute();
472

    
473
        // Add new copy of data with new revision id.
474
        while ($each_row = $data_rows->fetchAssoc()) {
475
          $each_row['revision_id'] = $new_revision_id;
476
          db_insert("field_revision_{$field['field_name']}")
477
            ->fields(array_keys($each_row), array_values($each_row))
478
            ->execute();
479
        }
480
      }
481

    
482
      // Update the host's field data with new revision number.
483
      db_update("field_revision_{$sandbox['field_name']}")
484
        ->fields(array("{$sandbox['field_name']}_revision_id" => $new_revision_id))
485
        ->condition('entity_type', $row_to_replace->entity_type)
486
        ->condition('revision_id', $row_to_replace->revision_id)
487
        ->condition('delta', $row_to_replace->delta)
488
        ->condition('language', $row_to_replace->language)
489
        ->execute();
490

    
491
      if ($field_collection_item_current_revision == $field_collection_duplicated_revision_id) {
492
        _field_collection_update_7009_update_data($new_revision_id, $field_collection_duplicated_revision_id);
493

    
494
        // Update the current field collection item data in its host.
495
        db_update("field_data_{$sandbox['field_name']}")
496
          ->fields(array('revision_id' => $new_revision_id))
497
          ->condition('revision_id', $field_collection_duplicated_revision_id)
498
          ->condition('entity_type', $row_to_replace->entity_type)
499
          ->execute();
500
      }
501
    }
502

    
503

    
504

    
505
    foreach ($modern_revisions as $each_modern_revision) {
506
      $new_revision_id = _field_collection_update_7009_new_revision($field_collection_item_id, $each_modern_revision, $sandbox['inner_fields'], $sandbox['field_name']);
507

    
508
      // Update inner fields with new revision number.
509
      foreach ($sandbox['inner_fields'] as $field) {
510
        db_update("field_revision_{$field['field_name']}")
511
          ->fields(array('revision_id' => $new_revision_id))
512
          ->condition('revision_id', $each_modern_revision->{$sandbox['field_name'] . '_revision_id'})
513
          ->condition('entity_type', 'field_collection_item')
514
          ->execute();
515
      }
516

    
517
      // Update the host's field data with new revision number.
518
      db_update("field_revision_{$sandbox['field_name']}")
519
        ->fields(array("{$sandbox['field_name']}_revision_id" => $new_revision_id))
520
        ->condition('entity_type', $each_modern_revision->entity_type)
521
        ->condition('revision_id', $each_modern_revision->revision_id)
522
        ->condition('delta', $each_modern_revision->delta)
523
        ->condition('language', $each_modern_revision->language)
524
        ->execute();
525

    
526
      if ($field_collection_item_current_revision == $each_modern_revision->{"{$sandbox['field_name']}_revision_id"}) {
527
        _field_collection_update_7009_update_data($new_revision_id, $field_collection_item_current_revision);
528

    
529
        // Update the current field collection item data in its host.
530
        db_update("field_data_{$sandbox['field_name']}")
531
          ->fields(array('revision_id' => $new_revision_id))
532
          ->condition('revision_id', $field_collection_item_current_revision)
533
          ->condition('entity_type', $each_modern_revision->entity_type)
534
          ->execute();
535
      }
536

    
537
      // Remove old copy of revision.
538
      db_delete('field_collection_item_revision')
539
        ->condition('revision_id', $each_modern_revision->revision_id)
540
        ->execute();
541
    }
542

    
543
    $sandbox['current_field_collection_item']++;
544
  }
545

    
546
  $sandbox['#finished'] = 0;
547

    
548
  if (count($vids) < $items_per_pass) {
549
    $sandbox['current_field']++;
550
    if ($sandbox['current_field'] == count($sandbox['field_collection_fields'])) {
551
      $sandbox['#finished'] = 1;
552
      return;
553
    }
554
    $sandbox['current_field_collection_item'] = 0;
555
    $sandbox['field_name'] = $sandbox['field_collection_fields'][$sandbox['current_field']];
556
    $sandbox['inner_fields'] = field_read_instances(array('entity_type' => 'field_collection_item', 'bundle' => $sandbox['field_name']));
557
  }
558
}
559

    
560
function _field_collection_update_7009_new_revision($field_collection_item_id, $row_to_replace, $inner_fields, $field_name) {
561
  // Add to field_collection_item_revision table.
562
  $new_revision_id = db_insert('field_collection_item_revision')
563
    ->fields(array('item_id'), array($field_collection_item_id))
564
    ->execute();
565

    
566
  return $new_revision_id;
567
}
568

    
569
function _field_collection_update_7009_update_data($new_revision, $old_revision) {
570
  // Update the current field collection item.
571
  db_update('field_collection_item')
572
    ->fields(array('revision_id' => $new_revision))
573
    ->condition('revision_id', $old_revision)
574
    ->execute();
575
}