I have a content-type seasonal_prices
with field-collection containing an entity reference field (referencing content-type room
) and a number field; the field-collection is multi-value with unlimited cardinality.
When adding new content of type seasonal_prices
, I want the form to be pre-populated with an instance of the field-collection for every existing content of type room
.
An example: If there are 5 nodes of type room
, the create-form of seasonal_prices
should show me 5 instances of the field-collection, where each reference-field is pre-populated with its reference to room
, so all I have to do is fill out the number-field.
UPDATE: Here is the code i finally used in a custom module, hope this is helpful:
<?php
function seasonal_prices_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
// Increase the max cardinality to 20
$range = drupal_map_assoc(range(1, count(get_roomtype_ids())));
$new_options = array(FIELD_CARDINALITY_UNLIMITED => t('Unlimited')) + $range;
$form['field']['cardinality']['#options'] = $new_options;
}
function seasonal_prices_form_alter(&$form, $form_state, $form_id) {
// update cardinality in field settings
$field_name = 'field_prices_and_roomtype';
$field = field_info_field($field_name);
$field['cardinality'] = count(get_roomtype_ids());
// field_update_field() throws an exception on failure
try {
field_update_field($field);
}
catch (Exception $e) {
drupal_set_message(t('Could not update cardinality of field.'), 'error');
}
// generate fieldcollection instances
if($form_id == 'seasonal_prices_node_form') {
$items_count = count(get_roomtype_ids());
$form_theme = $form[$field_name][LANGUAGE_NONE]['#theme'];
// remove delete and add more buttons
$form[$field_name][LANGUAGE_NONE][0]['remove_button']['#access'] = FALSE;
$form[$field_name][LANGUAGE_NONE]['add_more']['#access'] = FALSE;
$items = &$form_state['field'][$field_name][LANGUAGE_NONE];
// generate required number of fields collection
if ($items_count > 1 and $items['items_count'] != $items_count) {
$items['items_count'] = $items_count;
$items['field']['cardinality'] = $items_count;
$form[$field_name][LANGUAGE_NONE] = field_multiple_value_form($items['field'], $items['instance'], LANGUAGE_NONE, array(), $form, $form_state);
// reset theme function, as field_multiple_value_form hijacks it
$form[$field_name][LANGUAGE_NONE]['#theme'] = $form_theme;
}
// fill generated instances with default values and disable access
for ($delta = 0; $delta < ($items_count); $delta++) {
$form['field_prices_and_roomtype'][LANGUAGE_NONE][$delta]['field_ref_roomtype'][LANGUAGE_NONE]['#default_value'] = get_roomtype_ids()[$delta];
$form['field_prices_and_roomtype'][LANGUAGE_NONE][$delta]['field_ref_roomtype']['#access'] = FALSE;
// designate Fieldcollection Items correctly
$form['field_prices_and_roomtype'][LANGUAGE_NONE][$delta]['#prefix'] = '<div class="roomtype-form-label"><b>' . get_node_title(get_roomtype_ids()[$delta]) . '</b>';
$form['field_prices_and_roomtype'][LANGUAGE_NONE][$delta]['#suffix'] = '</div>';
}
}
}
// Helper function to get the node title without loading the whole node object.
function get_node_title($nid) {
return db_query('SELECT title FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchField();
}
// Helper function
function get_roomtype_ids() {
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'node')
->entityCondition('bundle', 'roomtype')
->propertyCondition('status', 1)
->propertyOrderBy('created', 'ASC');
$result = $query->execute();
return array_keys($result['node']);
}