Date post: | 18-Dec-2014 |
Category: |
Technology |
Upload: | ddiers |
View: | 3,057 times |
Download: | 0 times |
Drupal II: The SQL
David Diers, DeveloperFour KitchensAustin, TX
D.O - thebruce@beautyhammer
What we’ll cover
Basics of the Drupal DB APIUsing db_queryUsing and building dynamic queries including
Criteria clauses, joins, sorting, sub-selects, extenders, and tagging
How to work with result sets
Drupal and the DBDrupal uses the DB to:
Store content - where "content" is thought of very broadly.Store user or module configurations Store system values
Drupal retrieves these values all of the time.
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
Drupal 7 DB API uses PDO
In D7 the DB Abstraction layer got a face-liftBuilt on PDO
PDO is PHPOOPDrupal extends PDO classesPDO used in many projects
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 ™?
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?
Using the DB API
2 Primary ways to interact with data in D7dbquery – performant, limited transferability.Dynamic queries - more complex, high transferability, powerful, less performant.
db_query – the basics
IN SQL:
SELECT nid, titleFROM nodeWHERE type = ‘article’;
IN db_query: <?php$type = ‘article’;$result = db_query("SELECT nid, title FROM {node} WHERE type = :type", array(':type' => $type,));
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
db_query d6 => d7 transitions
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.
Dynamic sql – the basics
Dynamic QueriesMuch more transportable.You MUST use for ( INSERT, UPDATE, DELETE)You may use for (SELECT) • http://www.lullabot.com/articles/simplify-your-c
ode-with-drupal-7s-database-api ).
db_select – the basics
IN SQL:
SELECT nid, titleFROM nodeWHERE type = ‘article’;
IN db_select: <?php$type = ‘article’;$query = db_select(‘node’, ’n’);$result = $query->fields(‘n’, array(‘nid’,’title’) ->condition(‘n.type’,$type) ->execute();
db_select – the basics
(‘node’, ‘n’) Name of Table / Alias
(fields(‘n’, array(‘nid’, ‘title’))
Alias, array of fields
Single quotes are important for transferability.
IN db_select: <?php$type = ‘article’;$query = db_select(‘node’, ’n’);$result = $query->fields(‘n’, array(‘nid’,’title’) ->condition(‘n.type’,$type) ->execute();
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 chainingQuery statements are executed by ->execute(); easy to forget, but don't.You’ll get back a result set / statement object
Working with Result Sets
Use - foreach loop oror - 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);
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 queriesDo you need to INSERT, UPDATE, or DELETE? Use Dynamic queries.Are you querying the node table – Use Dynamic queries to respect node access.
More with Dynamic Queries
How to add fields or select *Conditional StatementsAND / OR Sub-selectsJOINSSORT
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
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');
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');
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);
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();
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');
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');?>
dynamic queries: sorting
orderBy(‘field’, ‘ASC’/’DESC’)
$result = db_select(‘node’, ‘n’) ->fields(‘n’, array(‘title’)) ->orderBy(‘n.created’, ‘DESC’) ->execute();
db_select Tagging
Tagging – lets alter hooks take action
ex: $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.
(http://druptest7.dev:8888/example_tag)
What about the others?
db_update, db_insert, db_deleteSimilar syntaxAssemble and execute.
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)
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
db_delete
Signature: $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
db_select extendersExtenders - 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
TIME FOR BONUS ROUND
YUB NUB
What is the ?Now that you have Drupal DB Chops You may start to consider…
To VIEWS ornot toVIEWS
DB API an Alternative to Views
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 )
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