4

I have created a custom content entity type called Course. When I installed my module, Drupal automatically created the table schema for my entity, so all the fields I defined in Course::baseFieldDefinitions() had their column in the database table course, as specified in the base_table annotation of my class.

Now I want to add an extra field to my entity. I edited the Course::baseFieldDefinitions() method to define my new field in the same way as I did with the previous ones. The problem is that I don't know how can I create the appropiate column in the database.

The relevant part of my Course entity is:

class Course extends ContentEntityBase implements CourseInterface {

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

    $fields['user_id'] = BaseFieldDefinition::create('entity_reference');
      // Settings and constraints for this field

    $fields['name'] = BaseFieldDefinition::create('string');
      // Settings and constraints for this field

    $fields['price'] = BaseFieldDefinition::create("float");
      // Settings and constraints for this field

    $fields['status'] = BaseFieldDefinition::create('boolean');
      // Settings and constraints for this field

    $fields['created'] = BaseFieldDefinition::create('created');
      // Settings and constraints for this field

    $fields['changed'] = BaseFieldDefinition::create('changed');
      // Settings and constraints for this field

    // New field being added
    $fiels["place"] = BaseFieldDefinition::create("string")
      ->setLabel(t("Place"))
      ->setDescription(t("The place of the course"))
      ->setSettings(["max_length" => 255, "text_processing" => 0])
      ->setDefaultValue("")
      ->setDisplayOptions("view", ["label" => "above", "type" => "string", "wegith" => -3])
      ->setDisplayOptions("form", ["type" => "string_textfield", "wegith" => -3]);

    return $fields;
  }

}

I've tried using the Drupal console command update:entities but it is not updating my database schema.

How could I add the place field to my database table?

  • If you haven't created Courses yet you can just reinstall the module. – ya.teck Jun 17 '16 at 9:05
  • @ya.teck thanks, but unfortunately I have already created entities, so I would need to update the schema without losing the current data. – crbelaus Jun 17 '16 at 9:21
  • 1
    You have a syntax error in your function. You wrote $fiels["place"] instead of $fields["place"] The database didn't update because you didn't add the field. Tip: When you add fields, you can see them in the entity form even before you update the database. If you don't see the field in the form then drupal didn't recognize it for a reason. – Eyal Jun 17 '16 at 13:39
  • Thank you very much, this is so embarrasing :(. After I corrected the typo, the solution provided by @googletorp worked flawlessly, so I marked it as the accepted answer. – crbelaus Jun 20 '16 at 7:31
  • You're welcome. I upvoted their answer as well. – Eyal Jun 20 '16 at 7:32
6

After installation, you need to handle updating the schema yourself. There are some different scenarios, some are more easy to deal with than others. The most complex is moving data from one field type to another which means you would have to do a migration of data.

Anyways Drupal core has the entityDefinitionUpdateManager() which can be accessed doing \Drupal::entityDefinitionUpdateManager(). This manager can do a lot of the things you need to do when you change the base fields of content entities.

Creation of a new field is pretty easy, and all you need to make your own update hook:

function hook_update_8xxx() {
  \Drupal::entityDefinitionUpdateManager()->applyUpdates();
}

This will apply all updates to all entities. This can generally be used for most things, but if there are data in Drupal has a failsafe that throws an exception to make sure it doesn't accidentally mess data up. During the beta the system attempted to handle data migration as well, but it didn't work well so it was decided that this is something module maintainers should do themselves.

  • 1
    This seems to do nothing on the database, after I execute the update the new column is not added to the course table. I don't know if it has something to do with this, but calling \Drupal::entityDefinitionUpdateManager()->getChangeSummary() returns an empty array. – crbelaus Jun 17 '16 at 9:22
  • 1
    The above solution should work. Did you apply the update using drush/console/update.php ? – Eyal Jun 17 '16 at 11:49
  • 1
    @Eyal I've written a hook_update function like the one in the @googletorp example. Then I executed drupal update:execute mymodule (I've also tried with drush updb but obtained the same result). The output shows that the update is picked allright, but the database is not changed. – crbelaus Jun 17 '16 at 12:23
  • 3
    You should not use that method in an update function. You have no control over what gets updated how. See drupal.org/node/2554101 for why this is a problem and how to do it instead. – Berdir Jun 18 '16 at 18:02
  • 3
    Never ever run applyUpdates() for all entities in hook update (api.drupal.org/api/drupal/…) You can easily broke another module's update sequence or other stuff, because this won't update only your's entities! Instead of doing that, use getFieldStorageDefinition() and updateFieldStorageDefinition(). – golddragon007 Aug 31 '17 at 9:32
4

As described in Write update functions for entity schema updates, automation removed (created on August 2015), which describes a change introduced on the 8.0.x branch, if you need to update the database schema used for an entity, you need to also implement hook_update_N() with code similar to the following one.
Since the class implementing the entity is Course, I assume the module machine name is course. Change the update number to the correct one for your module.

use Drupal\Core\StringTranslation\TranslatableMarkup;

function course_update_8110() {
  $storage_definition = BaseFieldDefinition::create("string")
    ->setLabel(new TranslatableMarkup("Place"))
    ->setDescription(new TranslatableMarkup("The place of the course"))
    ->setSettings(["max_length" => 255, "text_processing" => 0])
    ->setDefaultValue("")
    ->setDisplayOptions("view", ["label" => "above", "type" => "string", "weigth" => -3])
    ->setDisplayOptions("form", ["type" => "string_textfield", "weigth" => -3]);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('place', 'course', 'course', $storage_definition);
} 

I also fixed a typo in your code: Instead of "weight", you wrote "wegith".

The code I am showing is for adding a new field. The change record I linked shows also the code to use when existing fields are promoted to entity keys,or when the cardinality of a field with existing data is changed from single to multiple (or from multiple to single).

Before Automatic entity updates can fail when there is existing content, leaving the site's schema in an unpredictable state (one of the issues linked from the change record) was fixed, update.php had an automated system to fix the entity schema, which didn't make the entity schema state predictable for module updates.
Given the branch that removed the automatic updates, I would say that practically all the modules need to use code similar to the one I show in this answer.

1

You should execute the command with drush drush updatedb --entity-updates

  • A module should not depend from Drush being installed, and ask to user who is maintaining the site to run it. – kiamlaluno Aug 13 '18 at 20:37
  • And this is also now removed from Drupal core. – Bram Jul 8 at 11:02
1

Starting from Drupal 8.7.0 you need to use the Update API for that task, like so:

In modulename.install add a function like this:

function modulename_update_8001() {
  $field_storage_definition = BaseFieldDefinition::create('timestamp')
    ->setLabel(t('Start'))
    ->setDescription(t('The first day'))
    ->setRevisionable(FALSE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('start', $entity_type_id, $entity_type_id, $field_storage_definition);
}

Then run drush updatedb or go to Database Updates on the status report.

See https://www.drupal.org/node/3034742 for deeper understanding.

0

The code for an individual update is similar to the following one.

function my_module_update_8400() {
  $entity_manager = \Drupal::entityManager();
  $reserved = $entity_manager->getFieldStorageDefinitions('table_name')['column_name'];
  $entity_manager->onFieldStorageDefinitionCreate($reserved);
}
  • There is a service that is though for updating entity database schema. – kiamlaluno Aug 13 '18 at 20:38
  • What is the service name? Can you add a link or anything that could be helpful? – user3127648 Aug 14 '18 at 17:04
  • It's in the answer I added. – kiamlaluno Aug 20 '18 at 5:04

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.