Summary

In Drupal 7, core entity forms were very similar in their basic functionality but each entity type replicated more or less the same code to implement more or less the same logic. In Drupal 8, this logic has been abstracted into entity form controllers.

An entity form controller is an object implementing the EntityFormControllerInterface responsible for handling the entity form workflow: from building the form to performing validation and submission tasks. The base implementation provides the common logic and will exploit the Entity Field API to generalize most of its tasks, so that only minimal custom logic will need to be provided in the entity-specific subclasses.

Entity form controllers differ from storage controllers in the sense that an entity can have multiple form controllers, each one responsible for managing a different kind of operation. This way we can have, for instance, different controllers for the regular create/edit form and the deletion/deletion confirmation ones. See the examples below for more on this.

Regardless of the operation, the controller defines standard methods to build the entity from the submitted values and retrieve it from the form state, thus providing a more consistent and reliable API to code altering the entity form workflow. The controller itself is stored into the form state and can be retrieved by any form handler/callback. Entity forms can now be identified easily because they have form controllers which implement EntityFormControllerInterface.

API changes

There were previously two common ways to get the entity being operated on: for a node entity,

$node = $form_state['node']

$node = $form['#node']

Both of these methods are now deprecated, and will stop working in the future. The new recommended way to get the entity being operated on is

$entity = $form_state->getFormObject()->getEntity().

Form IDs for entity forms are now automatically generated by entity_form_id(). Most form IDs have stayed the same, but some have changed to make form IDs more consistent. The form IDs that have changed are:

taxonomy_form_term has been renamed to taxonomy_term_form

taxonomy_form_vocabulary has been renamed to taxonomy_vocabulary_form

The form functions for entities such as node_form() have been removed and replaced with entity form controllers.

The form functions that have been removed are:

node_form()

comment_form()

user_profile_form()

user_account_form()

user_register_form()

taxonomy_form_term()

New API functions have been introduced:

entity_form_controller() can be used to instantiate a new form controller class for the given operation

entity_form_state_defaults() provides a form state stub with the build info properly populated to build an entity form

entity_get_form() returns a processed entity form for the given operation. It replaces drupal_get_form() for entity forms.

entity_form_submit() submits an entity form with the given form state

The previous hook_node_prepare() has been replaced by a generic hook_entity_prepare_form() and an entity-type-specific version including hook_node_prepare_form(). The hook signature has changed to include, besides the entity object, the current form display, the current operation and the form state.