by Kristof De Jaeger // swentel
today 13:00, same room
by Tobias Stöckler // tstoeckler
Friday, 10:00 in room Ursa Minor
Photo source: Metro Centric, flickr.com/people/16782093@N03
Class based entity objects
ContentEntityInterface extends EntityInterface ConfigEntityInterface extends EntityInterface
Photo source: Bob Jagendorf, flickr.com/photos/bobjagendorf/
$manager = \Drupal::entityManager();
$entity = $manager ->getStorageController('comment') ->load($id);$entity->getEntityTypeId();
$entity->label();
$entity->id();
$entity_type = $entity_manager
->getDefinition('node');
$entity_type->id() == 'node'
$entity_type
->getClass()
$entity_type
->hasKey('label')
$entity_type
->isSubclassOf('ContentEntityInterface')
echo $entity->subject->value;
$tag = $entity ->field_tags[2] ->entity ->name->value;
$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() == 'de';$translation->title->value = 'German title';
$translation = $manager ->getTranslationFromContext($entity);
echo $translation->label();
$entity = $translation->getUntranslated();
foreach ($entity as $field_name => $items) {
$items instanceof FieldItemListInterface
foreach ($items as $item) {
$item instanceof FieldItemInterface
echo $item->target_id;
echo $item->entity->label();
}
}
=
(Node title, Node id, User name, User roles, ...)
+
(Node body, Node tags, User tags, ... - all configurable fields)
hook_entity_base_field_info()
hook_entity_base_field_info_alter()
hook_entity_bundle_field_info()hook_entity_bundle_field_info_alter()
$module = $field_definition->getProvider();
allow you to
compute field item properites
when they are accessed.
echo $node->body->processed;
echo $node->uid->entity->label();
$field_definitions =
$em->getBaseFieldDefinitions($entity_type_id);$field_definitions =
$em->getFieldDefinitions($etype_id, $bundle);
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\CommentStorageController",
* "access" = "Drupal\comment\CommentAccessController",
* "view_builder" = "Drupal\comment\CommentViewBuilder",
* "form" = {
* "default" = "Drupal\comment\CommentFormController",
* "delete" = "Drupal\comment\Form\DeleteForm"
* },
* "translation" = "Drupal\comment\CommentTranslationController"
* },
* 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);
$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'))
->setRequired(TRUE)
->setTranslatable(TRUE)
->setRevisionable(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);
class CommentStorageController extends FieldableDatabaseStorageController implements CommentStorageControllerInterface {
/**
* {@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->getStorageController('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);
\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
->getListController('contact_category')
->render();
provide re-usable functionality
based upon
a well-defined interface
allow you to easily
customize certain aspects of
your entity type
II
V
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) {
...
outside of
your storage controller
(or entity query service)
/**
* Defines the Node type configuration entity.
*
* @ConfigEntityType(
* id = "node_type",
* label = @Translation("Content type"),
* controllers = {
* "access" = "Drupal\node\NodeTypeAccessController",
* "form" = {
* "add" = "Drupal\node\NodeTypeFormController",
* "edit" = "Drupal\node\NodeTypeFormController",
* "delete" = "Drupal\node\Form\NodeTypeDeleteConfirm"
* },
* "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 ConfigEntityBase 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()
Helps REST, Rules, CTools, Search api, Tokens, ...
(mostly)
Angelo DeSantis, flickr.com/photos/angeloangelo
(no UI exposure required)
[META] Complete the Entity Field API
http://drupal.org/node/2095603