Projet

Général

Profil

Révision a1cafe7e

Ajouté par Assos Assos il y a plus de 4 ans

Weekly update of contrib modules

Voir les différences:

drupal7/sites/all/modules/field_collection/README.txt
1
Field collection
2
-----------------
3
Provides a field collection field, to which any number of fields can be attached.
1
CONTENTS OF THIS FILE
2
---------------------
3

  
4
 * Introduction
5
 * Requirements
6
 * Installation
7
 * Configuration
8
 * Using field collection with entity translation
9
 * Maintainers
10

  
11

  
12
INTRODUCTION
13
------------
14

  
15
Provides a field collection field to which any number of fields can be attached.
4 16

  
5 17
Each field collection item is internally represented as an entity, which is
6 18
referenced via the field collection field in the host entity. While
......
8 20
field collection item may also be viewed and edited separately.
9 21

  
10 22

  
11
 Usage
12
 ------
23
REQUIREMENTS
24
------------
25

  
26
This project require the following projects:
27

  
28
 * Entity API (https://www.drupal.org/project/entity)
29

  
13 30

  
14
  * Add a field collection field to any entity, e.g. to a node. For that use the
15
   the usual "Manage fields" interface provided by the "field ui" module of
16
   Drupal, e.g. "Admin -> Structure-> Content types -> Article -> Manage fields".
31
INSTALLATION
32
------------
17 33

  
18
  * Then go to "Admin -> Structure-> Field collection" to define some fields for
34
Install as you would normally install a contributed Drupal. See:
35
https://drupal.org/documentation/install/modules-themes/modules-7 for further
36
information.
37

  
38

  
39
CONFIGURATION
40
-------------
41

  
42
 * Add a field collection field to any entity, e.g. to a node. For that use the
43
   the usual "Manage fields" interface provided by the "field ui" project of
44
   Drupal, e.g "Admin -> Structure -> Content types -> Article -> Manage fields"
45

  
46
 * Then go to "Admin -> Structure-> Field Collection" to define some fields for
19 47
   the created field collection.
20 48

  
21
  * By the default, the field collection is not shown during editing of the host
49
 * By the default, the field collection is not shown during editing of the host
22 50
    entity. However, some links for adding, editing or deleting field collection
23 51
    items is shown when the host entity is viewed.
24 52

  
25
  * Widgets for embedding the form for creating field collections in the
53
 * Widgets for embedding the form for creating field collections in the
26 54
    host-entity can be provided by any module. In future the field collection
27
    module might provide such widgets itself too.
55
    project might provide such widgets itself too.
28 56

  
29 57

  
30
 Using field collection with entity translation
31
 -----------------------------------------------
58
USING FIELD COLLECTION WITH ENTITY TRANSLATION
59
-----------
32 60

  
33
  * Field collection items must be selected as a translatable entity type at
61
  * Field Collection items must be selected as a translatable entity type at
34 62
    Admin -> Config -> Regional -> Entity Translation.
35 63

  
36 64
  * The common use case is to leave the field collection field untranslatable
......
45 73
    language for the host will have a completely separate copy of the field
46 74
    collection item(s).
47 75

  
48
  * When using nested field collections the configuration of the fields and
76
  * When using nested field collections, the configuration of the fields and
49 77
    field collections is very important. The recommended approach is to first
50
    enable entity translation as defined in step 1, and set the outer 
51
    field collection field as translatable, and all it’s sub-fields to language
52
    undefined. Also the sub-field collections and it’s sub-fields should be
78
    enable entity translation as defined in step 1, and set the outer
79
    field collection field as translatable and all its sub-fields to language
80
    undefined. The sub-field collections and its sub-fields should also be
53 81
    set to language undefined. This will ensure that every language of the host
54 82
    will have a completely separate copy of the field collection item(s) and
55
    it’s fields.
83
    its fields.
84

  
85

  
86
MAINTAINERS
87
-----------
88

  
89
Current maintainers:
90
 * Joel Muzzerall (jmuzz) - https://www.drupal.org/user/2607886
91
 * Joel Farris (Senpai) - https://www.drupal.org/user/65470
92
 * Lee Rowlands (larowlan) - https://www.drupal.org/user/395439
93
 * Nedjo Rogers (nedjo) - https://www.drupal.org/user/4481
94
 * Ra Mänd (ram4nd) - https://www.drupal.org/user/601534
95
 * Renato Gonçalves (RenatoG) - https://www.drupal.org/user/3326031
96
 * Wolfgang Ziegler (fago) - https://www.drupal.org/user/16747
drupal7/sites/all/modules/field_collection/ctools/relationships/field_collection_from_field.inc
78 78
  if (isset($entity->{$plugin_info['field_name']})) {
79 79

  
80 80
    $items = field_get_items($plugin_info['entity_type'], $entity, $plugin_info['field_name']);
81

  
82
    // Use negative delta to get item from the end.
83
    if ($delta < 0) {
84
      // Add negative pseudo-delta to total amount of items to get the real
85
      // delta. Example (field_collection with 5 elements): count() == 5:
86
      // 5 + -1 = 4, which would be the last element in this example.
87
      $delta = count($items) + $delta;
88
    }
89

  
81 90
    if (!empty($items) && isset($items[$delta]['value'])) {
82 91
      $field_collection_item = field_collection_item_load($items[$delta]['value']);
83 92
    }
......
98 107
    '#type' => 'textfield',
99 108
    '#title' => t('Delta'),
100 109
    '#size' => 3,
101
    '#description' => t('The relationship can only create one context, but multiple items can be related. Please type in the number you want. The first one will be 0.'),
110
    '#description' => t('The relationship can only create one context, but multiple items can be related. Please type in the number you want. The first one will be 0. Use negative delta to get items from the end. The last item will be -1'),
102 111
    '#default_value' => empty($conf['delta']) ? 0 : $conf['delta'],
103 112
  );
104 113

  
drupal7/sites/all/modules/field_collection/field_collection.api.php
2 2

  
3 3
/**
4 4
 * @file
5
 * Contains API documentation and examples for the Field collection module.
5
 * Contains API documentation and examples for the Field Collection.
6 6
 */
7 7

  
8 8
/**
......
66 66
/**
67 67
 * Acts on a field collection item being inserted or updated.
68 68
 *
69
 * This hook is invoked before the field collection item is saved to the database.
69
 * This hook is invoked before the field collection item is saved to the
70
 * database.
70 71
 *
71 72
 * @param FieldCollectionItemEntity $field_collection_item
72 73
 *   The field collection item that is being inserted or updated.
......
140 141
/**
141 142
 * Alter the results of entity_view() for field collection items.
142 143
 *
143
  * This hook is called after the content has been assembled in a structured
144
 * This hook is called after the content has been assembled in a structured
144 145
 * array and may be used for doing processing which requires that the complete
145 146
 * field collection item content structure has been built.
146 147
 *
drupal7/sites/all/modules/field_collection/field_collection.diff.inc
2 2

  
3 3
/**
4 4
 * @file
5
 * Provide diff field functions for the Field collection module.
5
 * Provide diff field functions for the Field Collection.
6 6
 */
7 7

  
8 8
/**
9
 * Diff field callback for parsing Field collection fields comparative values.
9
 * Diff field callback for parsing Field Collection fields comparative values.
10 10
 */
11 11
function field_collection_field_diff_view($items, $context) {
12 12
  $diff_items = array();
......
25 25
  $view_mode = $context['view_mode'];
26 26
  $entity = entity_revision_load($entity_type, $item['revision_id']);
27 27

  
28
  if(empty($entity)) {
28
  if (empty($entity)) {
29 29
    return array();
30 30
  }
31 31

  
......
40 40
    $field_context['custom_settings'] = FALSE;
41 41
  }
42 42
  $view_mode_settings = field_view_mode_settings($entity_type, $bundle_name);
43
  $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings'])) ? $view_mode : 'default';
43
  $actual_mode = !empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default';
44 44
  if (!isset($field_context['custom_settings'])) {
45 45
    $field_context['custom_settings'] = $actual_mode && $actual_mode == $view_mode;
46 46
  }
......
50 50

  
51 51
  $result = array();
52 52
  foreach ($instances as $instance) {
53
    // Any view mode is supported in relation to hiding fields, but only if selected.
53
    // Any view mode is supported in relation to hiding fields, but only if
54
    // selected.
54 55
    if ($actual_mode && $instance['display'][$actual_mode]['type'] == 'hidden') {
55 56
      continue;
56 57
    }
......
67 68
      $field_context['settings'] = diff_get_field_settings($field_context);
68 69
      $field_context['display'] = $instance['display'][$actual_mode];
69 70

  
71
      $old_items = array();
72
      $new_items = array();
73
      if (!empty($entity->{$field_name}[$langcode])) {
74
        $new_items = $entity->{$field_name}[$langcode];
75
      }
76

  
77
      $func = $field['module'] . '_field_diff_view_prepare';
78
      if (function_exists($func)) {
79
        $func($old_items, $new_items, $field_context);
80
      }
81

  
70 82
      $func = $field['module'] . '_field_diff_view';
71 83
      if (!function_exists($func)) {
72 84
        $func = 'diff_field_diff_view';
73 85
      }
74 86

  
75
      if (!empty($entity->{$field_name}[$langcode])) {
76
        $raw_values = $func($entity->{$field_name}[$langcode], $field_context);
87
      if (!empty($new_items)) {
88
        $raw_values = $func($new_items, $field_context);
77 89
        $values = array();
78 90
        foreach ($raw_values as $raw_value) {
79
          $values[] = is_array($raw_value) ? implode(", ", $raw_value) : $raw_value;
91
          $values[] = is_array($raw_value) ? implode(', ', $raw_value) : $raw_value;
80 92
        }
81 93

  
82
        $result[] = check_plain($instance['label'] . ': ' . implode(", ", $values));
94
        $result[] = check_plain($instance['label'] . ': ' . implode(', ', $values));
83 95
      }
84 96
    }
85 97
  }
drupal7/sites/all/modules/field_collection/field_collection.entity.inc
6 6
class FieldCollectionItemEntity extends Entity {
7 7

  
8 8
  /**
9
   * Field collection field info.
9
   * Field Collection field info.
10 10
   *
11 11
   * @var array
12 12
   */
......
55 55
  public $item_id;
56 56

  
57 57
  /**
58
   * Field collection revision ID.
58
   * Field Collection revision ID.
59 59
   *
60 60
   * @var integer
61 61
   */
......
145 145
      if ($new_label = module_invoke_all('field_collection_item_label', $this, $host, $field, $label)) {
146 146
        return array_pop($new_label);
147 147
      }
148
      elseif ($field['cardinality'] == 1) {
148

  
149
      if ($field['cardinality'] == 1) {
149 150
        return $label;
150 151
      }
151
      elseif ($this->item_id) {
152

  
153
      if ($this->item_id) {
152 154
        return t('!instance_label @count', array('!instance_label' => $label, '@count' => $this->delta() + 1));
153 155
      }
154
      else {
155
        return t('New !instance_label', array('!instance_label' => $label));
156
      }
156

  
157
      return t('New !instance_label', array('!instance_label' => $label));
157 158
    }
158 159
    return t('Unconnected field collection item');
159 160
  }
......
220 221
   *   The entity type of the entity the field collection is attached to.
221 222
   */
222 223
  public function updateHostEntity($entity, $host_entity_type = NULL) {
223
    $this->fetchHostDetails();
224
    $this->fetchHostDetails($entity);
224 225
    // If it isn't possible to retrieve hostEntityType due to the fact that it's
225 226
    // not saved in the DB yet then fill in info about the hostEntity manually.
226 227
    // This happens when creating a new revision of a field collection entity
227 228
    // and it needs to relate to the new revision of the host entity.
228
    if (!$this->hostEntityType) {
229
    if (!$this->hostEntityType || isset($entity->tid)) {
229 230
      $this->hostEntityType = $host_entity_type;
230 231
      $this->hostEntity = $entity;
231 232
      list($this->hostEntityId, $this->hostEntityRevisionId) = entity_extract_ids($this->hostEntityType, $this->hostEntity);
232 233
    }
233 234
    list($recieved_id) = entity_extract_ids($this->hostEntityType, $entity);
234 235

  
235
    if ($this->isInUse() && !empty($this->hostEntityId)) {
236
      $current_id = $this->hostEntityId;
236
    if (!empty($this->hostEntityId) && $this->isInUse()) {
237
      if (is_array($this->hostEntityId)) {
238
        $current_id = in_array($recieved_id, $this->hostEntityId)
239
          ? $recieved_id
240
          : FALSE;
241
      }
242
      else {
243
        $current_id = $this->hostEntityId;
244
      }
237 245
    }
238 246
    else {
239 247
      $current_host = entity_revision_load($this->hostEntityType, $this->hostEntityRevisionId);
240
      list($current_id) = entity_extract_ids($this->hostEntityType, $current_host);
248
      list($current_id) = $current_host ? entity_extract_ids($this->hostEntityType, $current_host) : array($recieved_id);
241 249
    }
242 250

  
243 251
    if ($current_id == $recieved_id) {
......
300 308
    }
301 309
  }
302 310

  
303
  protected function fetchHostDetails() {
311
  /**
312
   * Collects info about the field collection's host.
313
   *
314
   * @param $hostEntity
315
   *   The host entity object. (optional)
316
   */
317
  protected function fetchHostDetails($hostEntity = NULL) {
304 318
    if (!isset($this->hostEntityId) || (!$this->hostEntityId && $this->hostEntityRevisionId)) {
305 319
      if ($this->item_id) {
306 320
        // For saved field collections, query the field data to determine the
307 321
        // right host entity.
308 322
        $query = new EntityFieldQuery();
309
        $query->fieldCondition($this->fieldInfo(), 'revision_id', $this->revision_id);
323
        $field_info = $this->fieldInfo();
324
        $query->fieldCondition($field_info, 'revision_id', $this->revision_id);
325
        if ($hostEntity) {
326
          $entity_type = key($field_info['bundles']);
327
          $bundle = current($field_info['bundles'][$entity_type]);
328
          $entity_info = entity_get_info($entity_type);
329
          $key = $entity_info['entity keys']['id'];
330
          $query->entityCondition('entity_type', $entity_type);
331
          $query->entityCondition('entity_id', $hostEntity->{$key});
332
          $query->entityCondition('bundle', $bundle);
333
          if (isset($entity_info['entity keys']['language'])) {
334
            $query->propertyCondition('language', $hostEntity->language);
335
          }
336
        }
337
        $query->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT');
310 338
        if (!$this->isInUse()) {
311 339
          $query->age(FIELD_LOAD_REVISION);
312 340
        }
......
353 381
              $this->langcode = $langcode;
354 382
              return $delta;
355 383
            }
356
            elseif (isset($item['entity']) && $item['entity'] === $this) {
384

  
385
            if (isset($item['entity']) && $item['entity'] === $this) {
357 386
              $this->langcode = $langcode;
358 387
              return $delta;
359 388
            }
......
370 399
                $this->langcode = $langcode;
371 400
                return $delta;
372 401
              }
373
              elseif (isset($item['entity']) && $item['entity'] === $this) {
402

  
403
              if (isset($item['entity']) && $item['entity'] === $this) {
374 404
                $this->langcode = $langcode;
375 405
                return $delta;
376 406
              }
......
385 415
   * Determines the language code under which the item is stored.
386 416
   */
387 417
  public function langcode() {
388
    if ($this->delta() === NULL || empty($this->langcode)) {
418
    if (empty($this->langcode) || $this->delta() === NULL) {
389 419
      $this->langcode = field_collection_entity_language('field_collection_item', $this);
390 420
    }
391 421

  
......
399 429
  /**
400 430
   * Determines whether this field collection item revision is in use.
401 431
   *
402
   * Field collection items may be contained in from non-default host entity
432
   * Field Collection items may be contained in from non-default host entity
403 433
   * revisions. If the field collection item does not appear in the default
404 434
   * host entity revision, the item is actually not used by default and so
405 435
   * marked as 'archived'.
......
432 462
  public function save($skip_host_save = FALSE) {
433 463
    // Make sure we have a host entity during creation.
434 464
    if (!empty($this->is_new) && !(isset($this->hostEntityId) || isset($this->hostEntity) || isset($this->hostEntityRevisionId))) {
435
      throw new Exception("Unable to create a field collection item without a given host entity.");
465
      throw new Exception('Unable to create a field collection item without a given host entity.');
436 466
    }
437 467

  
438 468
    // Copy the values of translatable fields for a new field collection item.
439
    if (field_collection_item_is_translatable() && !empty($this->is_new) && $this->langcode() == LANGUAGE_NONE) {
469
    if (!empty($this->is_new) && field_collection_item_is_translatable() && $this->langcode() == LANGUAGE_NONE) {
440 470
      $this->copyTranslations();
441 471
    }
442 472

  
......
446 476
    if ($skip_host_save) {
447 477
      return entity_get_controller($this->entityType)->save($this);
448 478
    }
449
    else {
450
      $host_entity = $this->hostEntity();
451
      if (!$host_entity) {
452
        throw new Exception("Unable to save a field collection item without a valid reference to a host entity.");
453
      }
454
      // If this is creating a new revision, also do so for the host entity.
455
      if (!empty($this->revision) || !empty($this->is_new_revision)) {
456
        $host_entity->revision = TRUE;
457
        if (!empty($this->default_revision)) {
458
          entity_revision_set_default($this->hostEntityType, $host_entity);
459
        }
460
      }
461
      // Set the host entity reference, so the item will be saved with the host.
462
      // @see field_collection_field_presave()
463
      $delta = $this->delta();
464
      if (isset($delta)) {
465
        $host_entity->{$this->field_name}[$this->langcode()][$delta] = array('entity' => $this);
466
      }
467
      else {
468
        $host_entity->{$this->field_name}[$this->langcode()][] = array('entity' => $this);
469
      }
470 479

  
471
      return entity_save($this->hostEntityType, $host_entity);
480
    $host_entity = $this->hostEntity();
481
    if (!$host_entity) {
482
      throw new Exception('Unable to save a field collection item without a valid reference to a host entity.');
483
    }
484
    // If this is creating a new revision, also do so for the host entity.
485
    if (!empty($this->revision) || !empty($this->is_new_revision)) {
486
      $host_entity->revision = TRUE;
487
      if (!empty($this->default_revision)) {
488
        entity_revision_set_default($this->hostEntityType, $host_entity);
489
      }
490
    }
491
    // Set the host entity reference, so the item will be saved with the host.
492
    // @see field_collection_field_presave()
493
    $delta = $this->delta();
494
    if (isset($delta)) {
495
      $host_entity->{$this->field_name}[$this->langcode()][$delta] = array('entity' => $this);
472 496
    }
497
    else {
498
      $host_entity->{$this->field_name}[$this->langcode()][] = array('entity' => $this);
499
    }
500

  
501
    return entity_save($this->hostEntityType, $host_entity);
473 502
  }
474 503

  
475 504
  /**
......
510 539
    foreach ($fields_instances as $translatable_field) {
511 540
      if ($fields[$translatable_field]['translatable'] == 1) {
512 541
        foreach ($target_languages as $langcode) {
513
          if (isset($this->{$translatable_field}[$source_language])) {
514
            //Source (translatable_field) is set, therefore continue processing.
515
            if(!isset($this->{$translatable_field}[$langcode])) {
516
              //Destination (translatable_field) is not set, therefore safe to copy the translation.
517
              $this->{$translatable_field}[$langcode] = $this->{$translatable_field}[$source_language];
518
            }
542
          // Source (translatable_field) is set, therefore continue
543
          // processing.
544
          if (isset($this->{$translatable_field}[$source_language])
545
            && !isset($this->{$translatable_field}[$langcode])) {
546
            // Destination (translatable_field) is not set, therefore safe to
547
            // copy the translation.
548
            $this->{$translatable_field}[$langcode] = $this->{$translatable_field}[$source_language];
519 549
          }
520 550
        }
521 551
        if ($source_language == LANGUAGE_NONE && count($this->{$translatable_field}) > 1) {
......
580 610
        entity_get_controller('field_collection_item')->resetCache(array($this->item_id));
581 611
        entity_revision_delete('field_collection_item', $this->revision_id);
582 612
      }
583
      if (!$row && !isset($this->hostEntity()->{$this->field_name}[$this->langcode()][$this->delta()])) {
613
      else {
584 614
        // Delete if there is no existing revision or translation to be saved.
585 615
        $this->delete($skip_host_update);
586 616
      }
......
630 660
    return drupal_map_assoc(array_keys($vars));
631 661
  }
632 662

  
633
  /**
634
   * Magic method to invoke setUp() on unserialization.
635
   *
636
   * @todo: Remove this once it appears in a released entity API module version.
637
   */
638
  public function __wakeup() {
639
    $this->setUp();
640
  }
641 663
}
drupal7/sites/all/modules/field_collection/field_collection.info
1
name = Field collection
1
name = Field Collection
2 2
description = Provides a field collection field, to which any number of fields can be attached.
3 3
core = 7.x
4 4
dependencies[] = entity
......
12 12
configure = admin/structure/field-collections
13 13
package = Fields
14 14

  
15
; Information added by Drupal.org packaging script on 2019-01-25
16
version = "7.x-1.0-beta13"
15
; Information added by Drupal.org packaging script on 2019-09-03
16
version = "7.x-1.1"
17 17
core = "7.x"
18 18
project = "field_collection"
19
datestamp = "1548457085"
19
datestamp = "1567537827"
drupal7/sites/all/modules/field_collection/field_collection.info.inc
24 24
      'required' => TRUE,
25 25
    );
26 26

  
27
    // Also add type-specific host entity references for all entity types that
28
    // have at least one field collection field.
29
    $field_collection_fields = field_read_fields(array('type' => 'field_collection'));
30
    $entity_types = entity_get_info();
31
    foreach (field_info_instances() as $entity_type => $bundles) {
32
      foreach ($bundles as $bundle => $fields) {
33
        if (array_intersect_key($fields, $field_collection_fields)) {
34
          $args = array('@type' => $entity_types[$entity_type]['label']);
35
          $properties["host_entity_$entity_type"] = array(
36
            'label' => t('Host entity (@type)', $args),
37
            'type' => $entity_type,
38
            'description' => t('The @type containing the field collection field (empty if this field collection is attached to an item of a different type).', $args),
39
            'getter callback' => 'field_collection_item_get_specific_type_host_entity',
40
            'computed' => TRUE,
41
          );
42
          break;
43
        }
44
      }
45
    }
46

  
27 47
    return $info;
28 48
  }
29 49

  
drupal7/sites/all/modules/field_collection/field_collection.install
63 63
      ),
64 64
    ),
65 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
  
66 72
  return $schema;
67 73
}
68 74

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

  
233 239
    entity_delete_multiple('field_collection_item', $ids);
234 240
    drupal_set_message(t('Deleted @count orphaned field collection items.', array('@count' => count($ids))));
......
368 374
        ->fieldLanguageCondition($f_name, LANGUAGE_NONE);
369 375
      $query_result = $query->execute();
370 376
      if (isset($query_result['field_collection_item'])) {
371
        $results = $results + $query_result['field_collection_item'];
377
        $results += $query_result['field_collection_item'];
372 378
      }
373 379
    }
374 380
  }
......
393 399
    }
394 400
  }
395 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->addExpression("COUNT(t.{$sandbox['field_name']}_revision_id)", 'vidcount');
429
  $query->havingCondition('vidcount', 2, '>=');
430
  $vids = $query->execute()->fetchCol();
431

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

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

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

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

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

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

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

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

  
493
    if ($field_collection_item_current_revision == $field_collection_duplicated_revision_id) {
494
      _field_collection_update_7009_update_data($new_revision_id, $field_collection_duplicated_revision_id);
495

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

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

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

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

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

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

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

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

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

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

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

  
565
  return $new_revision_id;
566
}
567

  
568
function _field_collection_update_7009_update_data($new_revision, $old_revision) {
569
  // Update the current field collection item.
570
  db_update('field_collection_item')
571
    ->fields(array('revision_id' => $new_revision))
572
    ->condition('revision_id', $old_revision)
573
    ->execute();
574
}
drupal7/sites/all/modules/field_collection/field_collection.migrate.inc
83 83
  /**
84 84
   * Import a single field collection item.
85 85
   *
86
   * @param $collection
86
   * @param \stdClass $collection
87 87
   *   Collection object to build. Pre-filled with any fields mapped in the
88 88
   *   migration.
89
   * @param $row
89
   * @param \stdClass $row
90 90
   *   Raw source data object - passed through to prepare/complete handlers.
91 91
   *
92 92
   * @return array|bool
......
139 139
        if ('field_' != substr($field, 0, 6)) {
140 140
          continue;
141 141
        }
142
        elseif (property_exists($entity_old, $field) && !property_exists($collection, $field)) {
142

  
143
        if (property_exists($entity_old, $field) && !property_exists($collection, $field)) {
143 144
          $entity->$field = $entity_old->$field;
144 145
        }
145 146
      }
......
149 150
    $status = entity_save('field_collection_item', $entity);
150 151
    migrate_instrument_stop('field_collection_save');
151 152

  
152
    if (in_array($this->hostEntityType, array('node', 'field_collection_item')) || ($status !== FALSE)) {
153
    if ($status !== FALSE || in_array($this->hostEntityType, array('node', 'field_collection_item'))) {
153 154
      $this->complete($entity, $row);
154 155
      if ($updating) {
155 156
        $this->numUpdated++;
......
159 160
      }
160 161
      return array($entity->item_id);
161 162
    }
162
    else {
163
      return FALSE;
164
    }
163

  
164
    return FALSE;
165 165
  }
166 166

  
167 167
  /**
drupal7/sites/all/modules/field_collection/field_collection.module
184 184
 * Loads a field collection revision.
185 185
 *
186 186
 * @param $revision_id
187
 *   The field collection revision ID.
187
 *   The id of the revision to load.
188
 *
189
 * @return
190
 *   The entity object, or FALSE if there is no entity with the given revision
191
 *   id.
188 192
 */
189 193
function field_collection_item_revision_load($revision_id) {
190 194
  return entity_revision_load('field_collection_item', $revision_id);
......
193 197
/**
194 198
 * Loads field collection items.
195 199
 *
200
 * @param $ids
201
 *   An array of entity IDs, or FALSE to load all entities.
202
 * @param $conditions
203
 *   (deprecated) An associative array of conditions on the base table, where
204
 *   the keys are the database fields and the values are the values those
205
 *   fields must have. Instead, it is preferable to use EntityFieldQuery to
206
 *   retrieve a list of entity IDs loadable by this function.
207
 * @param $reset
208
 *   Whether to reset the internal cache for the requested entity type.
209
 *
196 210
 * @return
197 211
 *   An array of field collection item entities.
198 212
 */
......
220 234
  foreach (field_info_fields() as $field) {
221 235
    if ($field['type'] == 'field_collection') {
222 236
      $path = field_collection_field_get_path($field);
223
      $count = count(explode('/', $path));
237
      $count = substr_count($path, '/') + 1;
224 238

  
225 239
      $items[$path . '/%field_collection_item'] = array(
226 240
        'page callback' => 'field_collection_item_page_view',
......
280 294
 * Implements hook_menu_alter() to fix the field collections admin UI tabs.
281 295
 */
282 296
function field_collection_menu_alter(&$items) {
283
  if (module_exists('field_ui') && isset($items['admin/structure/field-collections/%field_collection_field_name/fields'])) {
297
  if (isset($items['admin/structure/field-collections/%field_collection_field_name/fields']) && module_exists('field_ui')) {
284 298
    // Make the fields task the default local task.
285 299
    $items['admin/structure/field-collections/%field_collection_field_name'] = $items['admin/structure/field-collections/%field_collection_field_name/fields'];
286 300
    $item = &$items['admin/structure/field-collections/%field_collection_field_name'];
......
299 313

  
300 314
/**
301 315
 * Menu title callback.
316
 *
317
 * return string
302 318
 */
303 319
function field_collection_admin_page_title($field_name) {
304 320
  return t('Field collection @field_name', array('@field_name' => $field_name));
......
306 322

  
307 323
/**
308 324
 * Implements hook_admin_paths().
325
 *
326
 * @return array
309 327
 */
310 328
function field_collection_admin_paths() {
311 329
  if (variable_get('node_admin_theme')) {
......
326 344
      'title' => t('Administer field collections'),
327 345
      'description' => t('Create and delete fields on field collections.'),
328 346
    ),
347
    'edit field collections' => array(
348
      'title' => t('Edit field collections'),
349
      'description' => t('Edit field collections.'),
350
    ),
329 351
  );
330 352
}
331 353

  
......
339 361
 *   items is determined.
340 362
 * @param $account
341 363
 *   The user to check for. Leave it to NULL to check for the global user.
364
 *
342 365
 * @return boolean
343 366
 *   Whether access is allowed or not.
344 367
 */
......
346 369
  // We do not support editing field collection revisions that are not used at
347 370
  // the hosts default revision as saving the host might result in a new default
348 371
  // revision.
349
  if (isset($item) && !$item->isInUse() && $op != 'view') {
372
  if ($op != 'view' && isset($item) && !$item->isInUse()) {
350 373
    return FALSE;
351 374
  }
375
  if (user_access('edit field collections', $account)) {
376
    return TRUE;
377
  }
352 378
  if (user_access('administer field collections', $account)) {
353 379
    return TRUE;
354 380
  }
......
356 382
    return FALSE;
357 383
  }
358 384
  $op = $op == 'view' ? 'view' : 'edit';
385

  
359 386
  // Access is determined by the entity and field containing the reference.
360 387
  $field = field_info_field($item->field_name);
361
  $entity_access = entity_access($op == 'view' ? 'view' : 'update', $item->hostEntityType(), $item->hostEntity(), $account);
362
  return $entity_access && field_access($op, $field, $item->hostEntityType(), $item->hostEntity(), $account);
388
  $hostEntity = $item->hostEntity() !== FALSE ? $item->hostEntity() : NULL;
389
  $entity_access = entity_access($op == 'view' ? 'view' : 'update', $item->hostEntityType(), $hostEntity, $account);
390

  
391
  return $entity_access && field_access($op, $field, $item->hostEntityType(), $hostEntity, $account);
363 392
}
364 393

  
365 394
/**
......
548 577
    // In case the entity has been changed / created, save it and set the id.
549 578
    // If the host entity creates a new revision, save new item-revisions as
550 579
    // well.
551
    if (isset($item['entity']) || !empty($host_entity->revision)) {
580
    if (!empty($host_entity->revision) || isset($item['entity'])) {
552 581
      if ($entity = field_collection_field_get_entity($item)) {
553 582
        // If the host entity is saved as new revision, do the same for the item.
554 583
        if (!empty($host_entity->revision) || !empty($host_entity->is_new_revision)) {
......
615 644
      $items_to_remove = array_diff($ids, $current_by_id);
616 645
      // Delete unused field collection items now.
617 646
      foreach (field_collection_item_load_multiple($items_to_remove) as $un_item) {
618
        $un_item->updateHostEntity($host_entity);
647
        $un_item->updateHostEntity($host_entity, $host_entity_type);
619 648
        $un_item->deleteRevision(TRUE);
620 649
      }
621 650
    }
......
626 655
 * Implements hook_field_delete().
627 656
 */
628 657
function field_collection_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
658
  $ids = field_collection_field_item_to_ids($items);
629 659
  // Also delete all embedded entities.
630
  if ($ids = field_collection_field_item_to_ids($items)) {
660
  if ($ids && field_info_field($field['field_name'])) {
631 661
    // We filter out entities that are still being referenced by other
632 662
    // host-entities. This should never be the case, but it might happened e.g.
633 663
    // when modules cloned a node without knowing about field-collection.
......
665 695
  }
666 696
}
667 697

  
698
/**
699
 * Implements hook_field_load().
700
 *
701
 * Invokes the load hooks for the fields contained in new, unsaved field
702
 * collection items. This allows images inside a field collection item to be
703
 * seen on a node's preview page before it's saved.
704
 */
705
function field_collection_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
706
  foreach ($items as &$each_item) {
707
    foreach ($each_item as &$each_field_collection_item) {
708
      if (!empty($each_field_collection_item['entity'])) {
709
        _field_invoke_multiple('load', 'field_collection_item', array(NULL => &$each_field_collection_item['entity']));
710
      }
711
    }
712
  }
713
}
714

  
668 715
/**
669 716
 * Implements hook_field_delete_revision().
670 717
 */
671 718
function field_collection_field_delete_revision($entity_type, $entity, $field, $instance, $langcode, &$items) {
672 719
  foreach ($items as $item) {
673
    if (!empty($item['revision_id'])) {
674
      if ($entity = field_collection_item_revision_load($item['revision_id'])) {
675
        $entity->deleteRevision(TRUE);
676
      }
720
    if (!empty($item['revision_id'])
721
      && $entity = field_collection_item_revision_load($item['revision_id'])) {
722
      $entity->deleteRevision(TRUE);
677 723
    }
678 724
  }
679 725
}
......
698 744
  if (!empty($item['value'])) {
699 745
    return FALSE;
700 746
  }
701
  elseif (isset($item['entity'])) {
747

  
748
  if (isset($item['entity'])) {
702 749
    return field_collection_item_is_empty($item['entity']);
703 750
  }
704 751
  return TRUE;
......
882 929
  return implode('<br>', $output);
883 930
}
884 931

  
932
function field_collection_entity_preload($entities, $langcode, &$items, $fields) {
933
  static $local_entity_cache = array();
934

  
935
  $fc_ids = array();
936

  
937
  // Collect every possible term attached to any of the fieldable entities.
938
  foreach ($entities as $id => $entity) {
939
    foreach ($items[$id] as $delta => $item) {
940

  
941
      // Check if this item is in our local entity cache
942
      if (isset($local_entity_cache[$item['value']])) {
943
        $items[$id][$delta]['field_collection'] = $local_entity_cache[$item['value']];
944
        continue;
945
      }
946

  
947
      // Force the array key to prevent duplicates.
948
      $fc_ids[$item['value']] = $item['value'];
949
    }
950
  }
951

  
952
  if ($fc_ids) {
953
    $new_entities = array();
954
    $terms = field_collection_item_load_multiple($fc_ids);
955

  
956
    // Iterate through the fieldable entities again to attach the loaded
957
    // field collection data.
958
    foreach ($entities as $id => $entity) {
959
      $rekey = FALSE;
960

  
961
      foreach ($items[$id] as $delta => $item) {
962
        // Check whether the field collection field instance value could be loaded.
963
        if (isset($terms[$item['value']])) {
964
          // Replace the instance value with the term data.
965
          $e = $terms[$item['value']];
966
          $local_entity_cache[$item['value']] = $e;
967
          $items[$id][$delta]['field_collection'] = $e;
968

  
969
	  foreach ($fields as $field_name => $field) {
970
            if (isset($e->$field_name)) {
971
              $field_data = $e->$field_name;
972
              if (isset($field_data[$langcode])) {
973
                $new_entities[$e->item_id] = $e->item_id;
974
                $items[$e->item_id] = $field_data[$langcode];
975
              }
976
            }
977
          }
978
        }
979
        // Otherwise, unset the instance value, since the field colletion entity does not exist.
980
        else {
981
          unset($items[$id][$delta]);
982
          $rekey = TRUE;
983
        }
984
      }
985

  
986
      if ($rekey) {
987
        // Rekey the items array.
988
        $items[$id] = array_values($items[$id]);
989
      }
990
    }
991

  
992
    field_collection_entity_preload($new_entities, $langcode, $items, $fields);
993
  }
994
}
995

  
996
function field_collection_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
997
  $fields = field_read_fields(array('type' => 'field_collection'));
998
  field_collection_entity_preload($entities, $langcode, $items, $fields);
999
}
1000

  
885 1001
/**
886 1002
 * Implements hook_field_formatter_view().
887 1003
 */
......
915 1031

  
916 1032
      $view_mode = !empty($display['settings']['view_mode']) ? $display['settings']['view_mode'] : 'full';
917 1033
      foreach ($items as $delta => $item) {
918
        if ($field_collection = field_collection_field_get_entity($item)) {
919
          $element[$delta]['entity'] = $field_collection->view($view_mode, $langcode);
1034
        // Existing field collections should be loaded without cache so that
1035
        // node Preview will work for both existing nodes and new ones.
1036
        if (isset($item['entity']->item_id)) {
1037
          // Load without cache.
1038
          $field_collection = field_collection_item_load($item['entity']->item_id, TRUE);
1039
        }
1040
        else {
1041
          $field_collection = field_collection_field_get_entity($item);
1042
        }
1043

  
1044
        if ($field_collection) {
1045
          $element[$delta]['entity'] = $field_collection->view($view_mode);
920 1046
          $element[$delta]['#theme_wrappers'] = array('field_collection_view');
921 1047
          $element[$delta]['#attributes']['class'][] = 'field-collection-view';
922 1048
          $element[$delta]['#attributes']['class'][] = 'clearfix';
......
949 1075
      $view_mode = !empty($display['settings']['view_mode']) ? $display['settings']['view_mode'] : 'full';
950 1076
      foreach ($items as $delta => $item) {
951 1077
        if ($field_collection = field_collection_field_get_entity($item)) {
952
          $element[$delta]['entity'] = $field_collection->view($view_mode, $langcode);
1078
          $element[$delta]['entity'] = $field_collection->view($view_mode);
953 1079
        }
954 1080
      }
955 1081
      break;
......
998 1124
      $path = field_collection_field_get_path($field);
999 1125
      list($id) = entity_extract_ids($entity_type, $entity);
1000 1126
      $element['#suffix'] = '';
1001
      if (!empty($settings['description']) && $entity_type != 'node') {
1127
      if ($entity_type != 'node' && !empty($settings['description'])) {
1002 1128
        $element['#suffix'] .= '<div class="description field-collection-description">' . field_filter_xss($instance['description']) . '</div>';
1003 1129
      }
1004 1130
      $title = entity_i18n_string("field:{$field['field_name']}:{$instance['bundle']}:setting_add", $settings['add']);
......
1052 1178
        'default value' => FIELD_BEHAVIOR_NONE,
1053 1179
      ),
1054 1180
    ),
1181
    'field_collection_sorter' => array(
1182
      'label' => t('Sortable only'),
1183
      'field types' => array('field_collection'),
1184
      'behaviors' => array(
1185
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
1186
        'default value' => FIELD_BEHAVIOR_DEFAULT,
1187
      ),
1188
    ),
1055 1189
  );
1056 1190
}
1057 1191

  
......
1092 1226

  
1093 1227
      $field_state = field_form_get_state($field_parents, $field_name, $language, $form_state);
1094 1228

  
1095
      if (field_collection_hide_blank_items($field) && $delta == $field_state['items_count'] && $delta > 0) {
1229
      if ($delta > 0 && $delta == $field_state['items_count'] && field_collection_hide_blank_items($field)) {
1096 1230
        // Do not add a blank item. Also see
1097 1231
        // field_collection_field_attach_form() for correcting #max_delta.
1098 1232
        $recursion--;
1099 1233
        return FALSE;
1100 1234
      }
1101
      elseif (field_collection_hide_blank_items($field) && $field_state['items_count'] == 0) {
1235

  
1236
      if ($field_state['items_count'] == 0 && field_collection_hide_blank_items($field)) {
1102 1237
        // We show one item, so also specify that as item count. So when the
1103 1238
        // add button is pressed the item count will be 2 and we show two items.
1104 1239
        $field_state['items_count'] = 1;
......
1191 1326

  
1192 1327
      $recursion--;
1193 1328
      return $element;
1329

  
1330
    case 'field_collection_sorter':
1331
      $elements = array();
1332

  
1333
      $field_name = $field['field_name'];
1334
      $parents = $form['#parents'];
1335
      $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
1336
      $count = $field_state['items_count'];
1337

  
1338
      for ($delta = 0; $delta < $count; $delta++) {
1339
        $item_id = isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL;
1340
        $revision_id = isset($items[$delta]['revision_id']) ? $items[$delta]['revision_id'] : NULL;
1341

  
1342
        // add a label component to visually identify this field collection item
1343
        $element['label'] = array();
1344
        if ($item_id) {
1345
          $item = field_collection_item_load($item_id);
1346
          $element['label']['#markup'] = $item ? $item->label() : $item_id;
1347
        }
1348

  
1349
        // the field stored value (item_id) and revision_id values
1350
        // so we need hidden fields to represent them
1351
        $element['value'] = array(
1352
          '#type' => 'hidden',
1353
          '#default_value' => $item_id,
1354
        );
1355
        $element['revision_id'] = array(
1356
          '#type' => 'hidden',
1357
          '#default_value' => $revision_id,
1358
        );
1359

  
1360
        // Input field for the delta (drag-n-drop reordering).
1361
        // We name the element '_weight' to avoid clashing with elements
1362
        // defined by widget.
1363
        $element['_weight'] = array(
1364
          '#type' => 'weight',
1365
          '#title' => t('Weight for row @number', array('@number' => $delta + 1)),
1366
          '#title_display' => 'invisible',
1367
          // Note: this 'delta' is the FAPI 'weight' element's property.
1368
          '#delta' => $count,
1369
          '#default_value' => isset($items[$delta]['_weight']) ? $items[$delta]['_weight'] : $delta,
1370
          '#weight' => 100,
1371
        );
1372

  
1373
        $elements[$delta] = $element;
1374
      }
1375

  
1376
      if ($elements) {
1377
        $elements += array(
1378
          '#theme' => 'field_multiple_value_form',
1379
          '#field_name' => $field['field_name'],
1380
          '#cardinality' => $field['cardinality'],
1381
          '#title' => check_plain($instance['label']),
1382
          '#required' => FALSE,
1383
          '#description' => field_filter_xss($instance['description']),
1384
          '#max_delta' => $count-1,
1385
        );
1386
      }
1387

  
1388
      return $elements;
1194 1389
  }
1195 1390
}
1196 1391

  
......
1231 1426
    $field = field_info_field($field_name);
1232 1427

  
1233 1428
    if ($field['type'] == 'field_collection' && field_collection_hide_blank_items($field)
1234
        && field_access('edit', $field, $entity_type) && $instance['widget']['type'] == 'field_collection_embed') {
1429
        && field_access('edit', $field, $entity_type)) {
1235 1430

  
1236 1431
      $element_langcode = $form[$field_name]['#language'];
1237 1432
      if ($form[$field_name][$element_langcode]['#max_delta'] > 0) {
......
1240 1435
      // Remove blank form elements and force user to explicitly add a field
1241 1436
      // collection if both 'hide_initial_item' and 'hide_blank_items' are TRUE.
1242 1437
      if ($field['settings']['hide_initial_item']
1243
          && $field['settings']['hide_blank_items']
1244
          && field_collection_item_is_empty($form[$field_name][$element_langcode][0]['#entity'])) {
1438
        && $field['settings']['hide_blank_items']
1439
        && $form[$field_name][$element_langcode][0]['#entity'] instanceof FieldCollectionItemEntity
1440
        && field_collection_item_is_empty($form[$field_name][$element_langcode][0]['#entity'])) {
1245 1441

  
1246 1442
        _field_collection_process_children_attached($form[$field_name][$element_langcode][0]);
1247 1443
        unset($form[$field_name][$element_langcode][0]);
......
1249 1445
      }
1250 1446
    }
1251 1447

  
1252
    if ($field['type'] == 'field_collection'
1253
        && $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED
1448
    if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED
1254 1449
        && empty($form_state['programmed'])
1450
        && $instance['widget']['type'] === 'field_collection_embed'
1255 1451
        && field_access('edit', $field, $entity_type)
1256
        && $instance['widget']['type'] == 'field_collection_embed') {
1452
        && $field['type'] === 'field_collection') {
1257 1453

  
1258 1454
      $element_langcode = $form[$field_name]['#language'];
1259 1455
      $element_wrapper = $form[$field_name][$element_langcode]['add_more']['#ajax']['wrapper'];
......
1267 1463

  
1268 1464
  // If FCs are translatable, make sure we mark any necessary sub-fields in the
1269 1465
  // FC widget as translatable as well.
1270
  if ($entity_type == 'field_collection_item'
1466
  if ($entity_type === 'field_collection_item'
1271 1467
      && field_collection_item_is_translatable()
1272 1468
  ) {
1273 1469
    foreach (field_info_instances($entity_type, $form['#bundle']) as $field_name => $instance) {
......
1433 1629
 */
1434 1630
function field_collection_field_get_entity(&$item, $field_name = NULL) {
1435 1631
  if (isset($item['entity']) && ($item['entity']->entityType() == 'field_collection_item')) {
1632
    if (count($item) > 1) {
1633
      // If $item contains more thing than 'entity', then it is sent from VBO.
1634
      // We clone the object to avoid that the same field collection item of the
1635
      // faked object is attached to multiple host objects.
1636
      return clone $item['entity'];
1637
    }
1436 1638
    return $item['entity'];
1437 1639
  }
1438
  elseif (isset($item['value'])) {
1640

  
1641
  if (isset($item['value'])) {
1439 1642
    // By default always load the default revision, so caches get used.
1440 1643
    $entity = field_collection_item_load($item['value']);
1441 1644
    if ($entity && $entity->revision_id != $item['revision_id']) {
......
1444 1647
    }
1445 1648
    return $entity;
1446 1649
  }
1447
  elseif (!isset($item['entity']) && isset($field_name)) {
1650

  
1651
  if (isset($field_name) && !isset($item['entity'])) {
1448 1652
    $item['entity'] = entity_create('field_collection_item', array('field_name' => $field_name));
1449 1653
    return $item['entity'];
1450 1654
  }
......
1527 1731
  }
1528 1732

  
1529 1733
  // Now validate required elements if the entity is not empty.
1530
  if (!field_collection_item_is_empty($field_collection_item) && !empty($element['#field_collection_required_elements'])) {
1734
  if (!empty($element['#field_collection_required_elements']) && !field_collection_item_is_empty($field_collection_item)) {
1531 1735
    foreach ($element['#field_collection_required_elements'] as &$elements) {
1532 1736

  
1533 1737
      // Copied from _form_validate().
......
1550 1754
          $field_values = drupal_array_get_nested_value($form_state['values'], array_slice($elements['#array_parents'], 0, $field_depth));
1551 1755

  
1552 1756
          // Special case lists since we don't get the correct array_parents.
1553
          if (count($elements['#array_parents']) < $field_depth && is_array($field_values)) {
1757
          if (is_array($field_values) && count($elements['#array_parents']) < $field_depth) {
1554 1758
            $field_values = reset($field_values);
1555 1759
          }
1556 1760

  
......
1574 1778

  
1575 1779
  // Only if the form is being submitted, finish the collection entity and
1576 1780
  // prepare it for saving.
1577
  if ($form_state['submitted'] && !form_get_errors()) {
1781
  if ($form_state['submitted'] && !form_get_error($element)) {
1578 1782

  
1579 1783
    field_attach_submit('field_collection_item', $field_collection_item, $element, $form_state);
1580 1784

  
......
1759 1963
  return entity_metadata_wrapper($item->hostEntityType(), $item->hostEntity());
1760 1964
}
1761 1965

  
1966
/**
1967
 * Entity property info getter callback for the host entity property.
1968
 */
1969
function field_collection_item_get_specific_type_host_entity($item, array $options, $name) {
1970
  // These properties' machine names have the form "host_entity_TYPE".
1971
  if (substr($name, 0, 12) !== 'host_entity_') {
1972
    return NULL;
1973
  }
1974
  return $item->hostEntityType() === substr($name, 12) ? $item->hostEntity() : NULL;
1975
}
1976

  
1762 1977
/**
1763 1978
 * Entity property info getter callback for the field collection items.
1764 1979
 *
......
1805 2020
        $items[$delta][$columns[0]] = $value->item_id;
1806 2021
        $items[$delta][$columns[1]] = $value->revision_id;
1807 2022
      }
1808
      elseif (is_array($value) && isset($value['value']) && isset($value['revision_id'])) {
2023
      elseif (is_array($value) && isset($value['value'], $value['revision_id'])) {
1809 2024
        $items[$delta][$columns[0]] = $value['value'];
1810 2025
        $items[$delta][$columns[1]] = $value['revision_id'];
1811 2026
      }
......
1826 2041
 * Implements hook_devel_generate().
1827 2042
 */
1828 2043
function field_collection_devel_generate($object, $field, $instance, $bundle) {
2044
  if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_CUSTOM) {
2045
    return devel_generate_multiple('_field_collection_devel_generate', $object, $field, $instance, $bundle);
2046
  }
2047

  
2048
  return _field_collection_devel_generate($object, $field, $instance, $bundle);
2049
}
2050

  
2051
function _field_collection_devel_generate($object, $field, $instance, $bundle) {
1829 2052
  // Create a new field collection object and add fake data to its fields.
1830 2053
  $field_collection = entity_create('field_collection_item', array('field_name' => $field['field_name']));
1831 2054
  $field_collection->language = $object->language;
......
1927 2150
        if (!empty($value[$language])) {
1928 2151
          $source_items = !empty($entity->{$field_name}[$source_language]) ? field_collection_field_item_to_ids($entity->{$field_name}[$source_language]) : array();
1929 2152
          foreach ($value[$language] as $delta => $field_value) {
1930
            if (!isset($field_value['entity'])) {
1931
              if ($fc_entity = field_collection_field_get_entity($field_value)) {
1932
                // Check if this field collection item belongs to the source language
1933
                if (in_array($fc_entity->item_id, $source_items)) {
1934
                  // Clone the field collection item
1935
                  $new_fc_entity = clone $fc_entity;
1936
                  $new_fc_entity->item_id = NULL;
1937
                  $new_fc_entity->revision_id = NULL;
1938
                  $new_fc_entity->is_new = TRUE;
1939

  
1940
                  // Set the new entity for saving it later
1941
                  $entity->{$field_name}[$language][$delta]['entity'] = $new_fc_entity;
1942
                }
1943
              }
2153
            // Check if this field collection item belongs to the source language
2154
            if (!isset($field_value['entity'])
2155
              && ($fc_entity = field_collection_field_get_entity($field_value))
2156
              && in_array($fc_entity->item_id, $source_items)) {
2157
              // Clone the field collection item
2158
              $new_fc_entity = clone $fc_entity;
2159
              $new_fc_entity->item_id = NULL;
2160
              $new_fc_entity->revision_id = NULL;
2161
              $new_fc_entity->is_new = TRUE;
2162

  
2163
              // Set the new entity for saving it later
2164
              $entity->{$field_name}[$language][$delta]['entity'] = $new_fc_entity;
2165
            }
2166
          }
2167
        }
2168
      }
2169
    }
2170
  }
2171
}
2172

  
2173

  
2174
/**
2175
 * Implements hook_feeds_processor_targets_alter()
2176
 */
2177
function field_collection_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
2178

  
2179
  // Load up.
2180
  $loaded = &drupal_static(__FUNCTION__, FALSE);
2181

  
2182
  if (!$loaded) {
2183
    $loaded = TRUE;
2184
    $path = drupal_get_path('module', 'feeds') . '/mappers';
2185
    $files = drupal_system_listing('/.*\.inc$/', $path, 'name', 0);
2186
    foreach ($files as $file) {
2187
      if (strpos($file->uri, '/mappers/') !== FALSE) {
2188
        require_once DRUPAL_ROOT . '/' . $file->uri;
2189
      }
2190
    }
2191
  }
2192

  
2193
  foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
2194
    $info = field_info_field($name);
2195
    if ($info['type'] == 'field_collection') {
2196

  
2197
      $sub_type = 'field_collection_item';
2198
      $new_targets = module_invoke_all('feeds_processor_targets', $sub_type, $info['field_name']);
2199
      drupal_alter('feeds_processor_targets', $new_targets, $sub_type, $info['field_name']);
2200

  
2201
      foreach ($new_targets as $sub_name => $target) {
2202
        $new_name = t($info['field_name']) . ':' . t($sub_name);
2203
        $targets[$new_name] = $target;
2204
        if (isset($target['name'])) {
2205
          $targets[$new_name]['name'] = $instance['label'] . ':' . $target['name'];
2206
        }
2207
        // We override callback for now and retrieve original later.
2208
        $targets[$new_name]['callback'] = 'field_collection_feeds_set_target';
2209
      }
2210
    }
2211
  }
2212

  
2213
}
2214

  
2215

  
2216
/**
2217
 * Process Field Collection items.
2218
 *
2219
 * @param  [type] $source       [description]
2220
 * @param  [type] $entity       [description]
2221
 * @param  [type] $target       [description]
2222
 * @param  [type] $value        [description]
2223
 * @param  [type] $main_mapping [description]
2224
 * @return [type]               [description]
2225
 */
2226
function field_collection_feeds_set_target($source, $entity, $target, $value, $main_mapping) {
2227
  $sub_targets = &drupal_static(__FUNCTION__, array());
2228

  
2229
  $args = explode(':', $target);
2230
  $target = array_shift($args);
2231
  $sub_target = implode(':', $args);
2232

  
2233
  $sub_type = 'field_collection_item';
2234
  $new_targets = module_invoke_all('feeds_processor_targets', $sub_type, $target);
2235
  drupal_alter('feeds_processor_targets', $new_targets, $sub_type, $target);
2236

  
2237
  // Now we retrieve old callbacks and keep then on a static cache.
2238
  if (!isset($sub_targets[$target])) {
2239
    $sub_targets[$target] = array();
2240
    drupal_alter('feeds_processor_targets', $sub_targets[$target], $sub_type, $target);
2241
  }
2242

  
2243
  $_sub_targets = $new_targets;
2244

  
2245
  $value = is_array($value) ? $value : array($value);
2246
  $info = field_info_field($target);
... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.

Formats disponibles : Unified diff