123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 |
- <?php
- /**
- * @file
- * Implements the basic functionality required to create and display an entity.
- *
- * This example does not use the
- * @link http://drupal.org/project/entity Entity API module @endlink, which is
- * used by many entity implementations and is recommended by many.
- *
- * An example of use of creating and managing entities using the Entity API
- * module is provided in the
- * @link http://drupal.org/project/model Model Entity module @endlink.
- *
- * @todo: Reference the ronald_istos article series
- * @todo: Reference the Drupal module development book
- * @todo: Add a single field
- */
- /**
- * @defgroup entity_example Example: Entity
- * @ingroup examples
- * @{
- * Example creating a core Entity API entity.
- *
- * Note that this example does not use or demonstrate the contrib Entity API,
- * which you can find here: http://drupal.org/project/entity
- */
- /**
- * Implements hook_entity_info().
- *
- * This is the fundamental description of the entity.
- *
- * It provides a single entity with a single bundle and without revision
- * support.
- */
- function entity_example_entity_info() {
- $info['entity_example_basic'] = array(
- // A human readable label to identify our entity.
- 'label' => t('Example Basic Entity'),
- // The controller for our Entity, extending the Drupal core controller.
- 'controller class' => 'EntityExampleBasicController',
- // The table for this entity defined in hook_schema()
- 'base table' => 'entity_example_basic',
- // Returns the uri elements of an entity.
- 'uri callback' => 'entity_example_basic_uri',
- // IF fieldable == FALSE, we can't attach fields.
- 'fieldable' => TRUE,
- // entity_keys tells the controller what database fields are used for key
- // functions. It is not required if we don't have bundles or revisions.
- // Here we do not support a revision, so that entity key is omitted.
- 'entity keys' => array(
- // The 'id' (basic_id here) is the unique id.
- 'id' => 'basic_id' ,
- // Bundle will be determined by the 'bundle_type' field.
- 'bundle' => 'bundle_type',
- ),
- 'bundle keys' => array(
- 'bundle' => 'bundle_type',
- ),
- // FALSE disables caching. Caching functionality is handled by Drupal core.
- 'static cache' => TRUE,
- // Bundles are alternative groups of fields or configuration
- // associated with a base entity type.
- 'bundles' => array(
- 'first_example_bundle' => array(
- 'label' => 'First example bundle',
- // 'admin' key is used by the Field UI to provide field and
- // display UI pages.
- 'admin' => array(
- 'path' => 'admin/structure/entity_example_basic/manage',
- 'access arguments' => array('administer entity_example_basic entities'),
- ),
- ),
- ),
- // View modes allow entities to be displayed differently based on context.
- // As a demonstration we'll support "Tweaky", but we could have and support
- // multiple display modes.
- 'view modes' => array(
- 'tweaky' => array(
- 'label' => t('Tweaky'),
- 'custom settings' => FALSE,
- ),
- ),
- );
- return $info;
- }
- /**
- * Fetch a basic object.
- *
- * This function ends up being a shim between the menu system and
- * entity_example_basic_load_multiple().
- *
- * This function gets its name from the menu system's wildcard
- * naming conventions. For example, /path/%wildcard would end
- * up calling wildcard_load(%wildcard value). In our case defining
- * the path: examples/entity_example/basic/%entity_example_basic in
- * hook_menu() tells Drupal to call entity_example_basic_load().
- *
- * @param int $basic_id
- * Integer specifying the basic entity id.
- * @param bool $reset
- * A boolean indicating that the internal cache should be reset.
- *
- * @return object
- * A fully-loaded $basic object or FALSE if it cannot be loaded.
- *
- * @see entity_example_basic_load_multiple()
- * @see entity_example_menu()
- */
- function entity_example_basic_load($basic_id = NULL, $reset = FALSE) {
- $basic_ids = (isset($basic_id) ? array($basic_id) : array());
- $basic = entity_example_basic_load_multiple($basic_ids, array(), $reset);
- return $basic ? reset($basic) : FALSE;
- }
- /**
- * Loads multiple basic entities.
- *
- * We only need to pass this request along to entity_load(), which
- * will in turn call the load() method of our entity controller class.
- */
- function entity_example_basic_load_multiple($basic_ids = FALSE, $conditions = array(), $reset = FALSE) {
- return entity_load('entity_example_basic', $basic_ids, $conditions, $reset);
- }
- /**
- * Implements the uri callback.
- */
- function entity_example_basic_uri($basic) {
- return array(
- 'path' => 'examples/entity_example/basic/' . $basic->basic_id,
- );
- }
- /**
- * Implements hook_menu().
- */
- function entity_example_menu() {
- $items['examples/entity_example'] = array(
- 'title' => 'Entity Example',
- 'page callback' => 'entity_example_info_page',
- 'access arguments' => array('view any entity_example_basic entity'),
- );
- // This provides a place for Field API to hang its own
- // interface and has to be the same as what was defined
- // in basic_entity_info() above.
- $items['admin/structure/entity_example_basic/manage'] = array(
- 'title' => 'Administer entity_example_basic entity type',
- 'page callback' => 'entity_example_basic_list_entities',
- 'access arguments' => array('administer entity_example_basic entities'),
- );
- // Add example entities.
- $items['admin/structure/entity_example_basic/manage/add'] = array(
- 'title' => 'Add an Entity Example Basic Entity',
- 'page callback' => 'entity_example_basic_add',
- 'access arguments' => array('create entity_example_basic entities'),
- 'type' => MENU_LOCAL_ACTION,
- );
- // List of all entity_example_basic entities.
- $items['admin/structure/entity_example_basic/manage/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- // The page to view our entities - needs to follow what
- // is defined in basic_uri and will use load_basic to retrieve
- // the necessary entity info.
- $items['examples/entity_example/basic/%entity_example_basic'] = array(
- 'title callback' => 'entity_example_basic_title',
- 'title arguments' => array(3),
- 'page callback' => 'entity_example_basic_view',
- 'page arguments' => array(3),
- 'access arguments' => array('view any entity_example_basic entity'),
- );
- // 'View' tab for an individual entity page.
- $items['examples/entity_example/basic/%entity_example_basic/view'] = array(
- 'title' => 'View',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
- // 'Edit' tab for an individual entity page.
- $items['examples/entity_example/basic/%entity_example_basic/edit'] = array(
- 'title' => 'Edit',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('entity_example_basic_form', 3),
- 'access arguments' => array('edit any entity_example_basic entity'),
- 'type' => MENU_LOCAL_TASK,
- );
- // Add example entities.
- $items['examples/entity_example/basic/add'] = array(
- 'title' => 'Add an Entity Example Basic Entity',
- 'page callback' => 'entity_example_basic_add',
- 'access arguments' => array('create entity_example_basic entities'),
- );
- return $items;
- }
- /**
- * Basic information for the page.
- */
- function entity_example_info_page() {
- $content['preface'] = array(
- '#type' => 'item',
- '#markup' => t('The entity example provides a simple example entity.'),
- );
- if (user_access('administer entity_example_basic entities')) {
- $content['preface']['#markup'] = t('You can administer these and add fields and change the view !link.',
- array('!link' => l(t('here'), 'admin/structure/entity_example_basic/manage'))
- );
- }
- $content['table'] = entity_example_basic_list_entities();
- return $content;
- }
- /**
- * Implements hook_permission().
- */
- function entity_example_permission() {
- $permissions = array(
- 'administer entity_example_basic entities' => array(
- 'title' => t('Administer entity_example_basic entities'),
- ),
- 'view any entity_example_basic entity' => array(
- 'title' => t('View any Entity Example Basic entity'),
- ),
- 'edit any entity_example_basic entity' => array(
- 'title' => t('Edit any Entity Example Basic entity'),
- ),
- 'create entity_example_basic entities' => array(
- 'title' => t('Create Entity Example Basic Entities'),
- ),
- );
- return $permissions;
- }
- /**
- * Returns a render array with all entity_example_basic entities.
- *
- * In this basic example we know that there won't be many entities,
- * so we'll just load them all for display. See pager_example.module
- * to implement a pager. Most implementations would probably do this
- * with the contrib Entity API module, or a view using views module,
- * but we avoid using non-core features in the Examples project.
- *
- * @see pager_example.module
- */
- function entity_example_basic_list_entities() {
- $content = array();
- // Load all of our entities.
- $entities = entity_example_basic_load_multiple();
- if (!empty($entities)) {
- foreach ($entities as $entity) {
- // Create tabular rows for our entities.
- $rows[] = array(
- 'data' => array(
- 'id' => $entity->basic_id,
- 'item_description' => l($entity->item_description, 'examples/entity_example/basic/' . $entity->basic_id),
- 'bundle' => $entity->bundle_type,
- ),
- );
- }
- // Put our entities into a themed table. See theme_table() for details.
- $content['entity_table'] = array(
- '#theme' => 'table',
- '#rows' => $rows,
- '#header' => array(t('ID'), t('Item Description'), t('Bundle')),
- );
- }
- else {
- // There were no entities. Tell the user.
- $content[] = array(
- '#type' => 'item',
- '#markup' => t('No entity_example_basic entities currently exist.'),
- );
- }
- return $content;
- }
- /**
- * Callback for a page title when this entity is displayed.
- */
- function entity_example_basic_title($entity) {
- return t('Entity Example Basic (item_description=@item_description)', array('@item_description' => $entity->item_description));
- }
- /**
- * Menu callback to display an entity.
- *
- * As we load the entity for display, we're responsible for invoking a number
- * of hooks in their proper order.
- *
- * @see hook_entity_prepare_view()
- * @see hook_entity_view()
- * @see hook_entity_view_alter()
- */
- function entity_example_basic_view($entity, $view_mode = 'tweaky') {
- // Our entity type, for convenience.
- $entity_type = 'entity_example_basic';
- // Start setting up the content.
- $entity->content = array(
- '#view_mode' => $view_mode,
- );
- // Build fields content - this is where the Field API really comes in to play.
- // The task has very little code here because it all gets taken care of by
- // field module.
- // field_attach_prepare_view() lets the fields load any data they need
- // before viewing.
- field_attach_prepare_view($entity_type, array($entity->basic_id => $entity),
- $view_mode);
- // We call entity_prepare_view() so it can invoke hook_entity_prepare_view()
- // for us.
- entity_prepare_view($entity_type, array($entity->basic_id => $entity));
- // Now field_attach_view() generates the content for the fields.
- $entity->content += field_attach_view($entity_type, $entity, $view_mode);
- // OK, Field API done, now we can set up some of our own data.
- $entity->content['created'] = array(
- '#type' => 'item',
- '#title' => t('Created date'),
- '#markup' => format_date($entity->created),
- );
- $entity->content['item_description'] = array(
- '#type' => 'item',
- '#title' => t('Item Description'),
- '#markup' => $entity->item_description,
- );
- // Now to invoke some hooks. We need the language code for
- // hook_entity_view(), so let's get that.
- global $language;
- $langcode = $language->language;
- // And now invoke hook_entity_view().
- module_invoke_all('entity_view', $entity, $entity_type, $view_mode,
- $langcode);
- // Now invoke hook_entity_view_alter().
- drupal_alter(array('entity_example_basic_view', 'entity_view'),
- $entity->content, $entity_type);
- // And finally return the content.
- return $entity->content;
- }
- /**
- * Implements hook_field_extra_fields().
- *
- * This exposes the "extra fields" (usually properties that can be configured
- * as if they were fields) of the entity as pseudo-fields
- * so that they get handled by the Entity and Field core functionality.
- * Node titles get treated in a similar manner.
- */
- function entity_example_field_extra_fields() {
- $form_elements['item_description'] = array(
- 'label' => t('Item Description'),
- 'description' => t('Item Description (an extra form field)'),
- 'weight' => -5,
- );
- $display_elements['created'] = array(
- 'label' => t('Creation date'),
- 'description' => t('Creation date (an extra display field)'),
- 'weight' => 0,
- );
- $display_elements['item_description'] = array(
- 'label' => t('Item Description'),
- 'description' => t('Just like title, but trying to point out that it is a separate property'),
- 'weight' => 0,
- );
- // Since we have only one bundle type, we'll just provide the extra_fields
- // for it here.
- $extra_fields['entity_example_basic']['first_example_bundle']['form'] = $form_elements;
- $extra_fields['entity_example_basic']['first_example_bundle']['display'] = $display_elements;
- return $extra_fields;
- }
- /**
- * Provides a wrapper on the edit form to add a new entity.
- */
- function entity_example_basic_add() {
- // Create a basic entity structure to be used and passed to the validation
- // and submission functions.
- $entity = entity_get_controller('entity_example_basic')->create();
- return drupal_get_form('entity_example_basic_form', $entity);
- }
- /**
- * Form function to create an entity_example_basic entity.
- *
- * The pattern is:
- * - Set up the form for the data that is specific to your
- * entity: the columns of your base table.
- * - Call on the Field API to pull in the form elements
- * for fields attached to the entity.
- */
- function entity_example_basic_form($form, &$form_state, $entity) {
- $form['item_description'] = array(
- '#type' => 'textfield',
- '#title' => t('Item Description'),
- '#required' => TRUE,
- '#default_value' => $entity->item_description,
- );
- $form['basic_entity'] = array(
- '#type' => 'value',
- '#value' => $entity,
- );
- field_attach_form('entity_example_basic', $entity, $form, $form_state);
- $form['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Save'),
- '#weight' => 100,
- );
- $form['delete'] = array(
- '#type' => 'submit',
- '#value' => t('Delete'),
- '#submit' => array('entity_example_basic_edit_delete'),
- '#weight' => 200,
- );
- return $form;
- }
- /**
- * Validation handler for entity_example_basic_add_form form.
- *
- * We pass things straight through to the Field API to handle validation
- * of the attached fields.
- */
- function entity_example_basic_form_validate($form, &$form_state) {
- field_attach_form_validate('entity_example_basic', $form_state['values']['basic_entity'], $form, $form_state);
- }
- /**
- * Form submit handler: Submits basic_add_form information.
- */
- function entity_example_basic_form_submit($form, &$form_state) {
- $entity = $form_state['values']['basic_entity'];
- $entity->item_description = $form_state['values']['item_description'];
- field_attach_submit('entity_example_basic', $entity, $form, $form_state);
- $entity = entity_example_basic_save($entity);
- $form_state['redirect'] = 'examples/entity_example/basic/' . $entity->basic_id;
- }
- /**
- * Form deletion handler.
- *
- * @todo: 'Are you sure?' message.
- */
- function entity_example_basic_edit_delete($form, &$form_state) {
- $entity = $form_state['values']['basic_entity'];
- entity_example_basic_delete($entity);
- drupal_set_message(t('The entity %item_description (ID %id) has been deleted',
- array('%item_description' => $entity->item_description, '%id' => $entity->basic_id))
- );
- $form_state['redirect'] = 'examples/entity_example';
- }
- /**
- * We save the entity by calling the controller.
- */
- function entity_example_basic_save(&$entity) {
- return entity_get_controller('entity_example_basic')->save($entity);
- }
- /**
- * Use the controller to delete the entity.
- */
- function entity_example_basic_delete($entity) {
- entity_get_controller('entity_example_basic')->delete($entity);
- }
- /**
- * EntityExampleBasicControllerInterface definition.
- *
- * We create an interface here because anyone could come along and
- * use hook_entity_info_alter() to change our controller class.
- * We want to let them know what methods our class needs in order
- * to function with the rest of the module, so here's a handy list.
- *
- * @see hook_entity_info_alter()
- */
- interface EntityExampleBasicControllerInterface
- extends DrupalEntityControllerInterface {
- /**
- * Create an entity.
- */
- public function create();
- /**
- * Save an entity.
- *
- * @param object $entity
- * The entity to save.
- */
- public function save($entity);
- /**
- * Delete an entity.
- *
- * @param object $entity
- * The entity to delete.
- */
- public function delete($entity);
- }
- /**
- * EntityExampleBasicController extends DrupalDefaultEntityController.
- *
- * Our subclass of DrupalDefaultEntityController lets us add a few
- * important create, update, and delete methods.
- */
- class EntityExampleBasicController
- extends DrupalDefaultEntityController
- implements EntityExampleBasicControllerInterface {
- /**
- * Create and return a new entity_example_basic entity.
- */
- public function create() {
- $entity = new stdClass();
- $entity->type = 'entity_example_basic';
- $entity->basic_id = 0;
- $entity->bundle_type = 'first_example_bundle';
- $entity->item_description = '';
- return $entity;
- }
- /**
- * Saves the custom fields using drupal_write_record().
- */
- public function save($entity) {
- // If our entity has no basic_id, then we need to give it a
- // time of creation.
- if (empty($entity->basic_id)) {
- $entity->created = time();
- }
- // Invoke hook_entity_presave().
- module_invoke_all('entity_presave', $entity, 'entity_example_basic');
- // The 'primary_keys' argument determines whether this will be an insert
- // or an update. So if the entity already has an ID, we'll specify
- // basic_id as the key.
- $primary_keys = $entity->basic_id ? 'basic_id' : array();
- // Write out the entity record.
- drupal_write_record('entity_example_basic', $entity, $primary_keys);
- // We're going to invoke either hook_entity_update() or
- // hook_entity_insert(), depending on whether or not this is a
- // new entity. We'll just store the name of hook_entity_insert()
- // and change it if we need to.
- $invocation = 'entity_insert';
- // Now we need to either insert or update the fields which are
- // attached to this entity. We use the same primary_keys logic
- // to determine whether to update or insert, and which hook we
- // need to invoke.
- if (empty($primary_keys)) {
- field_attach_insert('entity_example_basic', $entity);
- }
- else {
- field_attach_update('entity_example_basic', $entity);
- $invocation = 'entity_update';
- }
- // Invoke either hook_entity_update() or hook_entity_insert().
- module_invoke_all($invocation, $entity, 'entity_example_basic');
- return $entity;
- }
- /**
- * Delete a single entity.
- *
- * Really a convenience function for deleteMultiple().
- */
- public function delete($entity) {
- $this->deleteMultiple(array($entity));
- }
- /**
- * Delete one or more entity_example_basic entities.
- *
- * Deletion is unfortunately not supported in the base
- * DrupalDefaultEntityController class.
- *
- * @param array $entities
- * An array of entity IDs or a single numeric ID.
- */
- public function deleteMultiple($entities) {
- $basic_ids = array();
- if (!empty($entities)) {
- $transaction = db_transaction();
- try {
- foreach ($entities as $entity) {
- // Invoke hook_entity_delete().
- module_invoke_all('entity_delete', $entity, 'entity_example_basic');
- field_attach_delete('entity_example_basic', $entity);
- $basic_ids[] = $entity->basic_id;
- }
- db_delete('entity_example_basic')
- ->condition('basic_id', $basic_ids, 'IN')
- ->execute();
- }
- catch (Exception $e) {
- $transaction->rollback();
- watchdog_exception('entity_example', $e);
- throw $e;
- }
- }
- }
- }
- /**
- * @} End of "defgroup entity_example".
- */
|