There's a reason views is the most popular module on drupal.org and it's pointy-clickly user interface is only a part of that. In this series we cover the ins and outs of writing modules that implement the Views API. Once you’ve realized the power of creating complex lists of nodes, users and other content via the views UI the next logical desire is to allow people to do that with the content provided by your custom module as well. This series will take an in-depth look at exposing your own database tables to the Views module so that users can use them as a place to pull content from including the fields themselves and meta-data about how they can be used to create relationships to other content on your site.
After getting the basics out of the way we’ll also take a look at writing our own custom field handlers to expose our module’s data to views so that it can be sorted, filtered, and queried in new ways. We’ll also look at implementing views plugins to do things like add custom access control options to views and to add new output styles.
Once you understand a bit more about how views works under the hood and how easy it is to tie in to that system you’ll be reimaging your solutions for all sorts of different problems.
In this video Joe describes the process of adding the rest of the fields from the databasics module to our implementation of hook_views_data() including how to differentiate between different data types like strings of text and numeric values and how this changes the views module's behavior. Then Joe talks about how to tell views about various tables that can be used in relationship to the databasics table via foreign keys like the node ID.
Additional resources
Modules Needed
In this lesson Joe will explain what an entity is and provide a little bit of history about how they came into being. We’ll also learn about some of the differences between custom entities and nodes (which happen to be a type of entity) and when, and why you might want to choose to write your own custom entities instead of using the node system or a more traditional datastore.
Entities were introduced in Drupal 7 as a way of taking the things that people loved about nodes + CCK in Drupal 6 and applying them to other types of data like users, comments, and taxonomy terms. The Entity API in Drupal 7 provides a set of common functions and classes to make it easier for developers to create their own custom entity types or to work with existing ones in a generic way. The API in Drupal core however is still missing some really useful tools and is supplemented by the Entity module in Drupal contributed which we'll make heavy use of throughout the series.
In this series we'll learn about the interplay between Entities, Entity Types, Bundles, and Fields and how to write custom code to deal with each of these things. The Entity API demo site files that we use in this series are all located in the Lullabot GitHub, as well as in zip files attached to the respective video pages, under the Downloads tab.
This series covers:
- What entities are and how they fit into the Drupal ecosphere
- EntityFieldQuery
- Entity classes, what they do and how to override them
- Providing an admin UI for adding/editing and deleting entities from Drupal
- Making entities fieldable
- View modes
- Creating custom UI's for dealing with entities
- Describing entity properties to Drupal
- Views integration for entities
- Entity Metadata wrappers
- Making entities revisionable
And much much more. This series assumes that you're already familiar with the basic tenets of writing modules for Drupal and makes use of things like hook_menu() without spending time explaining them. If you're not familiar with Drupal module development, you might want to brush up by watching our Module Development for Drupal 7 first.
Additional resources
Entity API Demo site files on GitHub
Entity module at Drupal.org
This lesson will explore the use of EntityFieldQuery to retrieve lists of entities from Drupal without directly querying the database which can be problematic in a system where the underlying schema can change depending on configuration settings in the user interface. Again focusing on writing code that will work with any entity in Drupal and isn't hard coded to your particular setup.
Additional resources
In the next set of lessons we're going to be writing to the code to create our own custom entity type. The goal is to create a video entity that stores embed codes for YouTube videos and allows us to display the videos on our site. In this scenario we don't want all the overhead that comes with using the node system, like comments for example, so instead we're going to write our own custom entity for storing the data. We're going to take a look at the completed entity type that we're attempting to build and just walk through all the various components. We'll take a look at creating/updating, and deleting a video via the UI, and also the views integration and fieldability of our custom video entities.
This lesson introduces students to Entity classes and illustrates what each of the main Entity classes does, followed by a more in depth look at the CRUD operations provided by the base entity class, and finally demonstrates overriding the default Entity class with our own custom Entity object to define a defaultUrl() for our entities and a new implementation of hook_menu where we can view an entity.
Note: At the end of the this video code is added to hook_entity_info() that references a VideoEntityUIController
class, however, the definition of that class is in our sample code, but was not shown being added here. And it is necessary to follow along with the videos. If you're following along you'll want to add the following code to the bottom of your videoasset.module file. If you're curious about what it does it's explained in the last part of this video.
/**
* Our custom controller for the admin ui.
*/
class VideoEntityUIController extends EntityDefaultUIController {}
Additional resources
Update your hook_entity_info implementation to take advantage of the Admin UI provided by the Entity API and quickly provide users of your site access to all the Entity CRUD operations via the UI. The API gives us a really good head start but we still need to write some code in order to provide a useable form for administrators. The API doesn’t make any assumptions about things like validating input so we also need to take care of that ourselves.
This video adds a new permission that allows privileged users administer our new videoasset entities. If you're following along as a user other than user 1 you'll need to make sure you give yourself the proper permissions. In the video, I'm logged in as the user with the ID of 1 so I'm just granted the permissions automatically.
Note: If you're following along with the videos in sequence there's an error that needs correcting. At the end of the previous video code was added to videoentity_entity_info()
that references a VideoEntityUIController
class, however, the definition of that class was not added. Which, will cause a PHP error because the class is missing.
In order to correct this error, you'll want to add the following code to the bottom of your videoentity.module file. This just ensures that the class is defined so that there are no errors. If you're curious about what it does it's explained in the last part of the previous video.
/**
* Our custom controller for the admin ui.
*/
class VideoEntityUIController extends EntityDefaultUIController {}
In a later tutorial in this series, we'll customize the form for our video entity by adding more code to this class.
Note: At 14:10 on line 36 this line is added:
'#value' => isset($VideoAsset->id) ? t('Update video asset') : t('Save video
asset'),
It should be:
'#value' => isset($video->id) ? t('Update video asset') : t('Save video
asset'),
So far we’ve seen that you can use entity_load and entity_view to display your entity. But what if you want more control over how your content gets rendered? In this lesson we’ll take a look at overriding the buildContent() method of our entity controller to spruce up the output a bit. We'll also overrid the save() method of the controller in order to populate the created_at and updated_at fields automatically when saving a video entity.
Note: In order to improve upon the security of the code in this lesson you'll want to make sure you're escaping all user input properly. The following code:
$build['embedcode'] = array(
'#type' => 'markup',
'#markup' => '<iframe width="560" height="315" src="http://www.youtube.com/embed/'. $entity->embedcode . '" frameborder="0" allowfullscreen></iframe>',
);
Should be updated to use the check_url() function when outputting $entity->embedcode
to ensure that user entered content is safe for use in the context of a URL.
$build['embedcode'] = array(
'#type' => 'markup',
'#markup' => '<iframe width="560" height="315" src="http://www.youtube.com/embed/'. check_url($entity->embedcode) . '" frameborder="0" allowfullscreen></iframe>',
);
Bundles are an implementation of an entity type to which fields can be attached. In this lesson we’ll take a look at configuring a single bundle type for our entities in order to allow us to make them fieldable by hardcoding the bundle information into hook_entity_info(). This is the most basic implementation of bundles. Then we’ll look at adding the ability to attach fields to our newly created bundle.
This chapter walks through the process of adding links to the contextual drop-down widgets new in Drupal 7. It also shows how using menu autoloaders can help simplify the code that you write in your page callback function since you won't have to do extra checking on the data.
As a note, if you are wondering why we started our function with an underscore (_), naming functions with an underscore in front of the name is a common convention in Drupal that sort of implies that "this function is for internal use by this module only" and shouldn't be called by itself. It's also a nice way to ensure that your internal functions are not colliding with the namespace of a hook or another module. Here's a good blog post about naming things.
This video walks through how to use the new hook_page_alter()
in Drupal 7 by transforming an unordered list into an ordered list. Because all of the content, region & blocks are stored within a renderable array before being output to the page, then this new hook allows modules and themes to make changes to page before it is fully rendered.
This video walks through the basic use of Drupal 7's Render API for outputting content, and gives some hands-on experience in navigating and working with renderable arrays. We expand the Menu Magic module by creating several different kinds of page elements to show how renderable arrays work.
This chapter goes through the process of passing a wildcard variable to a function via an argument from the URL. It creates a MENU_LOCAL_TASK tab on the node which inverts the text to display upside down. It uses a page callback function that is included within a separate file in order to save on how much memory is used.
In this video you'll learn how to use api.drupal.org the canonical source for information about Drupal's hooks, APIs, and code documentation in order to find out information about implementing a particular hook, making use of a particular function or library of functions, and even gaining a better understanding of some of the big picture concepts behind Drupal's code and APIs.
Walks through some of the basics elements that are required and common for all Drupal modules. Then we create a simple demo module to see how it works.
This chapter describes how Drupal modules are able respond to specific events through the hook system. A couple of example hooks are implemented in order to see how this process works. This video builds on the demo module we created in the previous chapter.
In this video Joe Shindelar provides a quick overview of the minimum set of tools you'll need in order to get started with module development. Some kind of web server to host your development site on, an editor that allows you to edit PHP files (preferably one with syntax highlighting), a MySQL client, and Drush. Learn about how these essential tools fit in the module developers tool belt and then download and install a bare bones copy of Drupal to start tinkering with.
Provides a overview presentation for how Drupal's menu system takes care of incoming requests via the index.php. Then it walks through the process of implementing a simple module that hooks into Drupal's menu system at the path of /magic.
It then executes a page callback function of menu_magic_basic(),
which outputs some simple markup text.
Additional resources
This screencast gives miscellaneous tips when writing Rules plugins, such as:
- Some words on declaring new data types for Rules
- How to restrict access to plugins
- How to form alter plugin configuration forms
- How to provide additional form validation
- How to use the "base" property to provide a non-default callback function
- How to invoke events programmatically with all arguments in a single array
- How to use drupal_static() to share variables/values with other parts of Drupal