Monday, April 9, 2012

Drupal Entities are the New Content Type

This may be old news to some, but for many Drupal entities are still a very new concept. While I could spend all day talking about the entity system, I just wanted to highlight what it is and how to get started.

In a nutshell, the entity system allows you to access things like nodes and users from a common interface, as well as define your own types of entities. To define your own entities, you implement hook_entity_info() in your module.

Here is a quick example form a sandbox module I'm working on. /** * Implements hook_entity_info() */ function entityqueue_entity_info() { $types['entityqueue'] = array( 'label' => t('Entity Queue'), 'base table' => 'entityqueue_queue', 'load hook' => 'entityqueue_load', 'uri callback' => 'entityqueue_uri', 'fieldable' => TRUE, 'entity keys' => array( 'id' => 'qid', 'label' => 'title', ), ); $types['entityqueueitem'] = array( 'label' => t('Entity Queue Item'), 'base table' => 'entityqueue_entity', 'load hook' => 'entityqueueitem_load', 'uri callback' => 'entityqueueitem_uri', 'fieldable' => TRUE, 'entity keys' => array( 'id' => 'qeid', ) ); return $types; } In my example, I'm not using bundles or revisions, both can be extremely useful depending on your need, but I am using the Field API, which makes it easy to allow site builders to add fields to my entities to extend their usage, just like you would use CCK in Drupal 6 to extend nodes (now the Field API in Drupal 7). From there, in your form builders, you use field_attach_form() to add these extra fields to your form, as seen at the end of node_form() and when you save your entity, you use field_attach_presave(), field_attach_insert() and field_attach_update() to handle insertion and updating values for those fields, and don't forget to use field_attach_delete() when handling deleting one of your entities./** * Save a queue. */ function entityqueue_save(&$queue) { $transaction = db_transaction(); try { // Load stored entity, if any. if (!empty($queue->qid)) { $queue->original = entity_load_unchanged('entityqueue', $queue->qid); } field_attach_presave('entityqueue', $queue); if (!isset($queue->is_new)) { $queue->is_new = empty($queue->qid); } module_invoke_all('entity_presave', $queue, 'entityqueue'); // Save the queue. if ($queue->is_new) { drupal_write_record('entityqueue_queue', $queue); $op = 'insert'; } else { // For existing queues, update the queue record which matches // $queue->qid. drupal_write_record('entityqueue_queue', $queue, 'qid'); $op = 'update'; } // Save fields. $function = "field_attach_$op"; $function('entityqueue', $queue); module_invoke_all('entity_' . $op, $queue, 'entityqueue'); // Clear internal properties. unset($queue->is_new); unset($queue->original); // Clear the static loading cache. entity_get_controller('entityqueue')->resetCache(array($queue->qid)); // Ignore slave server temporarily to give time for the // saved entity to be propagated to the slave. db_ignore_slave(); } catch (Exception $e) { $transaction->rollback(); watchdog_exception('entityqueue', $e); throw $e; } } To load your entities, complete with any attached fields, you can use entity_load(), which you may write a couple wrapper functions to make it even simpler, like so./** * Load an entityqueue object from the database. */ function entityqueue_load($qid, $reset = FALSE) { $qids = (isset($qid) ? array($qid) : array()); $conditions = array(); $queue = entity_load('entityqueue', $qids, $conditions, $reset); return $queue ? reset($queue) : FALSE; } /** * Load multiple queues. */ function entityqueue_load_multiple($qids, $reset = FALSE) { $conditions = array(); return entity_load('entityqueue', $qids, $conditions, $reset); } I like using node_load() and node_load_multiple() as examples as well, usually the best examples can be found right in core, just do a search for hook_entity_info() and look at the different callbacks and menu items callbacks.

Implement a couple views hooks and your entity has all the potential as it would if you had created a new content type, without cluttering up the content pages. For further reading, see The what, where and when of Drupal entities or if you are interested feel free to browse my sandbox entityqueue module on github.

No comments: