6

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 :)

  • 1
    You mind sharing your use case? It would be so much easier to use the address module and an existing entity reference field. – Neograph734 Mar 9 '17 at 17:48
  • yes , i am playing around testing things on drupal 8 custom field types and bumped on this problem . thank you – Malek Massoudi Mar 9 '17 at 17:56
7
+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;
    }
  }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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