8

hello i am trying to create a custom field type in drupal 8 containing two text fields and an entity reference field to a user , but i get this error when i try to save .

Error: Call to undefined method Drupal\Core\TypedData\DataDefinition::getTargetDefinition() in Drupal\Core\Entity\Plugin\DataType\EntityReference->getTargetDefinition() (line 51 of core/lib/Drupal/Core/Entity/Plugin/DataType/EntityReference.php).

below is my custom field definition :

public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    // Prevent early t() calls by using the TranslatableMarkup.


    $properties = [];

    $properties['street'] = DataDefinition::create('string')
      ->setLabel(t('Street'));

    $properties['city'] = DataDefinition::create('string')
      ->setLabel(t('City'));


    $properties['user']   = DataDefinition::create('entity_reference')
            ->setLabel(t('user'))
            ->setSetting('target_type', 'user');


    return $properties;
 }

Any help or tip would be very welcome , thank you :)

2
  • 2
    You mind sharing your use case? It would be so much easier to use the address module and an existing entity reference field. Mar 9, 2017 at 17:48
  • 1
    yes , i am playing around testing things on drupal 8 custom field types and bumped on this problem . thank you Mar 9, 2017 at 17:56

1 Answer 1

15
+25

EntityReferenceItem is more complicated than just the "entity" DataReferenceDefinition.

It has a DataReferenceDefinition for "target_id" as well.

I solved a similar issue by extending EntityReferenceItem.

Then you can get the entity from the parent definition, which is a bit long and complex and then just add your custom fields on top:

  /**
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties = parent::propertyDefinitions($field_definition);

    $properties['street'] = DataDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Title'));

    $properties['city'] = DataDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Title'));

    return $properties;
  }

Here's the code I used to add one text field to an EntityReferenceItem:

namespace Drupal\mymodule\Plugin\Field\FieldType;

use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Validation\Plugin\Validation\Constraint\AllowedValuesConstraint;
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
use Drupal\Component\Utility\Random;

/**
 * Defines the 'entity_reference' entity field type.
 *
 * Supported settings (below the definition's 'settings' key) are:
 * - target_type: The entity type to reference. Required.
 *
 * @FieldType(
 *   id = "entity_reference_with_title",
 *   label = @Translation("Entity reference with title"),
 *   description = @Translation("An entity field containing an entity reference and a text field."),
 *   category = @Translation("Custom"),
 *   default_widget = "entity_reference_with_title_autocomplete",
 *   default_formatter = "entity_reference_with_title_entity_view",
 *   list_class = "\Drupal\Core\Field\EntityReferenceFieldItemList",
 * )
 */
class EntityReferenceWithTitle extends EntityReferenceItem {

  /**
   * {@inheritdoc}
   */
  public static function defaultStorageSettings() {
    return array(
      'target_type' => \Drupal::moduleHandler()->moduleExists('node') ? 'node' : 'user',
      'title' => '',
    ) + parent::defaultStorageSettings();
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultFieldSettings() {
    return array(
      'handler' => 'default',
      'handler_settings' => array(),
    ) + parent::defaultFieldSettings();
  }

  /**
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties = parent::propertyDefinitions($field_definition);

    $properties['title'] = DataDefinition::create('string')
      ->setLabel(new TranslatableMarkup('Title'));

    return $properties;
  }

  /**
   * {@inheritdoc}
   */
  public static function mainPropertyName() {
    return 'target_id';
  }

  /**
   * {@inheritdoc}
   */
  public static function schema(FieldStorageDefinitionInterface $field_definition) {

    $schema = parent::schema($field_definition);

    $schema['columns'] = array(
      'title' => array(
        'type' => 'varchar',
        'length' => 255,
      ),
      'target_id' => $schema['columns']['target_id'],
    );

    return $schema;
  }

  /**
   * {@inheritdoc}
   */
  public function getConstraints() {
    $constraints = FieldItemBase::getConstraints();
    // Remove the 'AllowedValuesConstraint' validation constraint because entity
    // reference fields already use the 'ValidReference' constraint.
    foreach ($constraints as $key => $constraint) {
      if ($constraint instanceof AllowedValuesConstraint) {
        unset($constraints[$key]);
      }
    }
    return $constraints;
  }

  /**
   * {@inheritdoc}
   */
  public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
    $manager = \Drupal::service('plugin.manager.entity_reference_selection');
    if ($referenceable = $manager->getSelectionHandler($field_definition)->getReferenceableEntities()) {
      $random = new Random();
      $group = array_rand($referenceable);
      $values['target_id'] = array_rand($referenceable[$group]);
      $values['title'] = $random->sentences(2);
      return $values;
    }
  }

}
3

Your Answer

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

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