Imaginemos que queremos leer información de una base de datos externa en Drupal 7. Para ello vamos a crear un módulo. El tutorial cubrirá el proceso completo desde la instalación de Drupal.
Consideraciones iniciales
Todo el ejemplo se hará en entorno MAMP versión 2.2 sobre OS X.
Apache:
La carpeta de trabajo será el htdocs de Apache en el path: /Applications/MAMP/htdocs
Apache estará corriendo en puerto 80
La versión de PHP utilizada es PHP 5.5.3
(¡con todas las caches -tipo APC- desactivadas!)
Base de datos:
Elegiremos MySQL
, que escuchará en el puerto 3306
El usuario con que conectaremos a MySQL será root
y su password será root
(recuerda no hacer esto NUNCA en un entorno de producción). La base de datos que usaremos para la prueba se llamará drupal
y el usuario root
tendrá todos los permisos sobre ella.
Variables de entorno
Vamos a añadir al $PATH
el path donde tenemos los binarios de MySQL (por defecto en /Applications/MAMP/Library/bin
) para poder realizar llamadas a los binarios desde línea de comandos de forma más cómoda. Lo podemos hacer mediante la orden:
miguelm$ export PATH=$PATH:/Applications/MAMP/Library/bin |
miguelm$ export PATH=$PATH:/Applications/MAMP/Library/bin
Drupal:
La realease empleada será Drupal 7.21
Paso 1: Instalación de Drupal
– Descomprimir el zip en /Applications/MAMP/htdocs
– Crear la nueva base de datos para Drupal:
miguelm$ mysqladmin -u root -p create drupal
Enter password: |
miguelm$ mysqladmin -u root -p create drupal
Enter password:
– Entrar a MySQL:
miguelm$ mysql -u root -p |
miguelm$ mysql -u root -p
– Dar permisos al usuario root para usar esa BD:
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER
-> ON drupal.*
-> TO 'root'@'localhost' IDENTIFIED BY 'root';
Query OK, 0 rows affected (0,06 sec) |
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER
-> ON drupal.*
-> TO 'root'@'localhost' IDENTIFIED BY 'root';
Query OK, 0 rows affected (0,06 sec)
– Configurar Drupal para la instalación.
Primero nos movemos al directorio donde hemos descomprimido el zip de Drupal…
miguelm$ cd /Applications/MAMP/htdocs/ |
miguelm$ cd /Applications/MAMP/htdocs/
Y editar el fichero settings.php
para decirle cómo se llama nuestra base de datos, nuestro usuario y demás…
miguelm$ vim ./sites/default/settings.php |
miguelm$ vim ./sites/default/settings.php
La configuración de las bases de datos tiene que quedar asi:
$databases = array (
'default' =>
array (
'default' =>
array (
'database' => 'drupal',
'username' => 'root',
'password' => 'root',
'host' => 'localhost',
'port' => '3306',
'driver' => 'mysql',
'prefix' => '',
),
),
); |
$databases = array (
'default' =>
array (
'default' =>
array (
'database' => 'drupal',
'username' => 'root',
'password' => 'root',
'host' => 'localhost',
'port' => '3306',
'driver' => 'mysql',
'prefix' => '',
),
),
);
En entornos de desarrollo también es muy interesante incluir estas líneas en el archivo settings.php, para que se muestren en web los errores de PHP:
<?php
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE); |
<?php
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
El siguiente paso es instalar Drupal. Para ello, abrimos el navegador y (teniendo Apache levantado) procedemos a ejecutar install.php
visitando la URL: http://localhost/install.php

Haremos una instalación estándar en idioma inglés. El instalador debe terminar y veremos esta pantalla.

Entonces nos loggeamos en nuestro recién creado site visitando la URL: http://localhost/?q=user
y rellenando el username y pwd con los valores elegidos (por ejemplo, admin
/admin
)
Paso 2: Creación de base de datos externa
Ya tenemos Drupal instalado. Vamos ahora a crear una base de datos de prueba con una única tabla muy sencilla, que almacene por ejemplo una relación de títulos de libros.
Creamos la nueva bd, a la que llamaremos externaldatabase
.
miguelm$ mysqladmin -u root -p create externaldatabase |
miguelm$ mysqladmin -u root -p create externaldatabase
A continuación entramos en MySQL para asignar privilegios (lo haremos con el usuario root
, aunque recordemos que en entornos de producción elegiríamos otro user para esta bd)
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER on externaldatabase.* TO 'root'@'localhost' IDENTIFIED BY 'root';
Query OK, 0 rows affected (0,02 sec) |
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER on externaldatabase.* TO 'root'@'localhost' IDENTIFIED BY 'root';
Query OK, 0 rows affected (0,02 sec)
Y creamos nuestra tabla con datos de libros:
mysql> USE externaldatabase;
Database changed
mysql> CREATE TABLE libros (id INT, titulo VARCHAR(200));
Query OK, 0 rows affected (0,04 sec) |
mysql> USE externaldatabase;
Database changed
mysql> CREATE TABLE libros (id INT, titulo VARCHAR(200));
Query OK, 0 rows affected (0,04 sec)
Insertamos un par de datos de prueba:
mysql> INSERT into libros (id, titulo) VALUES (1,"El Quijote");
Query OK, 1 row affected (0,03 sec) |
mysql> INSERT into libros (id, titulo) VALUES (1,"El Quijote");
Query OK, 1 row affected (0,03 sec)
Paso 3: Nuevo módulo en Drupal 7:
Los módulos en Drupal están (normalmente) en /sites/all/modules
Vamos a crear una nueva carpeta en ese path que se llamará bdexterna
.
miguelm$ pwd
/Applications/MAMP/htdocs
miguelm$ cd sites/all/modules/
miguelm$ mkdir bdexterna |
miguelm$ pwd
/Applications/MAMP/htdocs
miguelm$ cd sites/all/modules/
miguelm$ mkdir bdexterna
Un módulo se compone de dos archivos: un archivo con extensión .info
(definición del módulo) y un archivo con extensión .module
(que contiene la lógica -programación PHP-).
Vamos a crear nuestro archivo externaldbtest.info
dentro de la carpeta externaldbtest
:
miguelm$ cd bdexterna
miguelm$ vim bdexterna.info |
miguelm$ cd bdexterna
miguelm$ vim bdexterna.info
El contenido de externaldbtest/externaldbtest.info
será:
name = BD Externa
description = "Modulo para consultar BD externa"
package = Aprendiendo Drupal7 en leccionespracticas.com
core = 7.x
También creamos el archivo bdexterna.module
que, de momento, dejamos vacío…:
miguelm$ touch bdexterna.module
Esto quiere decir que el módulo se llamará BD Externa, que se ubicará en la categoría de módulos “Aprendiendo Drupal7”, es compatible con Drupal 7.x y también describimos para qué sirve.
Una vez creados estos archivo podemos ir a http://localhost/?q=user/1#overlay=%3Fq%3Dadmin%252Fmodules en nuestro navegador y veremos que se ha creado una nueva categoría llamada “Aprendiendo Drupal7 en leccionespracticas.com” que contiene el módulo “BD Externa” (y se nos permite activarlo):

Antes de lanzarnos a hacer queries a nuestra base de datos externa, debemos entender cómo funcionan los módulos de Drupal. Y para ello nada mejor que empezar con un “Hola Mundo!”. Vamos a generar un bdexterna.module
de tal forma que al visitar la url http://localhost/?q=libros/listar
nos diga “Hola mundo”.
Para programar la respuesta a una determinada URL (/libros/listar
) debemos usar la función hook_menu(). Al visitar una URL, Drupal comprueba si alguno de nuestros módulos tiene programado una función nombremodulo_menu()
para esta dirección.
Vamos a empezar, por tanto, creando esta función.
saludar/saludar.module
<?php
/**
* @file
* Nuestro primer módulo en Drupal (leccionespracticas.com)
*/
/**
* Implementa hook_menu().
*/
function bdexterna_menu() {
$items['libros/listar'] = array(
'title' => 'LISTAR LIBROS',
'page callback' => 'bdexterna_libros_listar',
'access callback' => TRUE,
);
// con lo anterior indicamos que cuando se visite la url libros/listar
// se muestre una página con título 'LISTAR LIBROS' cuya salida será el
// resultado de ejecutar la funcion 'bdexterna_libros_listar', que deberemos definir...
return $items;
}
?> |
<?php
/**
* @file
* Nuestro primer módulo en Drupal (leccionespracticas.com)
*/
/**
* Implementa hook_menu().
*/
function bdexterna_menu() {
$items['libros/listar'] = array(
'title' => 'LISTAR LIBROS',
'page callback' => 'bdexterna_libros_listar',
'access callback' => TRUE,
);
// con lo anterior indicamos que cuando se visite la url libros/listar
// se muestre una página con título 'LISTAR LIBROS' cuya salida será el
// resultado de ejecutar la funcion 'bdexterna_libros_listar', que deberemos definir...
return $items;
}
?>
Y además deberemos crear la función de callback que hemos dicho que debía ejecutarse al visitar esta url, que será muy simple porque solo queremos mostrar un “Hola Mundo!”. Recordamos que el nombre que debemos darle a esta función es el que indicamos en el parámetro page_callback
, osea bdexterna_libros_listar
.
/**
* Callback para libros/listar.
*/
function bdexterna_libros_listar() {
return "Hola Mundo";
} |
/**
* Callback para libros/listar.
*/
function bdexterna_libros_listar() {
return "Hola Mundo";
}
La primera versión completa de nuestro archivo bdexterna.module
será, por tanto, asi:
<?php
/**
* @file
* Nuestro primer módulo en Drupal (leccionespracticas.com)
*/
/**
* Implementa hook_menu().
*/
function bdexterna_menu() {
$items['libros/listar'] = array(
'title' => 'LISTAR LIBROS',
'page callback' => 'bdexterna_libros_listar',
'access callback' => TRUE,
);
// con lo anterior indicamos que cuando se visite la url libros/listar
// se muestre una página con título 'LISTAR LIBROS' cuya salida será el
// resultado de ejecutar la funcion 'bdexterna_listar_libros', que
// deberemos definir
// el parámetro access callback indica quién puede acceder al callback:
// en este caso, al tener el valor TRUE, todos pueden acceder.
return $items;
}
/**
* Callback para URL libros/listar
*/
function bdexterna_libros_listar() {
return "Hola Mundo";
} |
<?php
/**
* @file
* Nuestro primer módulo en Drupal (leccionespracticas.com)
*/
/**
* Implementa hook_menu().
*/
function bdexterna_menu() {
$items['libros/listar'] = array(
'title' => 'LISTAR LIBROS',
'page callback' => 'bdexterna_libros_listar',
'access callback' => TRUE,
);
// con lo anterior indicamos que cuando se visite la url libros/listar
// se muestre una página con título 'LISTAR LIBROS' cuya salida será el
// resultado de ejecutar la funcion 'bdexterna_listar_libros', que
// deberemos definir
// el parámetro access callback indica quién puede acceder al callback:
// en este caso, al tener el valor TRUE, todos pueden acceder.
return $items;
}
/**
* Callback para URL libros/listar
*/
function bdexterna_libros_listar() {
return "Hola Mundo";
}
Solo nos queda activar el módulo, vaciar las caches de Drupal (URL http://localhost/?q=admin/config/development/performance
) y visitar la URL elegida (http://localhost/?q=libros/listar
). Comprobamos que se ve el “Hola Mundo”.

Función (callback) para consulta a base de datos
Ahora que hemos entendido cómo funcionan los hooks y hemos construído un módulo básico, podemos lanzarnos a conseguir nuestro objetivo: listar los libros.
Para ello modificaremos la función de callback que habíamos definido en el archivo bdexterna.module (llamada bdexterna_libros_listar
) y añadiremos el código necesario para realizar la consulta a la BD externa de libros.
Lo primero que debemos hacer es definir la nueva base de datos externa en Drupal. Como vimos en el post anterior, podemos hacerlo de dos formas. En este caso y puesto que solo usaré esta base de datos desde este módulo, optaré por definir la base de datos directamente en el propio módulo.
El código es bastante sencillo y self-explaining:
/**
* Callback para libros/listar.
*/
function bdexterna_libros_listar() {
// Definimos la base de datos externa...
$bd_libros = array(
'database' => 'externaldatabase', // nombre de la BD externa
'username' => 'root', // usuario para acceder a la BD externa
'password' => 'root', // password del usuario
'host' => 'localhost', // host donde se encuentra la BD
'driver' => 'mysql', // tipo de BD
); |
/**
* Callback para libros/listar.
*/
function bdexterna_libros_listar() {
// Definimos la base de datos externa...
$bd_libros = array(
'database' => 'externaldatabase', // nombre de la BD externa
'username' => 'root', // usuario para acceder a la BD externa
'password' => 'root', // password del usuario
'host' => 'localhost', // host donde se encuentra la BD
'driver' => 'mysql', // tipo de BD
);
A continuación introducimos el código para limpiar las caches. Este paso es vital. De no hacerlo, podríamos encontrarnos con que Drupal intenta acceder a tablas de la nueva base de datos que no existen (semaphore, session, etc etc) y nos encontraríamos con errores del tipo:
Uncaught exception thrown in shutdown function.
PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'externaldatabase.semaphore' doesn't exist: ... |
Uncaught exception thrown in shutdown function.
PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'externaldatabase.semaphore' doesn't exist: ...
Y si no me creéis, mirad:

El código que limpia las caches es el siguiente (lo he cogido prestado de aqui).
$core = array('cache', 'cache_path', 'cache_filter', 'cache_bootstrap', 'cache_page');
$cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
foreach ($cache_tables as $table) {
cache_clear_all('*', $table, TRUE);
} |
$core = array('cache', 'cache_path', 'cache_filter', 'cache_bootstrap', 'cache_page');
$cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
foreach ($cache_tables as $table) {
cache_clear_all('*', $table, TRUE);
}
A continuación añadimos la BD definida anteriormente y la marcamos como BD activa:
Database::addConnectionInfo('externaldatabase', 'default', $bd_libros);
// 'MisLibros' es una clave única de la BD en este módulo, default es el target y $other_database el vector que contiene la información de conexión
db_set_active('externaldatabase');
// marcamos la bd activa como la externa... |
Database::addConnectionInfo('externaldatabase', 'default', $bd_libros);
// 'MisLibros' es una clave única de la BD en este módulo, default es el target y $other_database el vector que contiene la información de conexión
db_set_active('externaldatabase');
// marcamos la bd activa como la externa...
Y podemos empezar a construir queries y mostrar resultados…
// y empezamos a construir la query..
$sql = "SELECT * from libros";
//print "Vamos a ejecutar la consulta '".$sql."'...<br />";
// lanzamos la ejecución de la query y guardamos en $result todos los resultados...
$results = db_query($sql);
// mostramos los resultados...
foreach($results as $res){
print_r($res);
} |
// y empezamos a construir la query..
$sql = "SELECT * from libros";
//print "Vamos a ejecutar la consulta '".$sql."'...<br />";
// lanzamos la ejecución de la query y guardamos en $result todos los resultados...
$results = db_query($sql);
// mostramos los resultados...
foreach($results as $res){
print_r($res);
}
Y lo único que restaría sería restaurar la BD por defecto:
// restaurar la BD activa a la Bd de Drupal...
db_set_active(); |
// restaurar la BD activa a la Bd de Drupal...
db_set_active();
El fichero bdexterna.module completo quedaría asi:
bdexterna.module
<?php
/**
* @file
* Nuestro primer módulo en Drupal (leccionespracticas.com)
*/
/**
* Implementa hook_menu().
*/
function bdexterna_menu() {
$items['libros/listar'] = array(
'title' => 'LISTAR LIBROS',
'page callback' => 'bdexterna_libros_listar',
'access callback' => TRUE,
);
// con lo anterior indicamos que cuando se visite la url libros/listar
// se muestre una página con título 'LISTAR LIBROS' cuya salida será el
// resultado de ejecutar la funcion 'bdexterna_listar_libros', que deberemos definir
return $items;
}
function bdexterna_clear_cache() {
$core = array('cache', 'cache_path', 'cache_filter', 'cache_bootstrap', 'cache_page');
$cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
foreach ($cache_tables as $table) {
cache_clear_all('*', $table, TRUE);
}
}
/**
* Callback para libros/listar.
*/
function bdexterna_libros_listar() {
bdexterna_clear_cache();
db_set_active();
// Definimos la base de datos externa...
$bd_libros = array(
'database' => 'externaldatabase', // nombre de la BD externa
'username' => 'root', // usuario para acceder a la BD externa
'password' => 'root', // password del usuario
'host' => 'localhost', // host donde se encuentra la BD
'driver' => 'mysql', // tipo de BD
);
Database::addConnectionInfo('externaldatabase', 'default', $bd_libros);
// 'MisLibros' es una clave única de la BD en este módulo, default es el target y $other_database el vector que contiene la información de conexión
db_set_active('externaldatabase');
// marcamos la bd activa como la externa...
// y empezamos a construir la query..
$sql = "SELECT * from libros";
// lanzamos la ejecución de la query y guardamos en $result todos los resultados...
$results = db_query($sql);
// mostramos los resultados...
foreach($results as $res){
print_r($res);
}
// restaurar la BD activa a la Bd de Drupal...
db_set_active();
//informar del final del proceso
drupal_set_message(t('The queries have been made.'));
}
?> |
<?php
/**
* @file
* Nuestro primer módulo en Drupal (leccionespracticas.com)
*/
/**
* Implementa hook_menu().
*/
function bdexterna_menu() {
$items['libros/listar'] = array(
'title' => 'LISTAR LIBROS',
'page callback' => 'bdexterna_libros_listar',
'access callback' => TRUE,
);
// con lo anterior indicamos que cuando se visite la url libros/listar
// se muestre una página con título 'LISTAR LIBROS' cuya salida será el
// resultado de ejecutar la funcion 'bdexterna_listar_libros', que deberemos definir
return $items;
}
function bdexterna_clear_cache() {
$core = array('cache', 'cache_path', 'cache_filter', 'cache_bootstrap', 'cache_page');
$cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
foreach ($cache_tables as $table) {
cache_clear_all('*', $table, TRUE);
}
}
/**
* Callback para libros/listar.
*/
function bdexterna_libros_listar() {
bdexterna_clear_cache();
db_set_active();
// Definimos la base de datos externa...
$bd_libros = array(
'database' => 'externaldatabase', // nombre de la BD externa
'username' => 'root', // usuario para acceder a la BD externa
'password' => 'root', // password del usuario
'host' => 'localhost', // host donde se encuentra la BD
'driver' => 'mysql', // tipo de BD
);
Database::addConnectionInfo('externaldatabase', 'default', $bd_libros);
// 'MisLibros' es una clave única de la BD en este módulo, default es el target y $other_database el vector que contiene la información de conexión
db_set_active('externaldatabase');
// marcamos la bd activa como la externa...
// y empezamos a construir la query..
$sql = "SELECT * from libros";
// lanzamos la ejecución de la query y guardamos en $result todos los resultados...
$results = db_query($sql);
// mostramos los resultados...
foreach($results as $res){
print_r($res);
}
// restaurar la BD activa a la Bd de Drupal...
db_set_active();
//informar del final del proceso
drupal_set_message(t('The queries have been made.'));
}
?>
Y el resultado:

Nótese que el resultado sale “feo” porque hacemos print’s desde el módulo. Lo que deberíamos hacer es RETURN’s de HTML (ver el siguiente punto).
El código final del módulo
He comprobado que algunas cosas de las enunciadas en apartados anteriores no son del todo ciertas. Por ejemplo, no es necesario el tema de vaciar las caches. También es interesante capturar en bloques try/except algunas cosas. Y por supuesto, no realizar presentación desde la capa de lógica (es decir, devolver cadenas HTML, no hacer prints desde el módulo…)
Esta versión del código contempla estas modificaciones.
bdexterna.info
:
name = BD Externa
description = "Modulo para consultar BD externa"
package = Aprendiendo Drupal7 en leccionespracticas.com
core = 7.x |
name = BD Externa
description = "Modulo para consultar BD externa"
package = Aprendiendo Drupal7 en leccionespracticas.com
core = 7.x
bdexterna.module
:
<?php
/**
* @file
* Nuestro primer módulo en Drupal (leccionespracticas.com)
*/
/**
* Implementa hook_menu().
*/
function bdexterna_menu() {
$items['libros/listar'] = array(
'title' => 'LISTAR LIBROS',
'page callback' => 'bdexterna_libros_listar',
'access callback' => TRUE,
);
// con lo anterior indicamos que cuando se visite la url libros/listar
// se muestre una página con título 'LISTAR LIBROS' cuya salida será el
// resultado de ejecutar la funcion 'bdexterna_listar_libros', que deberemos definir
return $items;
}
/**
* Callback para libros/listar.
*/
function bdexterna_libros_listar() {
$bd_libros = array(
'database' => 'externaldatabase', // nombre de la BD externa
'username' => 'root', // usuario para acceder a la BD externa
'password' => 'root', // password del usuario
'host' => 'localhost', // host donde se encuentra la BD
'driver' => 'mysql', // tipo de BD
);
try{
Database::addConnectionInfo('externaldatabase', 'default', $bd_libros);
db_set_active('externaldatabase');
}
catch (Exception $e){
db_set_active();
return "se produjo un error al marcar la BD activa: ".$e;
}
$sql = "SELECT * from libros";
$results = db_query($sql);
$salida = "";
foreach($results as $res){
$salida = $salida."[ID] =".$res->id." [TITULO] = ".$res->titulo;
}
db_set_active();
return $salida;
}
?> |
<?php
/**
* @file
* Nuestro primer módulo en Drupal (leccionespracticas.com)
*/
/**
* Implementa hook_menu().
*/
function bdexterna_menu() {
$items['libros/listar'] = array(
'title' => 'LISTAR LIBROS',
'page callback' => 'bdexterna_libros_listar',
'access callback' => TRUE,
);
// con lo anterior indicamos que cuando se visite la url libros/listar
// se muestre una página con título 'LISTAR LIBROS' cuya salida será el
// resultado de ejecutar la funcion 'bdexterna_listar_libros', que deberemos definir
return $items;
}
/**
* Callback para libros/listar.
*/
function bdexterna_libros_listar() {
$bd_libros = array(
'database' => 'externaldatabase', // nombre de la BD externa
'username' => 'root', // usuario para acceder a la BD externa
'password' => 'root', // password del usuario
'host' => 'localhost', // host donde se encuentra la BD
'driver' => 'mysql', // tipo de BD
);
try{
Database::addConnectionInfo('externaldatabase', 'default', $bd_libros);
db_set_active('externaldatabase');
}
catch (Exception $e){
db_set_active();
return "se produjo un error al marcar la BD activa: ".$e;
}
$sql = "SELECT * from libros";
$results = db_query($sql);
$salida = "";
foreach($results as $res){
$salida = $salida."[ID] =".$res->id." [TITULO] = ".$res->titulo;
}
db_set_active();
return $salida;
}
?>
Y la salida que conseguiremos:
