Build Your Own Custom Entities in Drupal – Setup

Daniel Sipos
This entry is part 1 of 2 in the series Build Your Own Custom Entities in Drupal

Build Your Own Custom Entities in Drupal

Entities are a great way to organize your data in Drupal. If you are familiar with nodes, taxonomy terms, comments or users, you should also know that since Drupal 7, these have been entities. Another important aspect about them is that they are fieldable via the Field API.

In this tutorial I will show you how you can define your own custom entity type and get started working with it. Why would one want to do this instead of using nodes? Because although they are great, nodes can sometimes be overkill. There is a lot of functionality you may not need such as revisions or commenting.

For the purpose of this tutorial, we will define our own custom entity type called project to represent simple information we have about our projects (title, description and deadline). Then we will look at a few things about working with the entities of this type.

For following along, I assume you know how to write a basic custom module (mine will be named demo). You can find a great tutorial on this subject here. Go ahead and write the .info file and create the empty .module and .install files. I also set up a Git repository where you can get all the source code for this tutorial (one branch per part, two parts will be published).

Additionally, you need the Entity API contrib module enabled on your site and set as a dependency to your custom module. The Entity API module is very powerful when working with entities as it provides a lot of functionality that the Drupal core lacks.

Defining our own Drupal entity type

The first thing we need to do to create a new entity type is to declare its schema definition. That is, write the code that will generate the database table for the entity data. In my demo.install file I have the following code:

/**
 * Implements hook_schema().
 */
function demo_schema() {

  $schema = array();

  $schema['demo_projects'] = array(
    'description' => 'The base table for the Project entity',
    'fields' => array(
      'id' => array(
        'description' => 'Primary key of the Project entity',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'name' => array(
        'description' => 'Project name.',
        'type' => 'varchar',
        'length' => 255,
        'not null' => FALSE,
      ),
      'description' => array(
        'description' => 'Project description.',
        'type' => 'text',
        'size' => 'big',
        'not null' => FALSE,
        'default' => NULL
      ),
      'deadline' => array(
        'description' => 'Project deadline.',
        'type' => 'int',
        'length' => 11,
        'not null' => FALSE,
      ),
    ),
    'primary key' => array('id'),
  );

  return $schema;
}

This is a simple implementation of hook_schema() through which we create a demo_projects table that has 4 columns: id, name, description and deadline, the first representing the primary key. Nothing big.

The next thing we need to do is implement hook_entity_info(). There are a lot of options we can specify in this hook, but here are the most basic and required ones (this goes in the demo.module file):

/**
 * Implements hook_entity_info().
 */
function demo_entity_info() {

  $info = array();

  $info['project'] = array(
    'label' => t('Project'),
    'base table' => 'demo_projects',
    'entity keys' => array(
      'id' => 'id',
      'label' => 'name',
    ),
    'module' => 'demo',
  );

  return $info;
}

With this hook we return a new key in the $info array that represents the entity machine name. Inside this array we specify the options (we will add more in the course of this tutorial). For now, we will stick to label (human readable name of the entity type), base table that stores the entity data, entity keys which are the properties that act as identifiers for the entities and module that specifies which module defines the entity type. The last one is not mandatory but recommended.

And with this we have registered our own basic entity type with Drupal. To test out if it works, enable the module for the first time and check if the table was created in the database. Then populate it with a few rows to have something to work with:

INSERT INTO `demo_projects` (`id`, `name`, `description`, `deadline`)
VALUES
    (1, 'Summer House', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', 1397501105),
    (2, 'Winter House', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', 1397501132);

Finally, register a path with Drupal (any path for testing only) using hook_menu() and paste the following in its callback function:

$projects = entity_load('project', array(1, 2));
dpm($projects);
return 'Some string';

First, we use the entity_load() function to load the project entities with the IDs of 1 and 2 and then we print them to the screen using the Devel dpm() function (so make sure Devel is enabled on your site for testing). And don’t forget that the callback function for the page needs to return something otherwise it won’t build.

Now if you navigate to that page you’ll see in Krumo the data from the 2 entities in the database.

Alternatively, you can use the EntityFieldQuery class to query for the new entities by any property you want (not just the id). For more information about how this works you can check out this Sitepoint tutorial that will get you started.

Entity class and controller

Unfortunately, Drupal core does not come with too many helper functions to work with entities (entity_load() is pretty much the only one). However, the Entity API module fills this gap.

In order to make use of its functionality, we need to alter the entity info we declared earlier and specify the PHP classes that can be used to work with the entities. For now, we’ll add 2 more keys to the array keyed project inside our hook_entity_info() declaration:

...

'entity class' => 'Entity',
'controller class' => 'EntityAPIController',

...

The first one is the base class provided by Entity API that will offer some wrapping functionality for the entities. This class is declared in the entity.inc file of the module and if you look inside, you’ll notice that many of its methods call the methods of another (controller) class. This is the class we specified for the controller class key.

The EntityAPIController class (found in entity.controller.inc file of the module) offers some sensible defaults for working with the entities. It extends the default Drupal core DrupalDefaultEntityController class and it is responsible – among many other things – for performing CRUD operations.

Both of these classes can be extended in your custom module to adjust functionality (like querying, loading or displaying the entities). We will see how to do this in a minute.

But first, I want to show you how to save a new entity. Currently, in my database I have 2 records with the ids 1 and 2. I want to adjust the code we wrote in the test page callback above to create a new entity with the id of 3 if one doesn’t already exist. It can look something like this:

 $projects = entity_load('project', array(1, 2, 3));

 if (!isset($projects[3])) {
   $entity = entity_create('project', array('id' => 3));
   $entity->name = t('Spring House');
   $entity->description = t('Some more lipsum.');
   $entity->save();
 }

 dpm($projects);

 return 'Some string';

As you can see, now we try to load 3 project entities and check for the existence of the third. If it doesn’t exist, we use the entity_create() helper function provided by Entity API, set the properties to some random values and then use the save() method on the entity to persist it to the database. This method is provided by the Entity class and its job is to call the save() method on the controller class we defined above. And that method will perform the logic necessary to persist the entity. But all this happens behind the scenes and we don’t have to worry about it.

If you reload that page, you should see only 2 returned project entities, but if loaded a second time, there should be 3.

Overriding the entity classes

The last thing I want to show you in this part of the tutorial is how to display your entities. For this, we will stick to the page callback function we’ve been working with and have it render a list of our entities.

The first thing we need to do is override the buildContent() method of the default EntityAPIController class. The reason is that the controller cannot make assumptions about our data so we need to provide some information about how to display it. First, let’s declare our controller class that extends the previous one:

/**
 * Extending the EntityAPIController for the Project entity.
 */
class ProjectEntityController extends EntityAPIController {

}

I chose the class name ProjectEntityController and you need to make sure that you replace with this name the value you set for the controller class key in the hook_entity_info() implementation. Don’t forget.

Inside of this class, we can copy the method name from the original one and have it return the same its parent would:

public function buildContent($entity, $view_mode = 'full', $langcode = NULL, $content = array()) {

$build = parent::buildContent($entity, $view_mode, $langcode, $content);

// Our additions to the $build render array

return $build;

}

As such, there are no new changes. But now we can add our own data to the returned value of this method which is nothing more than a Drupal render array. So for example we can write this right before we return the $build array:

$build['description'] = array(
  '#type' => 'markup',
  '#markup' => check_plain($entity->description),
  '#prefix' => '<div class="project-description">',
  '#suffix' => '</div>',
);
$build['deadline'] = array(
  '#type' => 'markup',
  '#markup' => date('d F, Y', check_plain($entity->deadline)),
  '#prefix' => '<p>Deadline: ',
  '#suffix' => '</p>',
);

We are basically adding two new items to the array. The first one will wrap the description with a <div class="project-description"> and the second will output a formatted date in between paragraph tags. This is basic Drupal theming so brush up on that if you don’t understand what’s going on here. But you will notice that the project name is missing. That will be rendered automatically by Drupal because we specified it as the label in the entity keys of the hook_entity_info() implementation.

The final step is to go to our page callback function and make it display our entities. A quick way of doing that (just for demonstration purposes):

$projects = entity_load('project', array(1, 2, 3));

$list = entity_view('project', $projects);

$output = array();

foreach ($list['project'] as $project) {
  $output[] = drupal_render($project);
}

return implode($output);

As before, we first load our entities with the respective ids. Then, we run them through the entity_view() helper function that will end up calling the buildContent() method we just overrode. This function returns a list of render arrays for each entity. We render each one and store the result in the $output array that we then implode and return.

You can refresh the page and you should see a listing of all the entities you loaded. Make sure you clear the caches so that the changes become visible.

Conclusion

In this tutorial we began learning about entities in Drupal by defining our own entity type in code. We’ve seen how to write a schema definition for the data they represent and how to register them with Drupal. Then we saw the power of using the Entity API contrib module for an object oriented way of working with the entities.

In the second part of this tutorial we will look at three main aspects. First, we’ll create some pages to display the individual project entities and spin up an admin interface for managing the projects. Second, we’ll make them fieldable through the UI. And third, we’ll expose them to Views so we can do some proper queries and listings. Stay tuned!

Build Your Own Custom Entities in Drupal

Build Your Own Custom Entities in Drupal – Implementation >>

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.