Creating or Updating Entities on Form Submissionfor Drupal 8 , 9 , 10 , and 11

Last updated :  

Most "real" forms on a Drupal site exist to create or update a piece of content — a node, a custom entity, a config entity like the Examples module's Robot. Rather than manually writing INSERT/UPDATE SQL, Drupal's entity API lets a form work with a PHP object that already knows how to save itself.

What you'll learn in this lesson

  • How EntityForm gives your form class access to $this->entity
  • How a field's default submit handler saves that entity for you
  • How to tell, inside submitForm(), whether you just created or updated a record

Extending EntityForm instead of FormBase

class RobotFormBase extends EntityForm {
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildForm($form, $form_state);
    $robot = $this->entity;

    $form['label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Label'),
      '#default_value' => $robot->label(),
      '#required' => TRUE,
    ];
    return $form;
  }
}

This is the real base class the Drupal Examples module's Robot config entity forms extend. EntityForm automatically provides $this->entity — either a freshly-created blank entity (add form) or the existing one loaded from the URL (edit form). Every field's #default_value reads straight from it, so the same buildForm() works correctly for both adding and editing.

Where the actual save happens

EntityForm's own default submitForm() copies each form value onto the entity via $this->entity = $this->buildEntity($form, $form_state), and its default save() method (a separate method, called automatically after submitForm()) calls $this->entity->save(). You get real entity persistence without writing a single explicit save call, as long as you don't override those methods yourself.

Detecting create vs. update

public function save(array $form, FormStateInterface $form_state) {
  $robot = $this->entity;
  $status = $robot->save();

  if ($status === SAVED_NEW) {
    $this->messenger()->addMessage($this->t('Created the %label robot.', ['%label' => $robot->label()]));
  }
  else {
    $this->messenger()->addMessage($this->t('Updated the %label robot.', ['%label' => $robot->label()]));
  }
}

Overriding save() (not submitForm()) is the normal way to customize what happens after an EntityForm persists its entity. The return value of $entity->save() is either the constant SAVED_NEW or SAVED_UPDATED, letting you give the user an accurate confirmation message either way.

Gotcha: if your class extends EntityForm and you override submitForm() yourself without calling parent::submitForm(), the entity never gets built from the submitted values in the first place — your custom save() override would then be saving a stale, unpopulated entity. Prefer overriding save() over submitForm() for entity forms specifically.

Quick check: on an EntityForm-based form, which method should you override to add a custom "confirmation message" after saving — submitForm() or save()? save() — it runs after the entity has already been built and persisted, and its return value tells you whether the save was a create or an update.

Key takeaways

  • Extend EntityForm (not plain FormBase) to get a form pre-wired to a specific entity via $this->entity.
  • The same buildForm() handles both add and edit, since #default_value always reads from the current entity state.
  • Override save(), not submitForm(), to customize post-save behavior on an entity form.
  • $entity->save() returns SAVED_NEW or SAVED_UPDATED — use it to give an accurate confirmation message.

Coming up next

Entities aren't the only kind of data a form submission needs to handle. The next lesson covers a genuinely trickier case: saving uploaded files correctly during submission.