Drupal II: The SQL


Published on

It's back...

AND it's better than ever, DBTNG (Database: The Next Generation) is nothing to be scared of and we'll show how easy it is to create both static and dynamic query statements for use in your custom modules and Drupal 6 to Drupal 7 module migration work. In this session we'll take a look at the Drupal 7 database abstraction layer and the database API and cover:

To db_query or not to db_query?

Dynamic query syntax and fluid interfaces

Working with result sets

Joins, conditional statements, subselects and sorting with db_select

Tagging your db_select queries for hook awareness

Decorator patterns for db_select -

db_update, db_insert, db_delete and our new friend, db_merge

Explore alternatives to views and how and when to make that call.

After this session attendees will be ready for Drupal III: Drupalicon Takes Manhattan

Published in: Technology, Education
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • Content – nodes, entitiesconfig - administrator, moduleconfiguraton, or user based configuration settingssystem – logs (watchdog), sessions, queue to be processed at next cron, class hashes
  • What is DB Abstraction?-> db implementations vary from product to product, ANSI sql implementations vary widelyDB Abstraction is nothing new – Just the way it is done.
  • It was built on PDO – PHP Data ObjectsPDO is written in PHPOOPDrupal implements extensions or interfaces of PDO classesPDO is in wide use across many projects (Symfony, Zend Framework, Magento)
  • 2 Primary ways to interact with data in D7dbquery - performant but limited transferability.Dynamic queries - more complex, high transferability, powerful, less performant.
  • Let’s use this simple query of the node table
  • enclose tables in { } for db prefixarg 2 - use placeholders to avoid sql injection, start with ":"EX: WHERE type = :type", array(':type' => 'page',))arg3 – options array - 2 common ones are:target - default or slavefetch - pdo fetch type (the select statement will return into the fetch type specified. Can and should use object(default), assoc array, or a string class name.
  • In transitioning D6 db_query to D7 be aware:The syntax signature has changed –D6 took a single parameter – the $query, followed by a variable number of arguments or an array of query substitutions.D6 used the % syntax for placeholders instead of the “:” syntax.Functions other than select could be executed via db_query.
  • Let’s use this simple query of the node table
  • Let’s use this simple query of the node table
  • $query = db_select(‘node’, ’n’);$result = $query->fields(‘n’, array(‘nid’,’title’) ->condition(‘n.type’,$type) ->execute;Fluid Interface - allows chaining (because the results of each chainable method return an instance of the object itself)Not all methods are chainable so consult your documentation.$result = $query->execute();Query statements are executed by ->execute();  easy to forget, but don't.You’ll get back a result set / statement objectforeach ($result as $record) { //do something
  • Tagging - any dynamic select query can be tagged with one or more strings which then allows alter hooks to determine if they need to take action.Via hook_query_alter & hook_query_TAG_alterex: $query->addTag('node_access');  - this should be implemented on all queries that retrieve nodes.Node access query alter will then check to see if a user can see the nodes in the result.
  • Extenders - implements a decorator pattern, currently only two in coreDecorator pattern – allows the “decoration” of a classes functionality at run time, allowing you to change a single instance of a class with a set of functionalityTableSort and PagerQuery = adds the methods for these extension to queryexample:$query = $query->extend('TableSort')->orderByHeader($header);Put these near the start.Not chainable, if you forget to return it to itself it will have odd results.
  • Drupal II: The SQL

    1. 1. Drupal II: The SQLDavid Diers, DeveloperFour KitchensAustin, TXD.O - thebruce@beautyhammer
    2. 2. What we’ll cover Basics of the Drupal DB API Using db_query Using and building dynamic queries including Criteria clauses, joins, sorting, sub- selects, extenders, and tagging How to work with result sets
    3. 3. Drupal and the DBDrupal uses the DB to: Store content - where "content" is thought of very broadly. Store user or module configurations Store system valuesDrupal retrieves these valuesall of the time.
    4. 4. Drupal and DB Abstraction What is DB Abstraction? A way of uniformly interacting and leveraging SQL commands with multiple types of database products. A structured way of dynamically constructing SQL statements DB Abstraction is nothing new for Drupal
    5. 5. Drupal 7 DB API uses PDO In D7 the DB Abstraction layer got a face-lift Built on PDO PDO is PHPOOP Drupal extends PDO classes PDO used in many projects
    6. 6. Why learn the DB API? Isn‟t most of this stuff in functions already? Doesn‟t views do this for me? Can‟t I just use raw SQL like they did in ye olde days ™?
    7. 7. Why Learn the DB API? Need a result set that you can‟t get or requires custom views development? Writing or supporting custom modules with their own schema? Need results from the contrib module‟s schema but there isn‟t a function to do so? Patching an existing modules‟ database functionality? Need additional ways besides features, views, panels to transfer configuration via update hooks? Need to implement custom sql statements to improve the performance of your site?
    8. 8. Using the DB API 2 Primary ways to interact with data in D7 dbquery – performant, limited transferability. Dynamic queries - more complex, high transferability, powerful, less performant.
    9. 9. db_query – the basics IN SQL: IN db_query: <?phpSELECT nid, title $type = „article‟;FROM node $result = db_query("SELECT nid, titleWHERE type = „article‟; FROM {node} WHERE type = :type", array(:type => $type,));
    10. 10. db_query – the breakdown$result = db_query("SELECT nid, title FROM {node} WHERE type = :type",array(:type => $type,)); db_query($query, $placeholders, $options) enclose tables in { } Placeholders start with ":" EX: WHERE type = :type", array(:type => page,)) Options array - 2 common ones are: Target (default or slave) Fetch (pdo fetch type)http://druptest7.dev:8888/example_dbq
    11. 11. db_query d6 => d7transitions In transitioning D6 db_query to D7 be aware: The syntax signature has changed – • D6 parameters were the $query, followed by a variable number of arguments or an array of query substitutions. • % syntax for placeholders • Varied sql commands executed via db_query.
    12. 12. Dynamic sql – the basics Dynamic Queries Much more transportable. You MUST use for ( INSERT, UPDATE, DELETE) You may use for (SELECT) • http://www.lullabot.com/articles/simplify-your-code- with-drupal-7s-database-api ).
    13. 13. db_select – the basics IN SQL: IN db_select: <?phpSELECT nid, title $type = „article‟;FROM node $query = db_select(„node‟, ‟n‟);WHERE type = „article‟; $result = $query->fields(„n‟, array(„nid‟,‟title‟) ->condition(„n.type‟,$type) ->execute();
    14. 14. db_select – the basics(„node‟, „n‟) IN db_select:Name of Table / Alias <?php $type = „article‟;(fields(„n‟, array(„nid‟, $query = db_select(„node‟, ‟n‟);„title‟)) $result = $query->fields(„n‟, array(„nid‟,‟title‟)Alias, array of fields ->condition(„n.type‟,$type) ->execute();Single quotes areimportant fortransferability.
    15. 15. Dynamic Queries – of note$query = db_select(„node‟, ‟n‟);$result = $query->fields(„n‟, array(„nid‟,‟title‟) ->condition(„n.type‟,$type) ->execute(); Fluid Interface - allows method chaining Query statements are executed by ->execute(); easy to forget, but dont. You‟ll get back a result set / statement object
    16. 16. Working with Result Sets Use - foreach loop or or - Specificaly get the next record $record = $result->fetch(); // Use the default fetch mode. $record = $result->fetchObject(); // Fetch as a stdClass object. $record = $result->fetchAssoc(); // Fetch as an associative array. or - to get a single field $record = $result->fetchField($column_index);
    17. 17. Which should I use? Is your query static? Use db_query it is faster. Does your query need to be constructed at run time? Use dynamic queries Do you need to INSERT, UPDATE, or DELETE? Use Dynamic queries. Are you querying the node table – Use Dynamic queries to respect node access.
    18. 18. More with Dynamic Queries How to add fields or select * Conditional Statements AND / OR Sub-selects JOINS SORT
    19. 19. Fields and db_select Adding fields to a query: $query->fields(n, array(nid, title, created, uid)); "select *" is fields with no field array indicated: $query->fields(n); http://druptest7.dev:8888/example_dyn
    20. 20. Conditional Statements Signature: $query->condition($field, $value = NULL, $operator = =) Default operator is SQL = can take ANSI sql comparators <, >, LIKE, = >= EX: $query->condition(nid,1) EX: $query->condition(nid,1, <>) In or between: EX: $query->condition(myfield, array(1, 2, 3), IN);
    21. 21. Conditional Statements(more) Nested Conditionals: db_and() / db_or() / db_xor() are used to handle nested conditionals such as: ->condition(db_or() ->condition(field2, 5) ->condition(field3, 6))Testing for NULL:$query->isNull(myfield);$query->isNotNull(myfield);
    22. 22. An example from the field… Original query:$result = db_query(SELECT * FROM {users}WHERE ((access <> 0 AND login <> 0 AND access< (%d - %d)) OR (login = 0 AND created < (%d -%d))) AND uid <> 1, REQUEST_TIME, $warn_time,REQUEST_TIME, $warn_time);
    23. 23. Now In dynamic query format $query = db_select(users, u); $query->fields(u, array(uid, name, mail, created, access)) ->condition(db_or() ->condition(db_and() ->condition(u.access, 0, <>) ->condition(u.login, 0, <>) ->condition(u.access, REQUEST_TIME - $warn_time, <)) ->condition(db_and() ->condition(u.login, 0) ->condition(u.created, REQUEST_TIME - $warn_time, <)) ) ->condition(u.uid, 1, <>); $results = $query->execute();
    24. 24. Subselects Subselects - form a query using dbtng then instead of executing it - use that query variable in a condition. Most successful when one value is returned, or a one column return value is used with an IN clause. $query->condition(myfield, $querysubselect, IN);
    25. 25. JOINS & db_select<?php$query = db_select(node, n);$query->join(field_data_body, b, n.nid = b.entity_id);$query->fields(n, array(nid, title))->condition(n.type, page)->condition(n.status, 1)->orderBy(n.created, DESC)->addTag(node_access);?>
    26. 26. dynamic queries: sorting orderBy(„field‟, „ASC‟/‟DESC‟)$result = db_select(„node‟, „n‟) ->fields(„n‟, array(„title‟)) ->orderBy(„n.created‟, „DESC‟) ->execute();
    27. 27. db_select TaggingTagging – lets alter hooks take actionex: $query->addTag(node_access); - this should beimplemented on all queries that retrieve nodes.Node access query alter will then check to see if auser can see the nodes in the result.(http://druptest7.dev:8888/example_tag)
    28. 28. What about the others? db_update, db_insert, db_delete Similar syntax Assemble and execute.
    29. 29. db_insert Syntax: $query = db_insert(node, $options); $nid = db_insert(node) ->fields(array( title => ‟This Example, uid => 1, created => REQUEST_TIME, )) ->execute(); db_insert returns the auto-increment value defined by hook_schema.(http://druptest7.dev:8888/example_insert)
    30. 30. db_update$num_updated = db_update(node)->fields(array( uid => 1))->condition(uid, 2)->execute();db_update returns the number of records updated. http://druptest7.dev:8888/example_update
    31. 31. db_deleteSignature: $query = db_delete(node, $options);$num_deleted = db_delete(node)->condition(nid, 5)->execute();db_delete returns the number of rows deleted. http://druptest7.dev:8888/example_delete
    32. 32. db_select extenders Extenders - implements a decorator pattern, currently only two in core TableSort and PagerQuery = adds the methods for these extension to query example: $query = $query ->extend(TableSort) ->orderByHeader($header); Put these near the start. Not chainable, if you forget to return it to itself it will have odd results. http://druptest7.dev:8888/example_extend
    34. 34. What is the ?Now that you have Drupal DB ChopsYou may start to consider… To VIEWS or not to VIEWS
    35. 35. DB API an Alternative toViews Who will maintain the functionality? Does it require a lot of custom views code? Are you doing a lot of aggregated data work? Do you need a highly tuned SQL statement for performance? Do you need a lot of user facing, non programmer modifications, will site builders be cloning views or modifying displays? Are you integrating with other modules (panels, voting, etc)? How complex are the changes you need to views default queries/output? To views or not to views (http://drupal.org/node/242311 )
    36. 36. Quick case study:• Client wanted private comments• Client wanted to see a listing of all comments made against all nodes• Views can do this but it is described as “hacky”• Created a db_select with pager and table extenders
    37. 37. Questions and Thank you!David Diers, DeveloperFour Kitchensdavid.diers@fourkitchens.comD.O - thebruce@beautyhammer