Entities in Drupal 7 & the Entity API
-
Upload
jd-leonard -
Category
Technology
-
view
15.840 -
download
9
description
Transcript of Entities in Drupal 7 & the Entity API
Entities in Drupal 7& the Entity API
#sfdug
March 11, 2013
JD Leonard (@drupal_jd)
ModernBizConsulting.com
About Me
Computer science background Working with Drupal since 2006 Developer, architect, project manager Freelance through my business:
Modern Biz Consulting Focus on complex web application development
Agenda
Ways we represent data in D6 vs D7 Entities, entity types, & bundles Fields (formerly CCK) The Entity API contrib module How (and why) to define a custom entity Using EntityFieldQuery Defining entity property info Leveraging the Entity Metadata Wrapper
Poll
Who here is...
– Brand new to Drupal?
– A site builder?
– A module developer?
– On the business side of things? Who here has...
– Created a custom D7 entity?
– Not created a custom D7 entity?
D6 Data
(Custom database table) User Comment File Taxonomy vocabulary Taxonomy term Node
– Page, Blog post, (custom content type)
D7 Data
(Custom database table) Entity
– User
– Comment
– File
– Taxonomy vocabulary
– Taxonomy term
– Node• Page, Blog post, (custom content type)
(Custom entity type)
Entity Types
Elemental building block for most important data in Drupal 7
Represents a concept or noun Different types store different data
– Generally in a single DB table
– Eg: Node• Title, body, created timestamp, etc.
– Eg: User• Username, created timestamp, last visit timestamp, etc.
Defined using hook_entity_info()
Entity
Instance of an entity type Examples of entities from core:
– The user jdleonard with uid 80902
– The page “Drupal Rocks” with nid 44 Any entity can be loaded with entity_load()
– Eg: entity_load(‘node’, array(44, 65))• Returns an array with two nodes with nids 44 and 65
– Core provides some convenience wrappers• Eg: node_load() and user_load()
Entity Bundles
Subtype of an entity Eg: Page and Blog post
– Two content types (bundles) of node entity type Not all entity types have more than one bundle
– Eg: User• No subtypes; concept stands on its own
Why We Need Entity Bundles
Each entity type stores some data in a table
– We call these pieces of data “properties”
– Eg: node• Title, body, author (uid), created timestamp
• But not all nodes are created equal– Page may have data beyond that captured by node– Blog posts get tagged– We need fields!
CCK: Content Construction Kit (D6)
Contrib module Store additional data per content (node) content type Eg: Fivestar
– Contrib module leveraging contrib CCK API
– Allows nodes to be rated (think 1-5 stars)
– Eg: let users rate pages or blog posts
Fields (D7)
Core concept Store additional data per entity type Applies power of CCK to all entity types
– Not just nodes! Eg: Fivestar
– Contrib module leveraging core Field API
– Allows entities to be rated
– Eg: let users rate pages, blog posts, users, comments, custom entities
Entities in Core vs Contrib
Entities are a Drupal 7 core concept Core provides the “Entity API”
– Functions and hooks to define and interact with entities, entity types, and entity bundles
Everything we've discussed so far is part of Drupal 7 core (no contrib modules necessary)
Not everything “made it into” core
– Thankfully there's the “Entity API” contrib module• (confusingly named)
Entity API Contrib Module
Makes dealing with entities easier Provides full CRUD functionality
– CReate, Update, and Delete Allows definition of metadata about entities Optionally makes entity data
– Exportable (for configuration)
– Revisionable (eg: node revisions) Optional administrative UI for managing entities Object-oriented representation of entity types
A Note on Documentation
Documentation for core's Entity API is separate from that for the Entity API contrib module
In practice, you'll probably always use the Entity API contrib module
– It provides so much awesome functionality! Don't get confused
– Always install the Entity API contrib module when defining an entity
– Make sure to read the module's documentation
Contrib Modules Defining Entities
Commerce
– Commerce Product, Commerce Payment Transaction Organic Groups
– OG Membership, OG Membership Type Rules
– Rules Configuration Message (think activity stream)
– Message, Message Type, Message Type Category … and many more!
Example Custom Entity Type
TextbookMadness.com
– Classified listings for textbooks at schools
– Online price comparison shopping (prices from Amazon, Textbooks.com, etc.)
Online prices are
– Fetched from a third-party API and stored by Drupal
– Hereafter known as Offers
How Shall we Define an Offer?
We could use the UI to define an offer node with a bunch of fields to store pricing information
But there's a lot of overhead!
– Don't need/want a page (path) per offer
– Don't need/want revisions
– Don't need/want node base table information• Language (and translation info), Title, Author,
Published status, Created date, Commenting, Promoting, etc.
We want an entity!
Implement hook_schema()
$schema['tbm_offer'] = array( // SIMPLIFIED FOR SLIDE
'fields' => array(
'offer_id' => array('type' => 'serial'),
'isbn' => array('type' => 'int'),
'retailer_id' => array('type' => 'int'),
'price' => array('type' => 'int'),
'last_updated' => array('type' => 'int'),
),
'primary key' => array('offer_id')
);
Implement hook_entity_info()$entities['tbm_offer'] = array(
'label' => t('Offer'),
'plural label' => t('Offers'),
'entity class' => 'Entity',
'controller class' => 'EntityAPIController',
'module' => 'tbm',
'base table' => 'tbm_offer',
'fieldable' => FALSE,
'entity keys' => array(
'id' => 'offer_id',
));
Make an Entity Type Exportable$entities['tbm_offer'] = array(
'label' => t('Offer'),
'plural label' => t('Offers'),
'entity class' => 'Entity',
'controller class' => 'EntityAPIControllerExportable',
'module' => 'tbm',
'base table' => 'tbm_offer',
'fieldable' => FALSE, 'exportable' => TRUE,
'entity keys' => array(
'id' => 'offer_id', 'name' => 'my_machine_name'
));
Make an Entity Type Revisionable$entities['tbm_offer'] = array(
'label' => t('Offer'),
'plural label' => t('Offers'),
'entity class' => 'Entity',
'controller class' => 'EntityAPIController',
'module' => 'tbm',
'base table' => 'tbm_offer', 'revision_table' => 'tbm_o_revision',
'fieldable' => FALSE,
'entity keys' => array(
'id' => 'offer_id', 'revision' => 'revision_id',
));
Other hook_entity_info() configuration$entities['tbm_offer'] = array( …
'entity class' => 'TbmOfferEntity', // Extends Entity class
'controller class' => 'TbmOfferEntityController',
'access callback' => 'tbm_offer_access',
'admin ui' => array(
'path' => 'admin/structure/offers',
'file' => 'tbm.admin.inc',
),
'label callback' => 'entity_class_label',
'uri callback' => 'entity_class_uri',
); // TbmOfferEntity->defaultLabel(), defaultUri()
Entity Property Info
hook_entity_property_info()
– Defines entity metadata
– Provided for core entities Automatically generated from hook_schema()
– Doesn't understand foreign key relationships (references)
– Doesn't know when an integer is actually a date (eg: unix timestamps)
Fill in the gaps with hook_entity_property_info_alter()
hook_entity_property_info_alter()
$offer = &$info['tbm_offer']['properties'];
$offer['url']['type'] = 'uri'; // was a varchar in hook_schema
$offer['url']['label'] = 'URL';
$offer['last_updated']['type'] = 'date'; // integer in hook_schema
$offer['last_updated']['label'] = t('Last updated');
// Other types: text, token (machine name), integer, decimal, duration, boolean, entity, struct, list<TYPE>
hook_entity_property_info_alter()
// Define a new property to reference an offer's retailer (eg: Amazon.com)
$offer['retailer'] = array(
'label' => t('Retailer'),
'type' => 'tbm_retailer', // The tbm_retailer entity type
'description' => t('The retailer making the offer.'),
'required' => TRUE,
'schema field' => 'retailer_id', // as defined in hook_schema
);
Entity API Integrations
Views
– Eg: in a view of offers, we can add a retailer relationship and include details about each offer's retailer
Rules Search API Features I18n Token system - Eg: [tbm_offer:retailer:name]
EntityFieldQuery
Tool for querying entities Can query entity properties and field data Can query field data across entity types
– Eg: “return all pages and users tagged with taxonomy term 456”
Returns entity IDs
– Usually you’ll then load with entity_load()
EntityFieldQuery Example
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'node')
->entityCondition('bundle', 'page')
->propertyCondition('status', 1)
->fieldCondition('field_awesome_factor', 'value', 3.2, '<')
->fieldOrderBy('field_awesome_factor', 'value', 'DESC')
->range(0, 10);
// Top 10 Published page nodes with an awesome factor < 3.2
EntityFieldQuery Example
$result = $query->execute(); // Keyed by entity type
if (isset($result['node'])) {
$nids = array_keys($result['node']);
$pages = node_load_multiple($nids);
$same_as_pages = entity_load('node', $nids);
}
Entity Metadata Wrapper Examples
// Get node author's email address (given $nid)
// BEFORE
$node = node_load($nid);
$author = user_load($node->uid);
$email = check_plain($author->mail);
// AFTER$wrapper = entity_metadata_wrapper('node', $nid);
$email = $wrapper->author->mail->value();
Entity Metadata Wrapper Examples
// Set node author's email address
$wrapper->author->mail = '[email protected]';
$wrapper->save();
// Iterate over a list of node's taxonomy terms
foreach ($wrapper->field_taxonomy_terms->getIterator() as $term_wrapper) {
$label = $term_wrapper->label->value();
}
More Modules!
Entity Construction Kit (ECK)
– CCK for entities
– Create entity types in a UI Entity Cache
– Integrates entities with Drupal's Cache API Entity Reference
– Like node reference field, but for any type of entity Automatic Entity Label
– Generic successor to Automatic Node Titles
More information
Entity API documentation
– Lots of information in many subpages EntityFieldQuery documentation Entity API contrib module page Deck is on Slideshare Email me: jd at ModernBizConsulting.com Follow me: @drupal_jd