0

I'm having a very bizarre issue with an entity relationship in my models. I have 4 entity classes within Drupal: DogEntity, BaseAnimalEntity, BaseToyEntity, DogToyEntity. The following entity relationship is expressed: DogEntity -> DogToyEntity.

I can see that the DogEntity table has a concrete value in the DogToyEntity column of the database. However, when I load the DogEntity entity, and then try to load the DogToyEntity from the DogEntity's id it returns a null value. I don't understand why this is happening.

Below are the class definitions for the classes:

BaseAnimal Class:

abstract class BaseAnimal extends ContentEntityBase implements BaseAnimalInterface {
    /**
     * Everything is implemented correctly, the entity is created correctly
     * So I'm leaving stuff out for brevity
     */

    public function getArbitraryField() {
        // all getXFunctions follow the form: $this->get('value')->value;
        return $this->get('arbitrary_field')->value;
    }

    public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
        $fields = parent::baseFieldDefinitions($entity_type);

        // Standard field, used as unique if primary index.
        $fields['id'] = BaseFieldDefinition::create('integer')
            ->setLabel(t('ID'))
            ->setDescription(t('The ID of the entity.'))
            ->setReadOnly(TRUE);
        // Standard field, unique outside of the scope of the current project.
        $fields['uuid'] = BaseFieldDefinition::create('uuid')
            ->setLabel(t('UUID'))
            ->setDescription(t('The UUID of the entity.'))
            ->setReadOnly(TRUE);

        // elided other fields for brevity.

        return $fields;
    }
}

Dog Class:

/**
 * @ContentEntityType(
 *   id = "dog"
 *   ... eliding
 */
public class Dog extends BaseAnimal implements DogInterface {
    /**
     * Everything is implemented correctly, the entity is created correctly
     * So I'm leaving stuff out for brevity
     */

    public function getOtherArbitraryField() {
        // all getXFunctions follow the form: $this->get('value')->value;
        return $this->get('other_arbitrary_field')->value;
    }

    public function setDogToy(int $value) {
        $this->set('dog_toy_id', $value);
        return $this;
    }

    public function getDogToy() {
        return $this->get('dog_toy_id')->value;
    }

    public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
        $fields = parent::baseFieldDefinitions($entity_type);
        $fields['dog_toy_id'] = BaseFieldDefinition::create('entity_reference')
            ->setLabel(t('Dog Toy'))
            ->setDescription(t('Dog\'s favorite toy.'))
            ->setSetting('target_type', 'dog_toy')
            ->setSetting('handler', 'default')
            ->setDisplayOptions('view', array(
                'label' => 'above',
                'weight' => -3,
              ))
            ->setDisplayConfigurable('view', TRUE);
        return $fields;
    }
}

Base Toy Class:

abstract class BaseToy extends ContentEntityBase implements BaseToyInterface {
    /**
     * Everything is implemented correctly, the entity is created correctly
     * So I'm leaving stuff out for brevity
     */

    public function getArbitraryField() {
        // all getXFunctions follow the form: $this->get('value')->value;
        return $this->get('arbitrary_field')->value;
    }

    public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
        $fields = parent::baseFieldDefinitions($entity_type);

        // Standard field, used as unique if primary index.
        $fields['id'] = BaseFieldDefinition::create('integer')
            ->setLabel(t('ID'))
            ->setDescription(t('The ID of the entity.'))
            ->setReadOnly(TRUE);
        // Standard field, unique outside of the scope of the current project.
        $fields['uuid'] = BaseFieldDefinition::create('uuid')
            ->setLabel(t('UUID'))
            ->setDescription(t('The UUID of the entity.'))
            ->setReadOnly(TRUE);

        // elided other fields for brevity.

        return $fields;
    }
}

Dog Toy Class:

/**
 * @ContentEntityType(
 *   id = "dog_toy"
 *   ... eliding
 */
public class DogToy extends BaseToy implements DogToyInterface {
    /**
     * Everything is implemented correctly, the entity is created correctly
     * So I'm leaving stuff out for brevity
     */

    public function getOtherArbitraryField() {
        // all getXFunctions follow the form: $this->get('value')->value;
        return $this->get('other_arbitrary_field')->value;
    }

    public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
        $fields = parent::baseFieldDefinitions($entity_type);
        // Unnecessary fields elided for brevity.
        return $fields;
    }
}

So these entities are created and work correctly. The problem comes when I do something like:

$dog = Dog::create($fields);
$dog->save(); // now has ID of 1.

// do some other things...

$toy = DogToy::create($other_fields);
$toy->save(); // now has ID of 1.

// do some other things...

$dog->setDogToy($toy->id());
$dog->save();  // Now Dog->dog_toy_id = 1.

The above works perfectly. The database will be populated with the appropriate relationship, and I'm happy.

Then I'll try to do something like:

$dog = Dog::load(1); // loads correctly
var_dump($dog); // In here, the value of dog_toy_id is set correctly to 1, see above.
$toy = DogToy::load($dog->getDogToy());
var_dump($toy); // and $toy will be NULL

I've tried several sorts of seemingly trivial troubleshooting, debugging, etc. But I don't understand what is happening. I can see that dog_toy_id is set within the Dog class and that the column has a 1 on the Dog table. Something is happening in that Toy::load() and I don't understand what it is.

1 Answer 1

2

The entity reference field has no value property. Use target_id in Dog::getDogToy() instead:

public function getDogToy() {
    return $this->get('dog_toy_id')->target_id;
}

Or entity to get the entity directly:

public function getDogToy() {
    return $this->get('dog_toy_id')->entity;
}

Then you don't need to load the DogToy entity:

$toy = $dog->getDogToy();
2
  • Thank you for this. I looked trough the documentation and I didn't see this. Clearly I missed something. Entity Reference API is where I looked.
    – lilott8
    Aug 7, 2017 at 17:46
  • Yes, for a base field you don't see this in the database. For a bundle field you would have found this out by looking at the column header. To check the main property of a field, see api.drupal.org/api/drupal/…
    – 4uk4
    Aug 7, 2017 at 18:06

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.