Hello,

I want to do calculations with the values of fields from a field collection. I have tried two methods that actually work because I use them in the node template temporarily, until I can get them working in a computed field. I've had no luck so far.

My field collection is called field_student, and the field I use to test this functionality is called field_bar

This is the first method, using entity_metadata_wrapper

global $node;	
$meta_wrapper = entity_metadata_wrapper('node', $node);
	$student_line = array();
	foreach ($meta_wrapper->field_student as $line) {
		    $student_line[] = $line->value()->field_bar;
    }
		$t = count($meta_wrapper->field_student);
		$totalbar = array();
		for ($i = 0; $i < $t; ++$i) {
			$totalbar[$i] = $student_line[$i]['und'][0]['value'];
	}
	$entity_field[0]['value'] = array_sum($totalbar);

This one throws the following error:

Error message
EntityMetadataWrapperException: Unknown data property field_student. in EntityStructureWrapper->getPropertyInfo() (line 339 of /var/www/ttms_db/sites/all/modules/contrib/entity/includes/entity.wrapper.inc).

The other method uses field_get_items

	global $node;
        $field_collection_items = field_get_items('node', $node, 'field_student');
	$field_collection_item_ids = array();
	$i = 0;
	foreach ($field_collection_items as $field_collection_item){
		$field_collection_item_ids[$i] = $field_collection_item['value'];
		$i++;
	}
        $field_collection_item_fields = entity_load('field_collection_item', $field_collection_item_ids);

	$bar_fields = array();

	$i = 0;
	foreach ($field_collection_item_fields as $field_collection_item_field){
		$bar_fields[$i] = field_get_items('field_collection_item', $field_collection_item_field, 'field_bar');
		$i++;
	}

	$bars= array();

	$i = 0;
	foreach ($bar_fields as $bar_field){
		$bars[$i] = $bar_field[0]['value'];
		$i++;
	}
$entity_field[0]['value'] = array_sum($bars);

Error message here is:

Error message
EntityMalformedException: Missing bundle property on entity of type node. in entity_extract_ids() (line 7562 of /var/www/ttms_db/includes/common.inc).

Interestingly I only get these error messages when I'm not storing the computed field in the database. When I ask the field to store the value in the database, I don't get anything at all, no error, no field.

I'm sure someone who has a better understanding of php and Drupal API will know what to do with these error messages as they are quite descriptive, but unfortunately not to me. Someone suggested that the wrapper doesn't work because the fields are not loaded yet at that point in rendering the node, but I don't know. It works as intended when I put this code in node.tpl.php, but I would like to store these values in the database and display them in a view later.

I have read a lot of issue threads and requests, manuals and tutorials, to no avail. If someone can help me on this one I promise to write a wonderful how-to because I think it will help a lot of people.

Thanks!

BP

Comments

BParticle’s picture

bump

HansKuiters’s picture

Hi BP, your code helped my a lot. This is my code to copy field collection data in a computed field array. I hope I can help you back with it. I am now struckling with the $output. I prints the actual html entity instead of performing a line break.

function computed_field_field_risico_verzameld_compute(&$entity_field, $entity_type, $entity, $field, $instance, $langcode, $items) {
  $field_collection_items = field_get_items($entity_type, $entity, 'field_risico'); // field_risico is node field
  $field_collection_item_ids = array();
  foreach ($field_collection_items as $field_collection_item) {
    $field_collection_item_ids[] = $field_collection_item['value'];
  }
  $field_collection_item_fields = entity_load('field_collection_item', $field_collection_item_ids);
  $links = array();
  foreach ($field_collection_item_fields as $field_collection_item_field) {
    $tid = field_get_items('field_collection_item', $field_collection_item_field, 'field_risicoterm');  // field_risicoterm is fieldcollection field
    $term = taxonomy_term_load($tid[0]['tid']);
    $link = field_get_items('field_collection_item', $field_collection_item_field, 'field_link');  // field_link is fieldcollection field
    $links[$term->name] = $link[0]['value'];
  }
  $output = '';
  foreach ($links as $term => $link) {
    $output .= $term .' - '. $link .'<br />';
  }
  $entity_field[0]['value'] = $output;
}
BParticle’s picture

Glad my code was of use to you! I'll look into yours and get back to this thread. Thank you for sharing it.

BParticle’s picture

Hello Capono, I'm afraid I need some help understanding your code. Is the entire block of code wrapped into that computed_field_field_risico_verzameld_compute function? Is that an arbitrarily chosen function name or does it follow some naming convention? In any case I couldn't make it work for me, sadly.

HansKuiters’s picture

Computed field gives you two choices: you can put your php code in the field directly or you can make your own function in a custom module, which I did. It is explained in the field description. So in my function name, risico_verzameld is the name of the computed field.

BParticle’s picture

I see. So without seeing the code of your custom module I can't really make out what's happening there I guess. Would be interesting to look into that too.

HansKuiters’s picture

I posted the complete compute function in comment#2. Create your own empty custom module (create an .info and .module file, put the function in the .module file, enable the module and go.

NancyDru’s picture

@BParticle: Have you tried the getIterator() method?

Try changing foreach ($meta_wrapper->field_student as $line)

To: foreach ($meta_wrapper->field_student->getIterator() as $line)

kaizerking’s picture

I have 3 fields in a field collection 2 terms refrence fields whose tids are 625 with term name -xyz ,tid - 626 with term name 'pqr' and field_time_duration filed.I want to filter the values by one of the tid or term name and populate one computed i.e field field_xyz =sum of durations filtered by tid 625 xyz and another computed field filed_pqr =sum of duartions filtered by tid 625-pqr
how to do that?
or since I just have two terms, may be instead of terms I can also use list integer field and filter using that field
can someone help plz?

swapnil66’s picture

Issue tags: +computed fields

I have creating two different content type "A" and "B" , i have created a field name "a_field_s" and "b_field_s" where **field type** is "computed" accordingly where first is for content type "A" and other is for B.

I am adding few fields in "a_field_s" with writing code as:

$entity_field[0]['value'] = $entity->field_class_3rd_no_of_student_ic[LANGUAGE_NONE][0]['value'] + $entity->field_class_4th_no_of_student_ic[LANGUAGE_NONE][0]['value'];

And also few fields in "b_field_s" as:

$entity_field[0]['value'] = $entity->field_class_3rd_no_of_student_ib[LANGUAGE_NONE][0]['value'] + $entity->field_class_4th_no_of_student_ib[LANGUAGE_NONE][0]['value'];

Both computed fields are working well.

Now i have taken one more field in other content type "C" naming "c_fields_s" as computed, and i want addition of "a_field_s" and "b_field_s" in this new field.

kaizerking’s picture

@ swapnil66, If the Content type c is the last one you are creating then use rules and sum and set value before saving. create an integer field in C content type for this NOT computed field.

milos.kroulik’s picture

I had a problem similar to first part of original description when I checked "Recalculate the field value every time." option.

robertgarrigos’s picture

the problem behind this is that the entity object is not exactly the same when the computed field does the calculation after node edit/creation of when node viewing. When creating or editing a node the $entity->field_collection_field contains real values but when viewing the node it contains field collection id. The methods to get real values are, then, different.

You can install devel module and expose then $entity object with dpm($entity) within your computed field code to see this. You will notice that the entity object gets printed twice when you select "Recalculate the field value every time. " and you edit a node with the computed field: once because its being edited and another one cause its being viewed.

robertgarrigos’s picture

For instance, this is my code in my computed field. It sums all field_cost field values of my field_ingredients_formula field collection.

    $total = 0;
    foreach ($entity->field_ingredients_formula['und'] as $key => $value) {
      if (isset($value['value'])) {
        $id = $value['value'];
        $ingredient = entity_metadata_wrapper('field_collection_item', $id);
        $cost = $ingredient->field_cost->value();
        $total += $cost;
      }
      elseif (isset($value['field_cost']['und'][0]['value'])) {
        $cost = $value['field_cost']['und'][0]['value'];
        $total += $cost;
      }
    }
    $entity_field[0]['value'] = $total;
esquareddesign’s picture

I have modified this to work with paragraphs, wich have replaced field collection in 8, but I keep erroring out. It is supposed to sum all field_total field values of field_job_parts paragraph. I have a node called Job with paragraph field field_job_parts containing a field called field_total that I need to sum up. Below is my code.

    $total = 0;
    foreach ($entity->field_job_parts['und'] as $key => $value) {
      if (isset($value['value'])) {
        $id = $value['value'];
        $part = entity_metadata_wrapper('paragraphs_item', $id);
        $cost = $part->field_total->value();
        $total += $cost;
      }
      elseif (isset($value['field_total']['und'][0]['value'])) {
        $cost = $value['field_total']['und'][0]['value'];
        $total += $cost;
      }
    }
    $entity_field[0]['value'] = $total;

What am I missing here?