Change record status: 
Project: 
Introduced in branch: 
8.x
Description: 

Drupal 8 has a new object oriented API for accessing *all* content entity data, the new Entity Field API.

This API only exists for content entities (entities that implement ContentEntityInterface) and not configuration entities.

With this API every datum (properties & fields) on an entity is accessed in unified way using a generic object oriented API based upon the lower-level Typed Data API (see below). Now, an entity solely consists of a list of fields based upon a certain type, whereas each field is represented as an object and contains a list of field item objects:

<?php
foreach ($entity as $field_name => $field_items) {
 
$item_1 = $field_items[0];
  foreach (
$field_items as $delta => $item) {
   
// Do something.
 
}
}
?>

Each field item is an object containing field values as specified by the field type, e.g. just a single 'value' or in case of an image field, the image file reference, the 'alt' text and the 'title' text.

<?php
 
echo $item->value;
 
// or for image fields
 
echo $item->fid;
  echo
$item->alt;
  echo
$item->title;
?>

This structure of fields, field items and field values is followed by every field on an entity. While some fields may be provided with the entity type (as the node title, created date, ..) others have been configured, thus are configurable via the field API. However, as all fields follow the same structure you can access their values as following:

<?php
echo $comment->subject[0]->value;
// Shortcut to use the value of the first item.
echo $comment->subject->value;
echo
$comment->comment_body->value;
?>

As noted, the API builds upon the lower-level TypedData API. The Typed Data API is a low level, generic and reusable object oriented API. Thus, each object (entity, field, field item, field value object) is "typed data", i.e. a data object based upon a specified data type which implements various interfaces (ListInterface, ComplexDataInterface, ..) defined by the Typed Data API.

Entity types have to define their base fields in the static baseFieldDefinitions() method. Core provides a number of field types that can be used for base fields like string, integer, entity_reference, uuid, language and so on. New types can be defined just like configurable field types. See Defining and using Content Entity Field definitions for the complete documentation.

The following is an example implementation:

<?php
 
/**
   * {@inheritdoc}
   */
 
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
   
$fields['nid'] = BaseFieldDefinition::create('integer')
      ->
setLabel(t('Node ID'))
      ->
setDescription(t('The node ID.'))
      ->
setReadOnly(TRUE);

   
$fields['uuid'] = BaseFieldDefinition::create('uuid')
      ->
setLabel(t('UUID'))
      ->
setDescription(t('The node UUID.'))
      ->
setReadOnly(TRUE);

   
$fields['vid'] = BaseFieldDefinition::create('integer')
      ->
setLabel(t('Revision ID'))
      ->
setDescription(t('The node revision ID.'))
      ->
setReadOnly(TRUE);

   
$fields['type'] = BaseFieldDefinition::create('entity_reference')
      ->
setLabel(t('Type'))
      ->
setDescription(t('The node type.'))
      ->
setSetting('target_type', 'node_type')
      ->
setReadOnly(TRUE);

   
$fields['langcode'] = BaseFieldDefinition::create('language')
      ->
setLabel(t('Language code'))
      ->
setDescription(t('The node language code.'));

   
$fields['title'] = BaseFieldDefinition::create('string')
      ->
setLabel(t('Title'))
      ->
setDescription(t('The title of this node, always treated as non-markup plain text.'))
      ->
setRequired(TRUE)
      ->
setTranslatable(TRUE)
      ->
setSettings(array(
       
'default_value' => '',
       
'max_length' => 255,
      ))
      ->
setDisplayOptions('view', array(
       
'label' => 'hidden',
       
'type' => 'string',
       
'weight' => -5,
      ))
      ->
setDisplayOptions('form', array(
       
'type' => 'string',
       
'weight' => -5,
      ))
      ->
setDisplayConfigurable('form', TRUE);

   
$fields['uid'] = BaseFieldDefinition::create('entity_reference')
      ->
setLabel(t('User ID'))
      ->
setDescription(t('The user ID of the node author.'))
      ->
setSettings(array(
       
'target_type' => 'user',
       
'default_value' => 0,
      ));

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

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

    return
$fields;
  }
?>

Field definition can be accessed with $entity->getFieldDefinitions() or $entityManager->getFieldDefinitions($entity_type, $bundle).

Please see the Typed Data handbook section, including the impact on entities.

To check if a certain field exists on an entity, hasField() can be used.

7.x

<?php
if (field_info_instance('node', 'field_name', 'article')) {
 
// Field exists.
}
?>

8.x

<?php
if ($node->hasField('field_name')) {
 
// Field exists.
}
?>

Additionally, Interfaces are being added for entities that provide easy access to the fixed base fields of an entity type, e.g. the file URI of a file or information about the published status of a node. Therefore, type hints should always use those interfaces.

7.x

<?php
function mymodule_file_update($file) {
  if (
$file->status)  {
   
mymodule_do_something($file->uri);
  }
}
?>

8.x

<?php
function mymoduel_file_update(\Drupal\file\FileInterface $file) {
  if (
$file->isPermanent()) {
   
my_module_do_something($file->getFileUri());
  }
}
?>

To implement a DataType in a module create a class in {module}/src/Plugin/DataType/{DataTypeName}.php.

Typed data types are defined using annotations, using the @Drupal\Core\TypedData\Annotation\DataType annotation, in the DataType plugin directory.

<?php
namespace Drupal\Core\TypedData\Plugin\DataType;

/**
 *
 * @DataType(
 *   id = "string",
 *   label = @Translation("String")
 * )
 */
class String extends PrimitiveBase implements StringInterface { }
?>

One of the most commonly-accessed properties of various objects is the id of the object. In previous versions of Drupal, one would need to access the nid for node objects, uid for user objects, the cid for comment objects, etc. In Drupal 8, you can simply access the ->id() method of the object, or if you would like to use the old way, ->nid->value, for instance.

7.x

<?php
// Access a node id.
$node->nid;
// Access a user id.
$user->uid;
// Access a comment id.
$comment->cid;
?>

8.x

<?php
// Access a node id.
$node->id();
// Access a user id.
$user->id();
// Access a comment id.
$comment->id();
?>

The following entity types have been converted to the new API as of now, they link to the interface that describes their specific methods:

Impacts: 
Module developers
Themers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done