Photo source: Metro Centric, flickr.com/people/16782093@N03
ContentEntityInterface extends EntityInterface ConfigEntityInterface extends EntityInterface
Photo source: Bob Jagendorf, flickr.com/photos/bobjagendorf/
$manager = \Drupal::entityManager();
$entity = $manager ->getStorage('comment') ->load($id);
$entity = Comment::load($id);$user = User::create(array('name' => 'me'));
$entity->getEntityTypeId();
$entity->label();
$entity->id();
echo $entity->subject->value;
$term_id = $entity ->field_tags[2] ->target_id;
$entity->hasField($field_name);
$entity = $field_item->getEntity();
$entity->title->value = 'new Title';
$entity->save();
if ($node->isPromoted()) {
$title = $node->getTitle();
}
elseif ($node->isPublished()) {
$node->setTitle(
$node->getAuthor()
->getUsername()
);
}
echo $entity ->getTranslation('de') ->title->value;
$translation = $entity->getTranslation('de');
$translation->language()->id == 'de';$translation->title->value = 'German title';
$translation = $manager ->getTranslationFromContext($entity);
echo $translation->label();
$entity = $translation->getUntranslated();
$entity_type = $entity_manager
->getDefinition('node');
$entity_type->id() == 'node'
$entity_type
->getClass()
$entity_type
->hasKey('label')
$entity_type
->isSubclassOf('ContentEntityInterface')
$field_definition = $entity-> getFieldDefinition($field_name); $field_definition->getName(); $field_definition->getPropertyDefinitions();
$entity_manager ->getFieldDefinitions('node', 'article');
foreach ($entity as $field_name => $items) {
$items instanceof FieldItemListInterface;
foreach ($items as $item) {
$item instanceof FieldItemInterface;
echo $item->target_id;
}
}
=
(Node title, Node id, User name, User roles, ...)
+
(Node body, Node tags, User tags, ... - all configurable fields)
$entity_manager-> getFieldStorageDefinitions('node');
hook_entity_base_field_info();
hook_entity_base_field_info_alter();
hook_entity_bundle_field_info();
hook_entity_bundle_field_info_alter();
hook_entity_field_storage_info();
hook_entity_field_storage_info_alter();
$module = $field_definition->getProvider();
allow you to
compute field item properties
when they are accessed.
echo $node->body->processed;
echo $node->uid->entity->label();
is_string($node->title) == FALSE
is_string($view->name) == TRUE
/**
* Defines the comment entity class.
*
* @ContentEntityType(
* id = "comment",
* label = @Translation("Comment"),
* bundle_label = @Translation("Content type"),
* controllers = {
* "storage" = "Drupal\comment\CommentStorage",
* "access" = "Drupal\comment\CommentAccessController",
* "view_builder" = "Drupal\comment\CommentViewBuilder",
* "form" = {
* "default" = "Drupal\comment\CommentForm",
* "delete" = "Drupal\comment\Form\DeleteForm"
* },
* "translation" = "Drupal\comment\CommentTranslationHandler"
* },
* base_table = "comment",
* uri_callback = "comment_uri",
* fieldable = TRUE,
* translatable = TRUE,
* entity_keys = {
* "id" = "cid",
* "bundle" = "field_id",
* "label" = "subject",
* "uuid" = "uuid"
* },
* links = {
* "canonical" = "comment.permalink",
* "delete-form" = "comment.confirm_delete",
* "edit-form" = "comment.edit_page",
* "admin-form" = "comment.bundle"
* }
* )
*/
class Comment extends ContentEntityBase implements CommentInterface {
class Comment extends ContentEntityBase implements CommentInterface {
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields['cid'] = FieldDefinition::create('integer')
->setLabel(t('Comment ID'))
->setDescription(t('The comment ID.'))
->setReadOnly(TRUE) ->setSetting('unsigned', TRUE);$fields['uuid'] = FieldDefinition::create('uuid')
->setLabel(t('UUID'))
->setDescription(t('The comment UUID.'))
->setReadOnly(TRUE);
$fields['pid'] = FieldDefinition::create('entity_reference')
->setLabel(t('Parent ID'))
->setSetting('target_type', 'comment')
return $fields;
}
}
$fields['title'] = FieldDefinition::create('string')
->setLabel(t('Title'))// ...
->setDisplayOptions('view', array(
'label' => 'hidden',
'type' => 'string',
'weight' => -5,
))
->setDisplayOptions('form', array(
'type' => 'string',
'weight' => -5,
))
->setDisplayConfigurable('form', TRUE);
FieldDefinition::create('created')
->setLabel(t('Created')) ->setRevisionable(TRUE) ->setTranslatable(TRUE);
class CommentStorage extends ContentEntityDatabaseStorage implements CommentStorageInterface {
/**
* {@inheritdoc}
*/
public function getMaxThread(EntityInterface $comment) {
$query = $this->database->select('comment', 'c')
->condition('entity_id', $comment->entity_id->value)
->condition('field_id', $comment->field_id->value)
->condition('entity_type', $comment->entity_type->value);
$query->addExpression('MAX(thread)', 'thread');
return $query->execute()
->fetchField();
}
}
$manager->getStorage('comment')->save($comment);
class Comment extends ContentEntityBase implements CommentInterface {
/**
* {@inheritdoc}
*/
public function postSave($storage, $update = TRUE) {
parent::postSave($storage, $update);
$this->releaseThreadLock();
//...
}
}
$manager->getViewBuilder('comment')->view($comment);
class DeleteForm extends ContentEntityConfirmFormBase { /** * {@inheritdoc} */ public function getQuestion() { return $this->t('Are you sure you want to delete the comment %title?', array('%title' => $this->entity->subject->value)); }
} \Drupal::service('entity.form_builder')
->getForm($comment);\Drupal::service('entity.form_builder')
->getForm($comment, 'delete');
/**
* Access controller for the comment entity.
*
* @see \Drupal\comment\Entity\Comment.
*/
class CommentAccessController extends EntityAccessController {
// ...
}
$manager->getAccessController('comment')
->access($comment, 'view');
$entityManager
->getListBuilder('contact_category')
->render();
provide re-usable functionality
based upon
a well-defined interface
allow you to easily
customize certain aspects of
your entity type
allow you to provide
re-usable behaviour along with storage
(no UI)
-function path_entity_insert(EntityInterface $entity) {
- if ($entity instanceof ContentEntityInterface && $entity->hasField('path')) {
- ....
+ class PathItem extends FieldItemBase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function insert() {
+ ....
"created" field
$fields['mail'] = FieldDefinition::create('email')
->setLabel(t('Email'))
->setDescription(t('The email of this user.'))
->setSetting('default_value', '')
->setPropertyConstraints(
'value',
array('UserMailUnique' => array()
));
$violations = $entity->validate();
// PASSED!!!
$this->assertEqual($violations->count(), 0);
// Try setting a too long string as UUID.
$test_entity->uuid->value = $this->randomString(129);
$violations = $test_entity->validate();
$this->assertTrue($violations->count() > 0);
// FAILED!!!
$violation = $violations[0];
echo $violation->getMessage();
$violation->getRoot() === $entity';
$violation->getPropertyPath() == 'field_test_text.0.format'
$violation->getInvalidValue();
/**
* Range constraint.
*
* Overrides the symfony constraint to use Drupal-style replacement patterns.
*
* @Plugin(
* id = "Range",
* label = @Translation("Range", context = "Validation"),
* type = { "integer", "float" }
* )
*/
class RangeConstraint extends Range {
public $minMessage = 'This value should be %limit or more.';
public $maxMessage = 'This value should be %limit or less.';
/**
* Overrides Range::validatedBy().
*/
public function validatedBy() {
return '\Symfony\Component\Validator\Constraints\RangeValidator';
}
}
// Make sure there are no active blocks for these feeds.
$ids = \Drupal::entityQuery('block')
->condition('plugin', 'aggregator_feed_block')
->condition('settings.feed', array_keys($entities))
->execute();
if ($ids) {
...
/**
* Defines the Node type configuration entity.
*
* @ConfigEntityType(
* id = "node_type",
* label = @Translation("Content type"),
* controllers = {
* "access" = "Drupal\node\NodeTypeAccessController",
* "form" = {
* "add" = "Drupal\node\NodeTypeForm",
* // ..
* },
* "list_builder" = "Drupal\node\NodeTypeListBuilder",
* },
* admin_permission = "administer content types",
* config_prefix = "type",
* bundle_of = "node",
* entity_keys = {
* "id" = "type",
* "label" = "name"
* },
* links = {
* "add-form" = "node.add",
* "edit-form" = "node.type_edit",
* "delete-form" = "node.type_delete_confirm"
* }
* )
*/
class NodeType extends ConfigEntityBundleBase implements NodeTypeInterface {
echo $type->name;
class NodeType extends ConfigEntityBase implements NodeTypeInterface {
public $type;
public $uuid;
public $name;
public $has_title = TRUE;
public $title_label = 'Title';
//.....
}
$node_type->toArray();
node.type.*:
type: mapping
label: 'Content type'
mapping:
type:
type: string
label: 'Machine-readable name'
uuid:
type: string
label: 'UUID'
name:
type: label
label: 'Name'
description:
type: text
label: 'Description'
help:
type: text
label: 'Explanation or submission guidelines'
has_title:
type: boolean
label: 'Has title'
title_label:
type: label
label: 'Title field label'
settings:
type: mapping
label: 'Settings'
mapping:
node:
type: node.settings.node
status:
type: boolean
label: 'Enabled status of the configuration entity'
langcode:
type: string
label: 'Default language'
Helps REST, Rules, CTools, Search api, Tokens, ...
Angelo DeSantis, flickr.com/photos/angeloangelo
[META] Complete the Entity Field API
http://drupal.org/node/2095603