Score:0

How can I get a multivalue field correctly inserted?

kz flag

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?

Score:3
cn flag

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.

Free Radical avatar
kz flag
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)`?
4uk4 avatar
cn flag
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.
Free Radical avatar
kz flag
OK, thanks for the additional explanation. I've removed the property.
Score:1
cn flag

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.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.