123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- <?php
- /**
- * @file
- * This is an example outlining how a module can make use of the new DBTNG
- * database API in Drupal 7.
- *
- * @todo Demonstrate transaction usage.
- *
- * General documentation is available at
- * @link database Database abstraction layer documentation @endlink and
- * at @link http://drupal.org/node/310069 @endlink.
- */
- /**
- * @defgroup dbtng_example Example: Database (DBTNG)
- * @ingroup examples
- * @{
- * Database examples, including DBTNG.
- *
- * 'DBTNG' means 'Database: The Next Generation.' Yes, Drupallers are nerds.
- *
- * General documentation is available at
- * @link database.inc database abstraction layer documentation @endlink and
- * at @link http://drupal.org/node/310069 Database API @endlink.
- *
- * The several examples here demonstrate basic database usage.
- *
- * In Drupal 6, the recommended method to save or update an entry in the
- * database was drupal_write_record() or db_query().
- *
- * In Drupal 7 and forward, the usage of db_query()
- * for INSERT, UPDATE, or DELETE is deprecated, because it is
- * database-dependent. Instead specific functions are provided to perform these
- * operations: db_insert(), db_update(), and db_delete() do the job now.
- * (Note that drupal_write_record() is also deprecated.)
- *
- * db_insert() example:
- * @code
- * // INSERT INTO {dbtng_example} (name, surname) VALUES('John, 'Doe')
- * db_insert('dbtng_example')
- * ->fields(array('name' => 'John', 'surname' => 'Doe'))
- * ->execute();
- * @endcode
- *
- * db_update() example:
- * @code
- * // UPDATE {dbtng_example} SET name = 'Jane' WHERE name = 'John'
- * db_update('dbtng_example')
- * ->fields(array('name' => 'Jane'))
- * ->condition('name', 'John')
- * ->execute();
- * @endcode
- *
- * db_delete() example:
- * @code
- * // DELETE FROM {dbtng_example} WHERE name = 'Jane'
- * db_delete('dbtng_example')
- * ->condition('name', 'Jane')
- * ->execute();
- * @endcode
- *
- * See @link database Database Abstraction Layer @endlink
- * @see db_insert()
- * @see db_update()
- * @see db_delete()
- * @see drupal_write_record()
- */
- /**
- * Save an entry in the database.
- *
- * The underlying DBTNG function is db_insert().
- *
- * In Drupal 6, this would have been:
- * @code
- * db_query(
- * "INSERT INTO {dbtng_example} (name, surname, age)
- * VALUES ('%s', '%s', '%d')",
- * $entry['name'],
- * $entry['surname'],
- * $entry['age']
- * );
- * @endcode
- *
- * Exception handling is shown in this example. It could be simplified
- * without the try/catch blocks, but since an insert will throw an exception
- * and terminate your application if the exception is not handled, it is best
- * to employ try/catch.
- *
- * @param array $entry
- * An array containing all the fields of the database record.
- *
- * @see db_insert()
- */
- function dbtng_example_entry_insert($entry) {
- $return_value = NULL;
- try {
- $return_value = db_insert('dbtng_example')
- ->fields($entry)
- ->execute();
- }
- catch (Exception $e) {
- drupal_set_message(t('db_insert failed. Message = %message, query= %query',
- array('%message' => $e->getMessage(), '%query' => $e->query_string)), 'error');
- }
- return $return_value;
- }
- /**
- * Update an entry in the database.
- *
- * The former, deprecated techniques used db_query() or drupal_write_record():
- * @code
- * drupal_write_record('dbtng_example', $entry, $entry['pid']);
- * @endcode
- *
- * @code
- * db_query(
- * "UPDATE {dbtng_example}
- * SET name = '%s', surname = '%s', age = '%d'
- * WHERE pid = %d",
- * $entry['pid']
- * );
- * @endcode
- *
- * @param array $entry
- * An array containing all the fields of the item to be updated.
- *
- * @see db_update()
- */
- function dbtng_example_entry_update($entry) {
- try {
- // db_update()...->execute() returns the number of rows updated.
- $count = db_update('dbtng_example')
- ->fields($entry)
- ->condition('pid', $entry['pid'])
- ->execute();
- }
- catch (Exception $e) {
- drupal_set_message(t('db_update failed. Message = %message, query= %query',
- array('%message' => $e->getMessage(), '%query' => $e->query_string)), 'error');
- }
- return $count;
- }
- /**
- * Delete an entry from the database.
- *
- * The usage of db_query is deprecated except for static queries.
- * Formerly, a deletion might have been accomplished like this:
- * @code
- * db_query("DELETE FROM {dbtng_example} WHERE pid = %d", $entry['pid]);
- * @endcode
- *
- * @param array $entry
- * An array containing at least the person identifier 'pid' element of the
- * entry to delete.
- *
- * @see db_delete()
- */
- function dbtng_example_entry_delete($entry) {
- db_delete('dbtng_example')
- ->condition('pid', $entry['pid'])
- ->execute();
- }
- /**
- * Read from the database using a filter array.
- *
- * In Drupal 6, the standard function to perform reads was db_query(), and
- * for static queries, it still is.
- *
- * db_query() used an SQL query with placeholders and arguments as parameters.
- *
- * @code
- * // Old way
- * $query = "SELECT * FROM {dbtng_example} n WHERE n.uid = %d AND name = '%s'";
- * $result = db_query($query, $uid, $name);
- * @endcode
- *
- * Drupal 7 DBTNG provides an abstracted interface that will work with a wide
- * variety of database engines.
- *
- * db_query() is deprecated except when doing a static query. The following is
- * perfectly acceptable in Drupal 7. See
- * @link http://drupal.org/node/310072 the handbook page on static queries @endlink
- *
- * @code
- * // SELECT * FROM {dbtng_example} WHERE uid = 0 AND name = 'John'
- * db_query(
- * "SELECT * FROM {dbtng_example} WHERE uid = :uid and name = :name",
- * array(':uid' => 0, ':name' => 'John')
- * )->execute();
- * @endcode
- *
- * But for more dynamic queries, Drupal provides the db_select() API method, so
- * there are several ways to perform the same SQL query. See the
- * @link http://drupal.org/node/310075 handbook page on dynamic queries. @endlink
- *
- * @code
- * // SELECT * FROM {dbtng_example} WHERE uid = 0 AND name = 'John'
- * db_select('dbtng_example')
- * ->fields('dbtng_example')
- * ->condition('uid', 0)
- * ->condition('name', 'John')
- * ->execute();
- * @endcode
- *
- * Here is db_select with named placeholders:
- * @code
- * // SELECT * FROM {dbtng_example} WHERE uid = 0 AND name = 'John'
- * $arguments = array(':name' => 'John', ':uid' => 0);
- * db_select('dbtng_example')
- * ->fields('dbtng_example')
- * ->where('uid = :uid AND name = :name', $arguments)
- * ->execute();
- * @endcode
- *
- * Conditions are stacked and evaluated as AND and OR depending on the type of
- * query. For more information, read the conditional queries handbook page at:
- * http://drupal.org/node/310086
- *
- * The condition argument is an 'equal' evaluation by default, but this can be
- * altered:
- * @code
- * // SELECT * FROM {dbtng_example} WHERE age > 18
- * db_select('dbtng_example')
- * ->fields('dbtng_example')
- * ->condition('age', 18, '>')
- * ->execute();
- * @endcode
- *
- * @param array $entry
- * An array containing all the fields used to search the entries in the table.
- *
- * @return object
- * An object containing the loaded entries if found.
- *
- * @see db_select()
- * @see db_query()
- * @see http://drupal.org/node/310072
- * @see http://drupal.org/node/310075
- */
- function dbtng_example_entry_load($entry = array()) {
- // Read all fields from the dbtng_example table.
- $select = db_select('dbtng_example', 'example');
- $select->fields('example');
- // Add each field and value as a condition to this query.
- foreach ($entry as $field => $value) {
- $select->condition($field, $value);
- }
- // Return the result in object format.
- return $select->execute()->fetchAll();
- }
- /**
- * Render a filtered list of entries in the database.
- *
- * DBTNG also helps processing queries that return several rows, providing the
- * found objects in the same query execution call.
- *
- * This function queries the database using a JOIN between users table and the
- * example entries, to provide the username that created the entry, and creates
- * a table with the results, processing each row.
- *
- * SELECT
- * e.pid as pid, e.name as name, e.surname as surname, e.age as age
- * u.name as username
- * FROM
- * {dbtng_example} e
- * JOIN
- * users u ON e.uid = u.uid
- * WHERE
- * e.name = 'John' AND e.age > 18
- *
- * @see db_select()
- * @see http://drupal.org/node/310075
- */
- function dbtng_example_advanced_list() {
- $output = '';
- $select = db_select('dbtng_example', 'e');
- // Join the users table, so we can get the entry creator's username.
- $select->join('users', 'u', 'e.uid = u.uid');
- // Select these specific fields for the output.
- $select->addField('e', 'pid');
- $select->addField('u', 'name', 'username');
- $select->addField('e', 'name');
- $select->addField('e', 'surname');
- $select->addField('e', 'age');
- // Filter only persons named "John".
- $select->condition('e.name', 'John');
- // Filter only persons older than 18 years.
- $select->condition('e.age', 18, '>');
- // Make sure we only get items 0-49, for scalability reasons.
- $select->range(0, 50);
- // Now, loop all these entries and show them in a table. Note that there is no
- // db_fetch_* object or array function being called here. Also note that the
- // following line could have been written as
- // $entries = $select->execute()->fetchAll() which would return each selected
- // record as an object instead of an array.
- $entries = $select->execute()->fetchAll(PDO::FETCH_ASSOC);
- if (!empty($entries)) {
- $rows = array();
- foreach ($entries as $entry) {
- // Sanitize the data before handing it off to the theme layer.
- $rows[] = array_map('check_plain', $entry);
- }
- // Make a table for them.
- $header = array(t('Id'), t('Created by'), t('Name'), t('Surname'), t('Age'));
- $output .= theme('table', array('header' => $header, 'rows' => $rows));
- }
- else {
- drupal_set_message(t('No entries meet the filter criteria (Name = "John" and Age > 18).'));
- }
- return $output;
- }
- /**
- * Implements hook_help().
- *
- * Show some help on each form provided by this module.
- */
- function dbtng_example_help($path) {
- $output = '';
- switch ($path) {
- case 'examples/dbtng':
- $output = t('Generate a list of all entries in the database. There is no filter in the query.');
- break;
- case 'examples/dbtng/advanced':
- $output = t('A more complex list of entries in the database.') . ' ';
- $output .= t('Only the entries with name = "John" and age older than 18 years are shown, the username of the person who created the entry is also shown.');
- break;
- case 'examples/dbtng/update':
- $output = t('Demonstrates a database update operation.');
- break;
- case 'examples/dbtng/add':
- $output = t('Add an entry to the dbtng_example table.');
- break;
- }
- return $output;
- }
- /**
- * Implements hook_menu().
- *
- * Set up calls to drupal_get_form() for all our example cases.
- */
- function dbtng_example_menu() {
- $items = array();
- $items['examples/dbtng'] = array(
- 'title' => 'DBTNG Example',
- 'page callback' => 'dbtng_example_list',
- 'access callback' => TRUE,
- );
- $items['examples/dbtng/list'] = array(
- 'title' => 'List',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10,
- );
- $items['examples/dbtng/add'] = array(
- 'title' => 'Add entry',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('dbtng_example_form_add'),
- 'access callback' => TRUE,
- 'type' => MENU_LOCAL_TASK,
- 'weight' => -9,
- );
- $items['examples/dbtng/update'] = array(
- 'title' => 'Update entry',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('dbtng_example_form_update'),
- 'type' => MENU_LOCAL_TASK,
- 'access callback' => TRUE,
- 'weight' => -5,
- );
- $items['examples/dbtng/advanced'] = array(
- 'title' => 'Advanced list',
- 'page callback' => 'dbtng_example_advanced_list',
- 'access callback' => TRUE,
- 'type' => MENU_LOCAL_TASK,
- );
- return $items;
- }
- /**
- * Render a list of entries in the database.
- */
- function dbtng_example_list() {
- $output = '';
- // Get all entries in the dbtng_example table.
- if ($entries = dbtng_example_entry_load()) {
- $rows = array();
- foreach ($entries as $entry) {
- // Sanitize the data before handing it off to the theme layer.
- $rows[] = array_map('check_plain', (array) $entry);
- }
- // Make a table for them.
- $header = array(t('Id'), t('uid'), t('Name'), t('Surname'), t('Age'));
- $output .= theme('table', array('header' => $header, 'rows' => $rows));
- }
- else {
- drupal_set_message(t('No entries have been added yet.'));
- }
- return $output;
- }
- /**
- * Prepare a simple form to add an entry, with all the interesting fields.
- */
- function dbtng_example_form_add($form, &$form_state) {
- $form = array();
- $form['add'] = array(
- '#type' => 'fieldset',
- '#title' => t('Add a person entry'),
- );
- $form['add']['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Name'),
- '#size' => 15,
- );
- $form['add']['surname'] = array(
- '#type' => 'textfield',
- '#title' => t('Surname'),
- '#size' => 15,
- );
- $form['add']['age'] = array(
- '#type' => 'textfield',
- '#title' => t('Age'),
- '#size' => 5,
- '#description' => t("Values greater than 127 will cause an exception. Try it - it's a great example why exception handling is needed with DTBNG."),
- );
- $form['add']['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Add'),
- );
- return $form;
- }
- /**
- * Submit handler for 'add entry' form.
- */
- function dbtng_example_form_add_submit($form, &$form_state) {
- global $user;
- // Save the submitted entry.
- $entry = array(
- 'name' => $form_state['values']['name'],
- 'surname' => $form_state['values']['surname'],
- 'age' => $form_state['values']['age'],
- 'uid' => $user->uid,
- );
- $return = dbtng_example_entry_insert($entry);
- if ($return) {
- drupal_set_message(t("Created entry @entry", array('@entry' => print_r($entry, TRUE))));
- }
- }
- /**
- * Sample UI to update a record.
- */
- function dbtng_example_form_update($form, &$form_state) {
- $form = array(
- '#prefix' => '<div id="updateform">',
- '#suffix' => '</div>',
- );
- $entries = dbtng_example_entry_load();
- $keyed_entries = array();
- if (empty($entries)) {
- $form['no_values'] = array(
- '#value' => t("No entries exist in the table dbtng_example table."),
- );
- return $form;
- }
- foreach ($entries as $entry) {
- $options[$entry->pid] = t("@pid: @name @surname (@age)",
- array(
- '@pid' => $entry->pid,
- '@name' => $entry->name,
- '@surname' => $entry->surname,
- '@age' => $entry->age,
- )
- );
- $keyed_entries[$entry->pid] = $entry;
- }
- $default_entry = !empty($form_state['values']['pid']) ? $keyed_entries[$form_state['values']['pid']] : $entries[0];
- $form_state['entries'] = $keyed_entries;
- $form['pid'] = array(
- '#type' => 'select',
- '#options' => $options,
- '#title' => t('Choose entry to update'),
- '#default_value' => $default_entry->pid,
- '#ajax' => array(
- 'wrapper' => 'updateform',
- 'callback' => 'dbtng_example_form_update_callback',
- ),
- );
- $form['name'] = array(
- '#type' => 'textfield',
- '#title' => t('Updated first name'),
- '#size' => 15,
- '#default_value' => $default_entry->name,
- );
- $form['surname'] = array(
- '#type' => 'textfield',
- '#title' => t('Updated last name'),
- '#size' => 15,
- '#default_value' => $default_entry->surname,
- );
- $form['age'] = array(
- '#type' => 'textfield',
- '#title' => t('Updated age'),
- '#size' => 4,
- '#default_value' => $default_entry->age,
- '#description' => t("Values greater than 127 will cause an exception"),
- );
- $form['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Update'),
- );
- return $form;
- }
- /**
- * AJAX callback handler for the pid select.
- *
- * When the pid changes, populates the defaults from the database in the form.
- */
- function dbtng_example_form_update_callback($form, $form_state) {
- $entry = $form_state['entries'][$form_state['values']['pid']];
- // Setting the #value of items is the only way I was able to figure out
- // to get replaced defaults on these items. #default_value will not do it
- // and shouldn't.
- foreach (array('name', 'surname', 'age') as $item) {
- $form[$item]['#value'] = $entry->$item;
- }
- return $form;
- }
- /**
- * Submit handler for 'update entry' form.
- */
- function dbtng_example_form_update_submit($form, &$form_state) {
- global $user;
- // Save the submitted entry.
- $entry = array(
- 'pid' => $form_state['values']['pid'],
- 'name' => $form_state['values']['name'],
- 'surname' => $form_state['values']['surname'],
- 'age' => $form_state['values']['age'],
- 'uid' => $user->uid,
- );
- $count = dbtng_example_entry_update($entry);
- drupal_set_message(t("Updated entry @entry (@count row updated)",
- array('@count' => $count, '@entry' => print_r($entry, TRUE))));
- }
- /**
- * @} End of "defgroup dbtng_example".
- */
|