I'm trying to insert some data into a custom content entity I have made containing a custom (unlimited cardinality) field type I created that contains 5 values, a html text value, 2 entity references and 2 integers. I have not marked the field as required and saving data to the custom entity without adding an instance of the custom field works fine, but as soon as I try to save the entity with data from the custom field, Drupal complains saying "This value should be of the correct primitive type" It also highlights all 5 properties of my custom field in red. This error message is vague however as it does not tell me exactly what "primitive types" are expected and it is also unclear if Drupal is highlighting all properties because they are all associated with my custom field, of if all properties are incorrect. I have googled and searched around but I cannot find any documentation, tutorials or working examples that explain what the primitive type for the 3 unique value types in my field are expected to be and I don't know how to go about finding the correct types in the absence of these resources. The 3 methods below are my implementation of my custom fielditem/fieldtype class, which extends FieldItemBase:
public static function schema(FieldStorageDefinitionInterface $field_definition) {
return [
'columns' => [
'body' => [
'type' => 'text',
'not null' => FALSE,
'description' => 'Text description.',
],
'reference' => [
'type' => 'int',
'not null' => TRUE,
'description' => 'Entity reference of institution entity.',
],
'context' => [
'type' => 'int',
'not null' => TRUE,
'description' => 'Entity ID of taxonomy term from component_context vocabulary.',
],
'start_date' => [
'type' => 'int',
'not null' => TRUE,
'description' => 'Start date',
],
'end_date' => [
'type' => 'int',
'not null' => TRUE,
'description' => 'End date',
],
],
];
}
public function isEmpty() {
$value1 = $this->get('reference')->getValue();
$value2 = $this->get('start_date')->getValue();
$value3 = $this->get('end_date')->getValue();
$value4 = $this->get('context')->getValue();
return empty($value1) || empty($value2) || empty($value3) || empty($value4);
}
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
// Add our properties.
$properties['body'] = DataDefinition::create('string')
->setLabel(t('Body Text'))
->setDescription(t('The description providing context for this component'));
$properties['reference'] = DataDefinition::create('integer')
->setLabel(t('Institution'))
->setDescription(t('The Institution this component is related to.'));
$properties['context'] = DataDefinition::create('integer')
->setLabel(t('Context'))
->setDescription(t('The way this component relates to this specific institution.'));
$properties['start_date'] = DataDefinition::create('integer')
->setLabel(t('Modifier'))
->setDescription(t('The starting date.'));
$properties['end_date'] = DataDefinition::create('integer')
->setLabel(t('Average'))
->setDescription(t('The ending date.'));
return $properties;
}
Below are the 2 methods I am using to implement my custom form widget that I am using to enter in and process the data, which extends WidgetBase:
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
$values = parent::massageFormValues($values, $form, $form_state);
foreach ($values as $delta => $value) {
$values[$delta]['body'] = $value['body']['value'];
$values[$delta]['reference'][0]['target_id'] = (int) $value['reference'][0]['target_id'];
$values[$delta]['context'][0]['target_id'] = (int) $value['context'][0]['target_id'];
$values[$delta]['start_date'] = (int) $value['start_date'];
$values[$delta]['end_date'] = (int) $value['end_date'];
}
return $values;
}
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element['body'] = [
'#type' => 'text_format',
'#title' => 'Body Text',
'#default_value' => $items[$delta]->body ?? NULL,
];
$element['reference'] = [
'#type' => 'entity_autocomplete',
'#target_type' => 'institution',
'#tags' => TRUE,
'#match_operator' => 'CONTAINS',
'#size' => 60,
'#placeholder' => '',
'#title' => 'Institution Reference',
'#default_value' => $items[$delta]->reference ?? NULL,
];
$element['context'] = [
'#type' => 'entity_autocomplete',
'#target_type' => 'taxonomy_term',
'#tags' => TRUE,
'#match_operator' => 'CONTAINS',
'#size' => 60,
'#placeholder' => '',
'#title' => 'Context',
'#default_value' => $items[$delta]->context ?? NULL,
'#selection_settings' => [
'target_bundles' => ['component_contexts'],
],
];
$element['start_date'] = [
'#type' => 'number',
'#title' => 'Start Date (Year)',
'#size' => 4,
'#default_value' => $items[$delta]->start_date ?? NULL,
];
$element['end_date'] = [
'#type' => 'number',
'#title' => 'End Date (Year)',
'#size' => 4,
'#default_value' => $items[$delta]->end_date ?? NULL,
];
if ($this->fieldDefinition->getFieldStorageDefinition()->getCardinality() == 1) {
$element += [
'#type' => 'fieldset',
'#attributes' => ['class' => ['container-inline']],
];
}
return $element;
}
And also a screenshot of devel output via kint, which shows the structure of the field data after being processed by my massage form values method:
Can anyone tell me what I'm getting wrong here? And why is the Drupal error message so vague? Any and all help is greatly appreciated, Cheers!