This chapter shows how to cluster different form elements into fieldsets as well as how to expand the Forms API renderable array a tree that preserves the structure and hierarchy of the form. We'll expand the Form Fun example module and talk about the #tree property. This video uses krumo() and dsm() functions. You will need to download, install, and enable the devel module to use these functions. These functions allow you to see what variables are available to you. To accomplish the same task without using the devel module, you can add the following snippet to your module: drupal_set_message('' . print_r($vars, true) .'');
Note: There is a typo in the code used in this video. The function form_fun_tree()
is missing a parameter, and should be as follows function form_fun_tree($form, &$form_state)
.
This lesson demonstrates the bare minimum needed to create a custom entity type and to load an Entity from the database. We’ll look at implementing a minimum viable hook_entity_info, talk about the relationship between the Entity API and the Schema API and use entity_load to retrieve a single entity record from the database.
Note, although it would be considered best practices to name the entity with the name of the module, e.g. videoentity_video, we did not include the module name prefix here because it is tedious to type it all out and to say "videoentity_video" without confusing people.
In the next lesson we'll cover the various entity classes and how they work. However, if you just want to get straight to using your entity and doing things like $entity = entity_load();
you'll need to declare a controller for your new entity type. Simply add this 'controller class' => 'EntityAPIController'
in hook_entity_info()
. That will get you started, and well talk about what exactly that line does in the next lesson.
Note: the video doesn't mention the 'primary key'
element in the schema array (although it is in the code). This bit is necessary for the schema to install properly and work with the Entity API so if you're following a long make sure you add that part as well.
Additional resources
This video goes through the process of creating a configuration form in order to save settings to the variables table in the database, and how to integrate those variables into your module.
Correction
The $item
array in the function demo_menu()
should be named $items
, to match the return $items;
line. (Either that or return $items;
should be fixed to return $item;
.) Just make sure the array you are building matches the name of the variable you are returning.
Additional resources
This video walks through the handy devel module from http://drupal.org/project/devel and demonstrates the tools it provides for debugging, inspecting and analyzing the code and SQL queries happening on your site. In this video you'll also learn about some of the helper functions built into the devel module that make it simpler to inspect the large nested arrays that you'll commonly come across when writing code for Drupal.
You may not have heard of the function dsm() before now. It is a legacy function and dpm() is the newer name. The two functions are identical since dsm() is just a wrapper for dpm().
The idea is that dsm() was a poor name for the function, it's short for drupal set message, but what was later decided that drupal print (as in print_r) message was better.
The difference between those two and kpr() is that dpm() does a permissions check to make sure the current user has permission to view devel's output, and then puts the krumo'd variable dump into the message queue via drupal_set_message(). This means that dpm() will work and let you see the output even if you're redirected. Great for debugging forms. kpr() just krumo's and dumps the value right here, right now. No permission check, no regard for where the content is being spit out.
This videos goes through the process of creating a form with Drupal Forms API that is single select list that has a validation, submission and redirect functionality.
NOTE:
Their is a typo in the code displayed in the video. The function
function form_fun_cake(&$form_state)
is missing the $form paramater and should instead be
function form_fun_cake($form, &$form_state)
Curious about when you're supposed to translate "title" and when you should leave it alone? Here's the answer: You don't need to translate the 'title' attribute of an array that defines a menu item because Drupal will take care of that automatically. In fact, you shouldn't translate those as they'll end up getting double translated if you do. This is because Drupal end's up using this string of text in a number of different ways some of which don't actually need to be translated and others that do like for example when it's the title of a page or the text of a link in the menu system. The #title (and #description) property for elements in Form API array however are your responsibility to translate.
Probably the most common use case for view modes is teaser nodes. Or, a node being rendered in the teaser view mode. View modes allow entities to be displayed different depending on context, and also allow other modules like Field API that participate in the entity rendering process to adjust their behavior depending on the requested view mode.
In this lesson we’re going to take a look at an ‘authenticated’ view mode that we can use to adjust the display for any authenticated users. Then we’ll update Entity Controller class and make use of this new view mode in our ::view() method.
NOTE: in the video Joe forgot to change the 'member' label to "Member" and then later in the video when we view it in the UI it is corrected. The sample code included with this video has the correct label.
In this lesson we're going to take a more in-depth look at the UI controller we used earlier to create our administrative UI for the entity. We'll walk through how the controller adds menu paths and the like, without us needing to do any extra work, and then clean up our form-builder functions by overriding the UI controller's method, so that we can gain control of the name of the function that's called.
This lesson takes a look at exposing the data in our entities to views. Lucky for us the entity API handles a lot of this for us. We’ll take a look at what we get for free, using the EntityDefaultViewsController class provided by Entity API module. We'll also discuss ways that we can customize this controller, which we'll tackle in a later lesson.
"There's a module for that."
You've probably heard this before. Many times you can find a module that provides the functionality you need — or at least pretty close to what you need. Drupal's contributed module projects number in the thousands, but what if there isn't a module for your use case? You just might need to build a module for that.
In this series, you will learn about the tools and resources available to Drupal developers, including where to find documentation and what APIs are available to you, both on drupal.org and api.drupal.org. We'll take a look at the Devel module and learn how to use it to inspect the variables, objects, arrays and other things at work under the hood of Drupal 7.
You'll build several different modules that explore and interact with Drupal's various systems and API, including:
- Form API
- Menu system
- Hooks
- Render API
- Theme system
- Database API
Over the course of this series you'll be able to:
- Describe the anatomy of a module
- Implement common hooks
- Write more secure code
- Interact with Drupal's menu system
- Create and alter forms
- Peform CRUD operations on a database
This series starts with the basics and moves you step-by-step to more advanced concepts. Even if you are quite comfortable with PHP but are struggling to understand how to appropriately interact with Drupal 7's API, the lessons in this series can help you develop "The Drupal Way."
Additional resources
In order to make the most of the entity APIs integration with other modules, such as Views, we need to describe the properties of our entity in more detail. The API can infer some information about a property based on our schema but we need to tell it that the integer stored in the updated_at column is actually a timestamp. We will do this by implementing hook_entity_property_info()
and describing each of our entities properties. With these definitions in place you will be able to use the formatters in Views much like you would for individual fields on content types provided by core.
Note: Before you implement hook_entity_property_info()
the API makes an educated guess about each property but once you've defined a single property, the API expects you to define all of the properties for your entity. Use the .install
file in your module to get a complete list of the properties you need to define with hook_property_entity_info
. You can also define additional properties that aren't mapped to fields in the database (these can be used for static properties).
Additional resources
If you've done any module development, you're probably familiar with hook_node_view and Drupal's arrays of doom. In this lesson we'll show you how to get easier access to the same information using entity metadata wrappers. We will use the entity_metadata_wrapper function to retrieve a new EntityMetaDataWrapper
object that provides an interface for easily accessing an entities property and field values. We'll use the getPropertyInfo
method to expose information about individual properties, and the getIterator
method to access fields that contain multiple values, such as tags. You'll see that by using meta data wrappers you can also access properties on referenced entities, such as the email address of the author of a node, without having to load that information independently.
Metadata wrappers also provide a consistent way to access properties common to all entities. For example, every entity in Drupal has a unique ID property or a human readable label, but these properties often have different names. User name vs. node title. Metadata wrappers allow you to access this information in a consistent way.
Additional resources
Revisions are an important concept in a content management system. Keeping track of all the edits that have been made to a particular entity over the course of its lifetime. A paper trail or sorts. This lesson takes a look at what is required in order to make our Entities support revisions.
If you've worked with Drupal's node system and enabled revisions then you've seen Drupal's basic revision handling in action. Every time you save a node, it creates a new version of that node. You can roll back to previous versions and keep track of how a piece of content has changed over time. Entity API also supports the concept of revisions and in this lesson we're going to take a look at adding revision support for our video entities.
In order to take advantage of this feature, we'll need to modify our database schema to accommodate storing multiple versions of the same entity. We'll move all fields that we want to make "revisionable" into a separate table and set up a new unique version ID field so that we can keep track of revisions.
Then we will update our hook_entity_info
implementation to tell the API that we want to use the revision system and make some changes to the code in our VideoEntityController
so that when an entity is updated we save a revision instead of overwriting the current data.
Finally we'll need to write a simple UI for viewing older versions of our video entity because the Entity API does not provide us with this code by default.
This chapter walks through how you can conditionally add either JavaScript or CSS to a content element as well as how to cache the content with Drupal's caching system. Additional notes: The cache will clear the first time cron.php is run AFTER whatever time you've specified as the cache expiration date in your code. Which you could easily calculate to be 30 seconds in the future and then store that timestamp in the database. However, you would also need to make sure that cron was running frequently enough to clear the cache every 30 seconds.
Additional resources
Render Arrays overview (Drupal.org)
In this video we'll look at adding yet another field handler, but in this instance we will be adding a Views field that does not directly map to an actual field in the database. Instead we will be creating our own variation on some data and adding it as a field that can be used in our views — a field that shows the percentage of page views as a black bar graph.
One of the most common things to do with Views is export a view from your site and store it in code as a default View. This is what Features module does when you create a feature with a view in it. In this lesson we'll export our sample site's view and add it to our module with hook_views_default_views().
In this video Joe will walk through writing a custom field handler for views. Demonstrating how to extend the set of handlers that come with the views module in order to provide new functionality or for dealing with new types of data. In this case we'll look at how to treat the numerical values in the databasics module as percentages in views. The method used to write a field handler in this video is similar to overriding other handlers like filters and sorts that will be discussed in coming chapters and provides some important foundations for understanding how to work with all views handlers.
Additional resources
In this video Joe looks at using hook_views_data()
in order to describe a database table to views such that views is capable of making queries to that table. We’ll talk about describing the table itself, and how to get it to appear in the views UI as an option that can be used as a base table.
Additional resources
Modules Needed
This video continues the process of adding a custom field handler started in the previous chapter.
Additional resources
In this video Joe continues the discussion of using hook_views_data()
to describe a module's table to the views module. Building on what was covered in the previous chapter we now deal with exposing one of the individual columns from our table as a field that views can use for filters, sorts, and to display.
Additional resources
Modules Needed
In this chapter Joe will take a look at where to get a copy of the databasics code and what it does already. Throughout the rest of this series we will be working towards replacing functionality from the databasics modules with views integration in order to allow for greater flexibility in the ways that our module can be used. We'll talk about each of this pieces of functionality in this chapter.
Additional resources
Databasics module on GitHub
Overview of the Database Layer in Drupal 7