Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Apress.Pro.Drupal.7.Development.3rd.Edition.Dec.2010.pdf
Скачиваний:
63
Добавлен:
14.03.2016
Размер:
12.64 Mб
Скачать

C H A P T E R 5

■ ■ ■

Working with Databases

Drupal depends on a database to function correctly. Content, comments, taxonomy, menus, users, roles, permissions, and just about everything else are stored in a database and used by Drupal as the source of information required to render content on your site and control who has access to what. Inside Drupal, a lightweight database abstraction layer exists between your code and the database. This abstraction layer removes a vast majority of the complexities of interacting with a database, and it shields Drupal from the differences between database engines. In this chapter, you’ll learn about how the database abstraction layer works and how to use it. You’ll see how queries can be modified by modules. Then, you’ll look at how to connect to additional databases (such as a legacy database). Finally, you’ll examine how the queries necessary to create and update database tables can be included in your module’s .install file by using Drupal’s schema API.

Defining Database Parameters

Drupal knows which database to connect to and what username and password to issue when establishing the database connection by looking in the settings.php file for your site. This file typically lives at sites/example.com/settings.php or sites/default/settings.php. The code that defines the database connection looks like this:

$databases = array ( 'default' => array (

'default' => array (

'driver' => 'mysql', 'database' => 'databasename', 'username' => 'username', 'password' => 'password', 'host' => 'localhost', 'port' => '',

'prefix' => '',

),

),

);

89

Download from Wow! eBook <www.wowebook.com>

CHAPTER 5 WORKING WITH DATABASES

This example is for connecting to a MySQL database. PostgreSQL users would prefix the connection string with pgsql instead of mysql. Obviously, the database name, username, and password used here must be valid for your database. They are database credentials, not Drupal credentials, and they are established when you set up the database account using your database’s tools. Drupal’s installer asks for the username and password so that it can build the $databases array in your settings.php file.

If you are using sqlite as the database for your site, the setup is slightly simpler. The driver should be set to sqlite, and the database should be set to the path including the name of the database.

$databases['default']['default'] = array( 'driver' => 'sqlite',

'database' => '/path/to/databasefilename',

);

Understanding the Database Abstraction Layer

Working with a database abstraction API is something you will not fully appreciate until you try to live without one again. Have you ever had a project where you needed to change database systems and you spent days sifting through your code to change database-specific function calls and queries? With an abstraction layer, you no longer have to keep track of nuances in function names for different database systems, and as long as your queries are American National Standards Institute (ANSI) SQL–compliant, you will not need to write separate queries for different databases. For example, rather than calling mysql_query() or pg_query(), Drupal uses db_query(), which keeps the business logic databaseagnostic.

Drupal 7’s database abstraction layer is based on PHP’s Data Object (PDO) library and serves two main purposes. The first is to keep your code from being tied to any one database. The second is to sanitize user-submitted data placed into queries to prevent SQL injection attacks. This layer was built on the principle that writing SQL is more convenient than learning a new abstraction layer language.

Drupal also has a schema API, which allows you to describe your database schema (that is, which tables and fields you will be using) to Drupal in a general manner and have Drupal translate that into specifics for the database you are using. We’ll cover that in a bit when we talk about .install files.

Drupal determines the type of database to connect to by inspecting the $database array inside your settings.php file. For example, if $databases['default']['default']['driver'] is set to mysql, then Drupal will include includes/database.mysql.inc. If it is equal to pgsql, Drupal will include includes/ database.pgsql.inc, and if it is equal to sqlite, Drupal will include includes/database.sqlite.inc. This mechanism is shown in Figure 5-1.

If you use a database that is not yet supported, you can write your own driver by implementing the wrapper functions for your database. For more information, see “Writing Your Own Database Driver” at the end of this chapter.

90

CHAPTER 5 WORKING WITH DATABASES

Figure 5-1. Drupal determines which database file to include by examining $databases.

Connecting to the Database

Drupal automatically establishes a connection to the database as part of its normal bootstrap process, so you do not need to worry about doing that.

If you are working outside Drupal itself (for example, you’re writing a stand-alone PHP script or have existing PHP code outside of Drupal that needs access to Drupal’s database), you would use the following approach.

//Make Drupal PHP's current directory. chdir('/full/path/to/your/drupal/installation');

//Bootstrap Drupal up through the database phase. include_once('./includes/bootstrap.inc'); drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE);

91

CHAPTER 5 WORKING WITH DATABASES

// Now you can run queries using db_query(). $result = db_query('SELECT title FROM {node}');

...

Caution Drupal is often configured to have multiple folders in the sites directory so that the site can be moved from staging to production without changing database credentials. For example, you might have sites/staging. example.com/settings.php with database credentials for your testing database server and sites/www. example.com/settings.php with database credentials for your production database server. When establishing a database connection as shown in this section, Drupal will always use sites/default/settings.php, because there is no HTTP request involved.

Performing Simple Queries

Drupal’s db_query() function is used to execute a SELECT query to the active database connection. There are other functions for performing INSERTS, UPDATES, and DELETES, and I’ll cover those in a moment, but first let’s look at extracting information from the database.

There is some Drupal-specific syntax you need to know when it comes to writing SQL statements. First, table names are enclosed within curly brackets so that table names can be prefixed to give them unique names, if necessary. This convention allows users who are restricted by their hosting provider in the number of databases they can create to install Drupal within an existing database and avoid table name collisions by specifying a database prefix in their settings.php file. Here is an example of a simple query to retrieve the name of role 2:

$result = db_query('SELECT name FROM {role} WHERE rid = :rid', array(':rid' => 2));

Notice the use of :rid as a named placeholder. In Drupal, queries are always written using placeholders, with the actual value assigned as a key => value pair. The :rid placeholder will automatically be replaced with the value assigned to :rid in the array that is used to define all of the values assigned to placeholders in the query—in this case, 2. Additional placeholders mean additional parameters:

db_query('SELECT name FROM {role} WHERE rid > :rid AND rid < :max_rid', array(':rid' => 0, ':max_rid' => 3);

The preceding line will become the following when it is actually executed by the database:

SELECT name FROM role WHERE rid > 0 AND rid < 3

User-submitted data must always be passed in as separate parameters so the values can be sanitized to avoid SQL injection attacks.

The first parameter for db_query() is always the query itself. The remaining parameters are the dynamic values to validate and insert into the query string. The values are passed as an array of key => value pairs.

92

CHAPTER 5 WORKING WITH DATABASES

We should note that using this syntax will typecast TRUE, FALSE, and NULL to their decimal equivalents (0 or 1). In most cases, this should not cause problems.

Let’s look at some examples. In these examples, we’ll use a database table called joke that contains three fields: a node ID (integer), a version ID (integer), and a text field containing a punch line.

Let’s start with an easy query. Get all rows of all fields from the table named joke where the field vid has an integer value that is the same as the value of $node->vid:

db_query('SELECT * FROM {joke} WHERE vid = :vid', array(':vid' => $node->vid));

Next let’s insert a new row into the joke table using the db_insert function. We’ll define the fields to insert using ->fields and an array of key => value pairs where the key is the name of the field and value is what will be assigned to that field in that row. Also note ->execute() at the end of the statement, which does just what it sounds like, executes the insert against the database.

$nid = db_insert('joke') ->fields(array(

'nid' => '4', 'vid' => 1,

'punchline' => 'And the pig said oink!',

))

->execute();

Next let’s update all of the rows in the joke table, setting the punchline equal to “Take my wife, please!”, where the nid is greater than or equal to 3. I’ll pass an array of fields and values to update using ->fields, and I’ll set the condition that has to be met in order to update the values for those fields using the ->condition modifier. In this example, I am going to update the punchline field for any record in the joke table where the nid field is greater than or equal to 3.

$num_updated = db_update('joke') ->fields(array(

'punchline' => 'Take my wife please!',

))

->condition('nid', 3, '>=') ->execute();

If I wanted to see how many rows were affected by the update, I could use the value assigned to $num_updated after the update is executed.

Finally let’s delete all of the rows from the joke table where the punchline is equal to “Take my wife please!” I’ll use the db_delete function and the ->condition modifier to specify the condition for deleting records from the table.

$num_deleted = db_delete('joke')

->condition('punchline', 'Take my wife please!') ->execute();

93

3

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]