0

For a project I am using custom defined entities. One is called "Country" and it has a name and country_code field.

The entity itself should be translatable for multiple reasons. The name and entity is marked as translatable and the translation of an entity throu Entity API works with no problem.

I wanted to use a custom service to check if a country code exists

public function checkIfValidCountryCode($country_code) {

  $query = \Drupal::entityQuery('country');

  $query->condition('country_code', $country_code);

  $result = $query->execute();


  if(empty($result)) {
    return FALSE;
  } else {
    return TRUE;
  }

}

but it throws an exception

The website encountered an unexpected error. Please try again later.

Drupal\Core\Entity\Query\QueryException: 'country_code' not found in Drupal\Core\Entity\Query\Sql\Tables->ensureEntityTable() (line 316 of core/lib/Drupal/Core/Entity/Query/Sql/Tables.php).
Drupal\Core\Entity\Query\Sql\Tables->addField('country_code', 'INNER', NULL) (Line: 44)
Drupal\Core\Entity\Query\Sql\Condition->compile(Object) (Line: 155)
Drupal\Core\Entity\Query\Sql\Query->compile() (Line: 74)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 46)

I really wrote it down exactly as defined in my Entity class:

namespace Drupal\custom_country\Entity;

use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\custom_country\CountryInterface;
use Drupal\user\UserInterface;

/**
 * Defines the Country entity.
 *
 * @ingroup custom_country
 *
 * @ContentEntityType(
 *   id = "country",
 *   label = @Translation("Country"),
 *   handlers = {
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
 *     "list_builder" = "Drupal\custom_country\CountryListBuilder",
 *     "views_data" = "Drupal\custom_country\Entity\CountryViewsData",
 *
 *     "form" = {
 *       "default" = "Drupal\custom_country\Form\CountryForm",
 *       "add" = "Drupal\custom_country\Form\CountryForm",
 *       "edit" = "Drupal\custom_country\Form\CountryForm",
 *       "delete" = "Drupal\custom_country\Form\CountryDeleteForm",
 *     },
 *     "access" = "Drupal\custom_country\CountryAccessControlHandler",
 *     "route_provider" = {
 *       "html" = "Drupal\custom_country\CountryHtmlRouteProvider",
 *     },
 *   },
 *   base_table = "country",
 *   admin_permission = "administer country entities",
 *   translatable = TRUE,
 *   entity_keys = {
 *     "id" = "id",
 *     "label" = "name",
 *     "uuid" = "uuid",
 *     "langcode" = "langcode",
 *     "status" = "status",
 *     "country_code" = "country_code"
 *   },
 *   links = {
 *     "canonical" = "/admin/custom/country/{country}",
 *     "add-form" = "/admin/custom/country/add",
 *     "edit-form" = "/admin/custom/country/{country}/edit",
 *     "delete-form" = "/admin/custom/country/{country}/delete",
 *     "collection" = "/admin/custom/country",
 *   },
 *   field_ui_base_route = "country.settings"
 * )
 */
class Country extends ContentEntityBase implements CountryInterface {
  use EntityChangedTrait;
  /**
   * {@inheritdoc}
   */
  public static function preCreate(EntityStorageInterface $storage_controller, array &$values) {
    parent::preCreate($storage_controller, $values);
    $values += array(
      'user_id' => \Drupal::currentUser()->id(),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getName() {
    return $this->get('name')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setName($name) {
    $this->set('name', $name);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getCreatedTime() {
    return $this->get('created')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setCreatedTime($timestamp) {
    $this->set('created', $timestamp);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getOwner() {
    return $this->get('user_id')->entity;
  }

  /**
   * {@inheritdoc}
   */
  public function getOwnerId() {
    return $this->get('user_id')->target_id;
  }

  /**
   * {@inheritdoc}
   */
  public function setOwnerId($uid) {
    $this->set('user_id', $uid);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function setOwner(UserInterface $account) {
    $this->set('user_id', $account->id());
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function isPublished() {
    return (bool) $this->getEntityKey('status');
  }

  /**
   * {@inheritdoc}
   */
  public function setPublished($published) {
    $this->set('status', $published ? NODE_PUBLISHED : NODE_NOT_PUBLISHED);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getCountryCode() {
    return $this->get('country_code')->value;
  }

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {

    //ID field
    $fields['id'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('ID'))
      ->setDescription(t('The ID of the Country entity.'))
      ->setReadOnly(TRUE)
    ;

    //UUID field
    $fields['uuid'] = BaseFieldDefinition::create('uuid')
      ->setLabel(t('UUID'))
      ->setDescription(t('The UUID of the Country entity.'))
      ->setReadOnly(TRUE)
    ;

    $fields['langcode'] = BaseFieldDefinition::create('language')
      ->setLabel(t('Language code'))
      ->setDescription(t('The language code for the Country entity.'))
      ->setDisplayOptions('form', array(
        'type' => 'language_select',
        'weight' => 10,
      ))
      ->setDisplayConfigurable('form', TRUE)
    ;

    //Version
    $fields['country_code'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Country Code'))
      ->setDescription(t('Country Code in lower case. Examples: ch, de, fr, etc.'))
      ->setRevisionable(FALSE)
      ->setTranslatable(FALSE)
      ->setRequired(TRUE)
      ->setSettings(array(
        'default_value' => '',
        'max_length' => 2,
        'text_processing' => 0,
      ))
      ->setDisplayOptions('view', array(
        'label' => 'above',
        'type' => 'string',
        'weight' => 0,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'string_textfield',
        'weight' => 0,
      ))
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE)
    ;

    $fields['name'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Name'))
      ->setDescription(t('The name of the Country entity.'))
      ->setRequired(TRUE)
      ->setRevisionable(FALSE)
      ->setTranslatable(TRUE)
      ->setSettings(array(
        'max_length' => 255,
        'text_processing' => 0,
      ))
      ->setDefaultValue('')
      ->setDisplayOptions('view', array(
        'label' => 'above',
        'type' => 'string',
        'weight' => 0,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'string_textfield',
        'weight' => 0,
      ))
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE)
    ;

    $fields['status'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Publishing status'))
      ->setDescription(t('A boolean indicating whether the Country is published.'))
      ->setDefaultValue(TRUE)
    ;

    $fields['created'] = BaseFieldDefinition::create('created')
      ->setLabel(t('Created'))
      ->setDescription(t('The time that the entity was created.'))
    ;

    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Changed'))
      ->setDescription(t('The time that the entity was last edited.'))
    ;

    return $fields;
  }

}

I googled pretty much everywhere but could not find what I did wrong.

Can anybody help me?

  • Does that field actually exist in the entity? Like you can create and load them and see it?(load with ::load($id)) – Kevin Apr 11 '17 at 13:07
  • @Kevin Jep it does. Used Country::load(2) to load it and printed it via Kint. All goes well. – Martin Apr 11 '17 at 15:00
  • Did you find any solution? – johndevman Aug 17 '17 at 14:11
  • @johndevman Nope, not yet. Was able to find a workaround but not a solution. – Martin Aug 21 '17 at 7:47
  • Had similar issue: @Martin See my answer. – johndevman Aug 21 '17 at 7:50
1

You are missing data_table in your Entity annotation. Add:

data_table = "country_field_data"

And it should work as expected. And update the entity using something like Drush: drush entity-updates

| improve this answer | |
  • yep, that was it. – Martin Sep 8 '17 at 9:25
0

I would try the followings:

  • With phpymyadmin (or similiar) checking if the schema of your table (country) is just looking the same as expected based on the country entity type annotation/basefields.
  • Maybe you creating process of your entity type was "step by step" and you need to run drush entup or similiar to update your entity schema.
  • I would also try to make the same query with \Drupal::database()->select(...) or with
    \Drupal::entityTypeManager()->getStorage('country')->loadByProperties([])

It's indeed very strange that entityQuery is trying to find a basefield in a different table.

| improve this answer | |
  • Yep, I already tried using the Database query and it works but Drupal itself uses entityQueries itself, when editing the entity via /admin/custom/country/[number]/ there will be an autocomplete field and it uses entityQuery. So one way or another, I need to get this problem fixed. – Martin Apr 11 '17 at 15:02
  • Sure thing! But at least that's a good starting point to investigate! – ssibal Apr 11 '17 at 20:59

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.