Drupal 7 Entities
                      {    Entities, nodes, fields, the Entity API &
                           TextbookMadness.com




{   JD Leonard
    Freelance Drupal Consultant & Developer
    Founder, TextbookMadness.com                                 { Berkeley DUG 2/27/12
Entities, Entities, Entities
             Powerful new concept in Drupal 7


    Agenda:
        How data is represented
            Drupal 6 vs. Drupal 7
            Entities
            Fields (CCK)
        Entities vs. nodes
        The Entity API (contrib module)
        Live example: entities, nodes, and fields used
         to build TextbookMadness.com
{ Drupal      6                { Drupal      7

     {Custom DB table}            {Custom DB table]
     User                         Entity
     Comment                          User
                                       Comment
     Taxonomy
                                       Taxonomy
     Node
                                       Node
         Page                             Page
         Blog post                        Blog post
         {Custom node type}               {Custom node type}
                                       {Custom entity type}

Drupal Data
Entity Types
    Elemental building block for most data in Drupal 7
    Represents a concept or noun
    In core: user, comment, taxonomy, & node
    Stores data differently
        Generally in a single DB table
        Node
             Title, body, created timestamp
        User
             Username, created timestamp, last visit timestamp
    Defined using hook_entity_info() – example later!
Entity
    Instance of an entity type
    In core:
        Users, comments, taxonomies, and nodes are entities
        Eg: the user jdl1234 with uid 12 is an entity
        Eg: the page ‚Drupal rocks‛ with nid 44 is an entity
    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 wrappers that do extra work
             Eg: node_load() and user_load()
Entity Bundles
    Bundle
        Subtype of an entity
        Eg: page & blog post
             Two content types of node entity type
             ‚Bundles‛ of node entity type
        Not all entity types have more than one
             Eg: user
                  Concept stands on its own
    Why bother?
        Each entity type stores some data in a table
             Eg: node
                  Title, body, created timestamp
                  But not all nodes are created equal
                      Page may have data beyond that captured by node
                      Blog posts get tagged
CCK, Fields, & Entities
    Drupal 6 CCK (Content Construction Kit)
         Contrib module
         Store additional data per content (node) type
         Eg: Fivestar
              Contrib module leveraging contrib CCK API
              Allows nodes to be rated (think 1-5 stars)
                   Eg: let users rate pages
    Drupal 7 fields
         Core concept
         Store additional data per entity type
         Applies power of CCK to all entity types
         Eg: Fivestar
              Contrib module leveraging core Field API
              Allows entities to be rated
                   Eg: let users rate pages, users, comments, custom entities
Entities & Nodes
    Similarities
        Represent ‚things‛; store data
        Fieldable
        Types can be defined in code
{ Nodes                        { Entities
     Site building                 Optionally fieldable
     UI to add/edit                Development
      content types, fields,        Lightweight
      and content                   No UI provided
     Versioning built in           Data storage up to
     Data stored in nodes           you
      table and fields              Can be more
                                     performant/scalable

Entities vs. Nodes
Core Entities & Entity API
    Entities are a Drupal 7 core concept
    Core functions and hooks provided to interact with
     entities and entity types
    EntityFieldQuery
        Core API for querying entities
        Can query entity data (‚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()
    The Entity API contrib module builds on core
Entity API
    Makes dealing with entities easier
    Provides full CRUD functionality
        CReate, Update, and Delete
    Allows definition of metadata about entities and
     relationships between them
        Views integration
        Rules integration
        Search API integration
    Optionally make data exportable
    Optional administrative UI for managing entities
    Object-oriented representation of entity types
        Enables extending an entity type’s functionality
Modules Using Entity API
    Profile2
    Organic Groups
    Rules
    Message
    Drupal commerce
    < and lots more!
TextbookMadness.com
    Drupal 7 site
    Cross between Craigslist and Kayak
        Free textbook classified listings
             Private to each college we partner with
             Helps students buy and sell used books with each other
        Online price comparison
             Prices from 30+ online retailers
                  Amazon, Half, Chegg, Textbooks.com, you name it
             New, used, rental, international edition, eBook, and
              buyback prices
    Uses entities and the Entity API
    Demo!
Textbook Madness Data
    Users (John Smith)
    Schools (Rice University)
    Retailers (Amazon.com
    Textbooks (with an ISBN)
    Offers (online prices)
    Listings (student book classifieds)

    Everything above except users are defined as custom
     entity types
School Entity Definition
 /* Implements hook_entity_info(). // Drupal core hook */
 function tbm_entity_info() {
   $entities = array(
     'tbm_school' => array( // Machine name for my entity
       'label' => t('School'),
       'plural label' => t('Schools'),
       'entity class' => 'TbmSchoolEntity', // Advanced. You can put ‘Entity’
       'controller class' => 'TbmSchoolEntityController', // Advanced. You can put ‘EntityAPIController’
       'base table' => 'tbm_school', // Name of the related table defined in hook_schema() in tbm.install
       'fieldable' => FALSE,
       'entity keys' => array(
         'id' => 'school_id', // Primary key as defined in hook_schema()
         'label' => 'name', // Column in hook_schema() to be used to represent the entity in a friendly way
       ),
       'uri callback' => 'entity_class_uri',
       'access callback' => 'tbm_school_access', // Callback defined to return TRUE if the school is enabled
       'module' => 'tbm', // My module name
       'admin ui' => array(
         'path' => 'admin/structure/schools',
         'file' => 'tbm.admin.inc', // Where tbm_school_form() for add/edit form is defined
         'file path' => drupal_get_path('module', 'tbm') . '/pages',
       ),
     ),
   );
   return $entities;
 }
School Schema Definition
/* Implements hook_schema(). */
function tbm_schema() {
 $schema['tbm_school'] = array(
   'fields' => array(
     'school_id' => array('type' => 'serial', 'size' => 'small', 'unsigned' => TRUE, 'not null' => TRUE),
     'machine_name' => array('type' => 'varchar', 'length' => 100, 'not null' => TRUE, 'description' => 'The machine name of the school.'),
     'name' => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'description' => 'The name of the school.'),
     'name_short' => array('type' => 'varchar', 'length' => 64, 'description' => 'The short name of the school.'),
     'name_long' => array('type' => 'varchar', 'length' => 255, 'description' => 'The long name of the school.'),
     'url' => array('type' => 'varchar', 'length' => 1024, 'not null' => TRUE, 'description' => 'The URL of the school's homepage.'),
     'email_domains' => array('type' => 'varchar', 'length' => 1024, 'description' => 'The email domains (comma delimited) valid for the school.'),
     'sponsor1_name' => array('type' => 'varchar', 'length' => 64, 'description' => 'The name of the first sponsor.'),
     'sponsor1_name_short' => array('type' => 'varchar', 'length' => 32, 'description' => 'The short name of the first sponsor.'),
     'sponsor1_name_long' => array('type' => 'varchar', 'length' => 128, 'description' => 'The long name of the first sponsor.'),
     'sponsor1_url' => array('type' => 'varchar', 'length' => 1024, 'description' => 'The URL of the first sponsor's homepage.'),
     'sponsor2_name' => array('type' => 'varchar', 'length' => 64, 'description' => 'The name of the second sponsor.'),
     'sponsor2_name_short' => array('type' => 'varchar', 'length' => 32, 'description' => 'The short name of the second sponsor.'),
     'sponsor2_name_long' => array('type' => 'varchar', 'length' => 128, 'description' => 'The long name of the second sponsor.'),
     'sponsor2_url' => array('type' => 'varchar', 'length' => 1024, 'description' => 'The URL of the second sponsor's homepage.'),
     'enabled' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'Whether the school is enabled.'),
     'listed' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'Whether the school is listed.'),
   ),
   'primary key' => array('school_id'),
   'unique keys' => array(
     'machine_name' => array('machine_name'),
   ),
 );
 return $schema;
School EntityFieldQuery
      This function shows how to use an EntityFieldQuery
      Users are necessarily associated with a school
      I have a field, field_school, attached to the user entity type, which
       stores this relationship data
      The query finds active users (status == 1) at the given school


 /**
  * Load an array of uids of users at the school with the given ID.
  * @param int $school_id The ID of the school to load users for
  */
 function tbm_school_uids($school_id) {
   $query = new EntityFieldQuery();

     $result = $query
      ->entityCondition('entity_type', 'user')
      ->propertyCondition('status', 1)
      ->fieldCondition('field_school', 'school_id', $school_id)
      ->execute();

     return array_key_exists('user', $result) ? array_keys($result['user']) : array();
 }
The end!

Drupal 7 entities & TextbookMadness.com

  • 1.
    Drupal 7 Entities { Entities, nodes, fields, the Entity API & TextbookMadness.com { JD Leonard Freelance Drupal Consultant & Developer Founder, TextbookMadness.com { Berkeley DUG 2/27/12
  • 2.
    Entities, Entities, Entities Powerful new concept in Drupal 7  Agenda:  How data is represented  Drupal 6 vs. Drupal 7  Entities  Fields (CCK)  Entities vs. nodes  The Entity API (contrib module)  Live example: entities, nodes, and fields used to build TextbookMadness.com
  • 3.
    { Drupal 6 { Drupal 7  {Custom DB table}  {Custom DB table]  User  Entity  Comment  User  Comment  Taxonomy  Taxonomy  Node  Node  Page  Page  Blog post  Blog post  {Custom node type}  {Custom node type}  {Custom entity type} Drupal Data
  • 4.
    Entity Types  Elemental building block for most data in Drupal 7  Represents a concept or noun  In core: user, comment, taxonomy, & node  Stores data differently  Generally in a single DB table  Node  Title, body, created timestamp  User  Username, created timestamp, last visit timestamp  Defined using hook_entity_info() – example later!
  • 5.
    Entity  Instance of an entity type  In core:  Users, comments, taxonomies, and nodes are entities  Eg: the user jdl1234 with uid 12 is an entity  Eg: the page ‚Drupal rocks‛ with nid 44 is an entity  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 wrappers that do extra work  Eg: node_load() and user_load()
  • 6.
    Entity Bundles  Bundle  Subtype of an entity  Eg: page & blog post  Two content types of node entity type  ‚Bundles‛ of node entity type  Not all entity types have more than one  Eg: user  Concept stands on its own  Why bother?  Each entity type stores some data in a table  Eg: node  Title, body, created timestamp  But not all nodes are created equal  Page may have data beyond that captured by node  Blog posts get tagged
  • 7.
    CCK, Fields, &Entities  Drupal 6 CCK (Content Construction Kit)  Contrib module  Store additional data per content (node) type  Eg: Fivestar  Contrib module leveraging contrib CCK API  Allows nodes to be rated (think 1-5 stars)  Eg: let users rate pages  Drupal 7 fields  Core concept  Store additional data per entity type  Applies power of CCK to all entity types  Eg: Fivestar  Contrib module leveraging core Field API  Allows entities to be rated  Eg: let users rate pages, users, comments, custom entities
  • 8.
    Entities & Nodes  Similarities  Represent ‚things‛; store data  Fieldable  Types can be defined in code
  • 9.
    { Nodes { Entities  Site building  Optionally fieldable  UI to add/edit  Development content types, fields,  Lightweight and content  No UI provided  Versioning built in  Data storage up to  Data stored in nodes you table and fields  Can be more performant/scalable Entities vs. Nodes
  • 10.
    Core Entities &Entity API  Entities are a Drupal 7 core concept  Core functions and hooks provided to interact with entities and entity types  EntityFieldQuery  Core API for querying entities  Can query entity data (‚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()  The Entity API contrib module builds on core
  • 11.
    Entity API  Makes dealing with entities easier  Provides full CRUD functionality  CReate, Update, and Delete  Allows definition of metadata about entities and relationships between them  Views integration  Rules integration  Search API integration  Optionally make data exportable  Optional administrative UI for managing entities  Object-oriented representation of entity types  Enables extending an entity type’s functionality
  • 12.
    Modules Using EntityAPI  Profile2  Organic Groups  Rules  Message  Drupal commerce  < and lots more!
  • 13.
    TextbookMadness.com  Drupal 7 site  Cross between Craigslist and Kayak  Free textbook classified listings  Private to each college we partner with  Helps students buy and sell used books with each other  Online price comparison  Prices from 30+ online retailers  Amazon, Half, Chegg, Textbooks.com, you name it  New, used, rental, international edition, eBook, and buyback prices  Uses entities and the Entity API  Demo!
  • 14.
    Textbook Madness Data  Users (John Smith)  Schools (Rice University)  Retailers (Amazon.com  Textbooks (with an ISBN)  Offers (online prices)  Listings (student book classifieds)  Everything above except users are defined as custom entity types
  • 15.
    School Entity Definition /* Implements hook_entity_info(). // Drupal core hook */ function tbm_entity_info() { $entities = array( 'tbm_school' => array( // Machine name for my entity 'label' => t('School'), 'plural label' => t('Schools'), 'entity class' => 'TbmSchoolEntity', // Advanced. You can put ‘Entity’ 'controller class' => 'TbmSchoolEntityController', // Advanced. You can put ‘EntityAPIController’ 'base table' => 'tbm_school', // Name of the related table defined in hook_schema() in tbm.install 'fieldable' => FALSE, 'entity keys' => array( 'id' => 'school_id', // Primary key as defined in hook_schema() 'label' => 'name', // Column in hook_schema() to be used to represent the entity in a friendly way ), 'uri callback' => 'entity_class_uri', 'access callback' => 'tbm_school_access', // Callback defined to return TRUE if the school is enabled 'module' => 'tbm', // My module name 'admin ui' => array( 'path' => 'admin/structure/schools', 'file' => 'tbm.admin.inc', // Where tbm_school_form() for add/edit form is defined 'file path' => drupal_get_path('module', 'tbm') . '/pages', ), ), ); return $entities; }
  • 16.
    School Schema Definition /*Implements hook_schema(). */ function tbm_schema() { $schema['tbm_school'] = array( 'fields' => array( 'school_id' => array('type' => 'serial', 'size' => 'small', 'unsigned' => TRUE, 'not null' => TRUE), 'machine_name' => array('type' => 'varchar', 'length' => 100, 'not null' => TRUE, 'description' => 'The machine name of the school.'), 'name' => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'description' => 'The name of the school.'), 'name_short' => array('type' => 'varchar', 'length' => 64, 'description' => 'The short name of the school.'), 'name_long' => array('type' => 'varchar', 'length' => 255, 'description' => 'The long name of the school.'), 'url' => array('type' => 'varchar', 'length' => 1024, 'not null' => TRUE, 'description' => 'The URL of the school's homepage.'), 'email_domains' => array('type' => 'varchar', 'length' => 1024, 'description' => 'The email domains (comma delimited) valid for the school.'), 'sponsor1_name' => array('type' => 'varchar', 'length' => 64, 'description' => 'The name of the first sponsor.'), 'sponsor1_name_short' => array('type' => 'varchar', 'length' => 32, 'description' => 'The short name of the first sponsor.'), 'sponsor1_name_long' => array('type' => 'varchar', 'length' => 128, 'description' => 'The long name of the first sponsor.'), 'sponsor1_url' => array('type' => 'varchar', 'length' => 1024, 'description' => 'The URL of the first sponsor's homepage.'), 'sponsor2_name' => array('type' => 'varchar', 'length' => 64, 'description' => 'The name of the second sponsor.'), 'sponsor2_name_short' => array('type' => 'varchar', 'length' => 32, 'description' => 'The short name of the second sponsor.'), 'sponsor2_name_long' => array('type' => 'varchar', 'length' => 128, 'description' => 'The long name of the second sponsor.'), 'sponsor2_url' => array('type' => 'varchar', 'length' => 1024, 'description' => 'The URL of the second sponsor's homepage.'), 'enabled' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'Whether the school is enabled.'), 'listed' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'Whether the school is listed.'), ), 'primary key' => array('school_id'), 'unique keys' => array( 'machine_name' => array('machine_name'), ), ); return $schema;
  • 17.
    School EntityFieldQuery  This function shows how to use an EntityFieldQuery  Users are necessarily associated with a school  I have a field, field_school, attached to the user entity type, which stores this relationship data  The query finds active users (status == 1) at the given school /** * Load an array of uids of users at the school with the given ID. * @param int $school_id The ID of the school to load users for */ function tbm_school_uids($school_id) { $query = new EntityFieldQuery(); $result = $query ->entityCondition('entity_type', 'user') ->propertyCondition('status', 1) ->fieldCondition('field_school', 'school_id', $school_id) ->execute(); return array_key_exists('user', $result) ? array_keys($result['user']) : array(); }
  • 18.