2

I have a custom field type that contains a number field, among others.

class MyFieldItem extends FieldItemBase {
    public static function propertyDefinitions($field_definition) {
        $properties = [];
        $properties['some_number'] = DataReferenceTargetDefinition::create(
            'integer'
        );
        ...
    }
    ...
}

I need the sum of all values of the property some_number. A function adding the numbers would look like this:

function addAllNumbers($items) {
    $sum = 0;
    foreach ($items as $item) {
        $sum += $item->get('some_number')->getValue();
    }
    return $sum;
}

I need this sum for many purposes, like to display it in the formatter, or to validate forms.

Now, I've found that I'm calculating this sum in several places in my code. But an important programming principle tells me: "Don't repeat yourself!"

Where is a natural place to perform calculations on the FieldItemList of a custom FieldType?

I see several candidates for such a place.

  • The .module file. However, this is hardly connected to the custom FieldType and often a confusing collection of random things.
  • The MyFieldItem class defining the custom FieldType. Here, the iteration would go over $this->parents. However, I don't see a way to access the FieldType object from within the Formatter.
  • The formatter. However, then it would be necessary to somehow format the FieldItemList during the form validation.
  • Some utility class. But probably, other developers would find that strange in the future.

There should be one-- and preferably only one --obvious way to do it.
(The Zen of Python, by Tim Peters)

5
  • I vote to close this as opinion based. One possible solution is to save the sum as a field and only to the calculation when the entity is updated/saved.
    – user72672
    Jan 8, 2020 at 22:46
  • This would introduce database denormalization, which is problematic, too. That one shouldn't repeat oneself is not an opinion, but a matter of survival in complex projects. Jan 8, 2020 at 23:29
  • I think there are too many decisions/options here because it's unclear what you are trying to do. Maybe if you could explain the purpose of addAllNumbers. Opinion: I don't think the usage of addAllNumbers fits Tim Peters' example either because its usage is arbitrary and you can sum things in different places.
    – mradcliffe
    Jan 9, 2020 at 11:30
  • 1
    If my question is unclear, the perfect answer by @4k4 might help to understand it. I simply needed the natural place for something that concerns 1) a custom field type, 2) many pieces of very different code, and 3) all items of the field, if there are multiple. Defining a custom FieldItemList works and is the way to do it. Jan 9, 2020 at 11:44
  • 1
    I'd like to point out this part in Help Center-Asking If the question is about code you wrote, for which you want to write better code... show the code you are using He showed the code, and asked if there was a better way to do (locate) it. Pedantic: I don't think Peters' rule applies here. The rule is less about DRY, than about creating a language/interface with multiple ways to do the same exact thing with zero functional difference. Like how in PHP die() is literally "Equivalent to exit" Jan 9, 2020 at 15:17

1 Answer 1

3

The natural place would be a method in a custom field item list:

class MyFieldItemList extends FieldItemList {

  public function addAllNumbers() {
    $sum = 0;
    foreach ($this->list as $item) {
      $sum += $item->some_number;
    }
    return $sum;
  }

}

Set the list class in the field type:

 * @FieldType(
 *   ...
 *   list_class = "\Drupal\mymodule\MyFieldItemList",

Not the answer you're looking for? Browse other questions tagged or ask your own question.