0

I have a custom module that creates a field type. It is a plain text field abd I've added it to a content type using the Drupal UI. The cardinality of this field is "Unlimited".

This is how I create the field in code:

class MyItem extends FieldItemBase {

  /**
   * {@inheritdoc}
   */
  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    return [
      'columns' => [
        'value' => [
          'type' => 'text',
          'size' => 'tiny',
          'not null' => FALSE,
        ],
        'safevalue' => [
          'type' => 'text',
          'size' => 'tiny',
          'not null' => FALSE,
        ],
      ],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties['value'] = DataDefinition::create('string')
      ->setLabel(t('Value'));
    $properties['safevalue'] = DataDefinition::create('string')
      ->setLabel(t('Safe value'))
      ->setComputed(TRUE);
    return $properties;
  }

}

As you can see, there are two columns: value is supposed to store raw user input. safevalue is supposed to store a sanitized version of the data.

For testing this. I am just doing this inside hook_node_presave():

function mymodule_node_presave(\Drupal\Core\Entity\EntityInterface $entity) {
  switch ($entity->getBundle()) {
    case 'mybundle':
      $entity->field_myfield = ['one', 'two', 'three'];
      $entity->field_myfield->safevalue =  ['one', 'two', 'three'];
      break;
  }
}

If the field has a cardinality 1 (i.e. the values inserted are scalars), this works fine.

However, if I insert arrays, when I examine the database, and look at the table node__field_myfield, I see that the columns field_myfield_value and field_myfield_safevalue both exist with identical configurations.

If I create a node using the UI, I observe this:

  • field_myfield_value column contains three rows with the strings 'one', 'two' and 'three'. That's correct.
  • field_myfield_safevalue have the string 'Array' in its first row, and NULL in the two others. That's wrong.

I guess that what makes things go wrong is that this is a multivalue field and that I need to use some other action to get the values correctly inserted.

How can I get a multivalue field correctly inserted in the safevalue column?

2 Answers 2

1

When you access

$entity->field_myfield->safevalue

That is implicitly the first item in the field list's safevalue. You're not setting the safe value for all deltas in that field.

To do that, you need to set each value separately. Like so:

$values = [
  ['value' => 'foo', 'safevalue' => 'bar'],
  ['value' => 'foo2', 'safevalue' => 'bar2'],
];
$entity->field_myfield = $values;

Note the are several different permutations of the above, this is just one of them, if your usual code style for setting entity properties is different it's fine to use that instead.

3

The field deltas are one level higher than the properties.

$entity->field_myfield = [
  0 => [
    'value' => 'one',
    'safevalue' => 'one',
  ],
  1 => [
    'value' => 'two',
    'safevalue' => 'two',
  ],
  2 => [
    'value' => 'three',
    'safevalue' => 'three',
  ],
];

BTW when you save the field property then don't specify >setComputed(TRUE). This is only when you calculate the field value in a typed data plugin.

3
  • I am not sure if I understand your "BTW". The intent is to compute the safe values by running the raw values through some sanitizing function. In the example, I didn't do this in order to keep the example simple. If I compute the safe values as described, should I not then use ->setComputed(TRUE)? May 31, 2022 at 12:26
  • 1
    Computed values are calculated in memory, not saved to the database. This is usually done in a typed data plugin (specified in DataDefinition::create() or overridden in ->setClass(). You don't have a problem with field deltas then, because the typed data is more granular.
    – 4uk4
    May 31, 2022 at 12:41
  • OK, thanks for the additional explanation. I've removed the property. May 31, 2022 at 12:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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