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/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);
2247

  
2248
  // Iterate over all values.
2249
  $delta = 0;
2250
  $field = isset($entity->$target) ? $entity->$target : array();
2251
  try {
2252

  
2253
    // $delta = which FC instance.
2254
    // We iterate by subfield, not by FC.
2255
    while (isset($value[$delta])) {
2256

  
2257
      // Zero out.
2258
      $field_collection_item = null;
2259

  
2260
      // FC is already set on host entity.
2261
      if (isset($field[LANGUAGE_NONE][$delta]['entity'])) {
2262
        $field_collection_item = $field[LANGUAGE_NONE][$delta]['entity'];
2263
      }
2264
      // FC is on host entity, we have FC item_id, but FC is not loaded.
2265
      elseif (isset($field[LANGUAGE_NONE][$delta]['value'])) {
2266
        $field_collection_item = field_collection_item_load($field[LANGUAGE_NONE][$delta]['value']);
2267

  
2268
        // Zero out field so that we don't just keep accumulating values.
2269
        unset($field_collection_item->{$sub_target}[LANGUAGE_NONE] );
2270
      }
2271

  
2272
      // Host entity does not have any attached FCs yet.
2273
      if (empty($field_collection_item)) {
2274
        $field_collection_item = entity_create('field_collection_item', array('field_name' => $target));
2275
        $field_collection_item->setHostEntity($entity->feeds_item->entity_type, $entity);
2276
      }
2277

  
2278
      $sub_mapping = array();
2279
      $config = $source->importer()->getConfig();
2280
      if (!empty($config['processor']['config']['mappings'])) {
2281
        foreach ($config['processor']['config']['mappings'] as $mapping) {
2282
          if ($mapping['target'] == $target . ':' . $sub_target) {
2283
            $sub_mapping = $mapping;
2284
            $sub_mapping['target'] = $sub_target;
2285
            // Needs language or feeds mappers shout php notices.
2286
            $sub_mapping['language'] = !empty($config['processor']['config']['language']) ? $config['processor']['config']['language'] : LANGUAGE_NONE;
2287
            break;
2288
          }
2289
        }
2290
      }
2291

  
2292
      if (isset($_sub_targets[$sub_target]['callback']) && function_exists($_sub_targets[$sub_target]['callback'])) {
2293
        $callback = $_sub_targets[$sub_target]['callback'];
2294

  
2295
        // Normalize
2296
        if (!is_array($value[$delta])) {
2297
          $value[$delta] = array($value[$delta]);
2298
        }
2299

  
2300
        // Check for a limit and force that limit.
2301
        if ($info['cardinality'] !== '-1') {
2302
          $value[$delta] = array_slice($value[$delta], 0, $info['cardinality']);
2303
        }
2304

  
2305
        // HiJack the file callback so we can make it work.
2306
        if ($callback == 'file_feeds_set_target') {
2307
          $callback = 'field_collection_file_feeds_set_target';
2308
        }
2309

  
2310
        // Allow altering with many parameters. Cannot use drupal_alter here.
2311
        $implements = module_implements('sub_target_pre_callback_parse');
2312
        foreach ($implements as $module_name) {
2313
          $hook = $module_name . '_' . 'sub_target_pre_callback_parse';
2314
          $hook($target, $sub_target, $entity, $field, $field_collection_item, $value[$delta]);
2315
        }
2316

  
2317
        $callback($source, $field_collection_item, $sub_target, $value[$delta], $sub_mapping);
2318
      }
2319

  
2320
      // No need to save the field collection here. Just wait until the node is saved.
2321
      // If we save the FC here we get a huge performance degregation.
2322
      $field[LANGUAGE_NONE][$delta]['entity'] = $field_collection_item;
2323

  
2324
      // Break when only hitting the max delta.
2325
      if ($info['cardinality'] == $delta) {
2326
        break;
2327
      }
2328

  
2329
      $delta++;
2330
    }
2331

  
2332
  }
2333
  catch (Exception $e) {
2334
    drupal_set_message($e->getMessage(), 'error');
2335
    watchdog_exception('field_collection', $e, $e->getMessage());
2336
    throw $e;
2337
  }
2338

  
2339
  $entity->{$target} = $field;
2340
}
2341

  
2342
/**
2343
 * Wrapper function for file_feeds_set_target as it doesn't do the nested stuff.
2344
 */
2345
function field_collection_file_feeds_set_target($source, $entity, $target, $value) {
2346

  
2347
  if (empty($value)) {
2348
    return;
2349
  }
2350
  module_load_include('inc', 'file');
2351

  
2352
  // Make sure $value is an array of objects of type FeedsEnclosure.
2353
  if (!is_array($value)) {
2354
    $value = array($value);
2355
  }
2356
  foreach ($value as $k => $v) {
2357
    if (!($v instanceof FeedsEnclosure)) {
2358
      if (is_string($v)) {
2359
        $value[$k] = new FeedsEnclosure($v, file_get_mimetype($v));
2360
      }
2361
      else {
2362
        unset($value[$k]);
2363
      }
2364
    }
2365
  }
2366
  if (empty($value)) {
2367
    return;
2368
  }
2369

  
2370
  $entity_type = 'field_collection_item';
2371
  $bundle = $entity->field_name;
2372

  
2373
  // Determine file destination.
2374
  // @todo This needs review and debugging.
2375
  $instance_info = field_info_instance($entity_type, $target, $bundle);
2376
  $info = field_info_field($target);
2377
  $data = array();
2378
  if (!empty($entity->uid)) {
2379
    $data[$entity_type] = $entity;
2380
  }
2381
  $destination = file_field_widget_uri($info, $instance_info, $data);
2382

  
2383
  // Populate entity.
2384
  $i = 0;
2385
  $field = isset($entity->$target) ? $entity->$target : array();
2386
  foreach ($value as $v) {
2387
    $file = FALSE;
2388
    try {
2389
      $v->setAllowedExtensions($instance_info['settings']['file_extensions']);
2390
      $file = $v->getFile($destination);
2391
    }
2392
    catch (Exception $e) {
2393
      watchdog('feeds', check_plain($e->getMessage()));
2394
    }
2395
    if ($file) {
2396
      $field[LANGUAGE_NONE][$i] = (array)$file;
2397
      $field[LANGUAGE_NONE][$i]['display'] = 1; // @todo: Figure out how to properly populate this field.
2398
      if ($info['cardinality'] == 1) {
2399
        break;
2400
      }
2401
      $i++;
2402
    }
2403
  }
2404
  $entity->{$target} = $field;
2405

  
2406
}
2407

  
2408

  
2409
/**
2410
 * Implementation of hook_feeds_presave().
2411
 * Invoked before a feed item is saved.
2412
 *
2413
 * @param FeedsSource $source
2414
 *   FeedsSource object that describes the source that is being imported.
2415
 * @param $entity
2416
 *   The entity object.
2417
 * @param array $item
2418
 *   The parser result for this entity.
2419
 * @param int|null $entity_id
2420
 *   The id of the current item which is going to be updated. If this is a new
2421
 *   item, then NULL is passed.
2422
 */
2423
function field_collection_feeds_presave(FeedsSource $source, $entity, $item, $entity_id) {
2424
  $feed_config = $source->importer()->getConfig();
2425
  $mappings = $feed_config['processor']['config']['mappings'];
2426

  
2427
  // Only hook in when updating the entity.
2428
  if (empty($entity_id)) {
2429

  
2430
    // Go through $mappings and find the FC fields.
2431
    foreach ($mappings as $mapping) {
2432

  
2433
      if (strpos($mapping['target'], ':') !== FALSE) {
2434
        $parts = explode(':', $mapping['target']);
2435
        $fc_name = array_shift($parts);
2436
        $info = field_info_field($fc_name);
2437

  
2438
        // If the field is not a field collection, skip it.
2439
        if ($info['type'] != 'field_collection') {
2440
          continue;
2441
        }
2442

  
2443
        if (isset($entity->{$fc_name})) {
2444
          foreach ($entity->{$fc_name}[LANGUAGE_NONE] as $delta => $fc_unloaded) {
2445

  
2446
            // If an FC is not loaded, we don't want it. Unset it so it won't save.
2447
            if (!isset($entity->{$fc_name}[LANGUAGE_NONE][$delta]['entity'])) {
2448
              unset($entity->{$fc_name}[LANGUAGE_NONE][$delta]);
1944 2449
            }
1945 2450
          }
2451

  
1946 2452
        }
1947 2453
      }
1948 2454
    }
1949 2455
  }
1950 2456
}
2457

  

Formats disponibles : Unified diff