Para entender bien esta entrega será necesario tener conocimientos avanzados de uso de arrays en PHP.
Como explicar el hook_schema requiere de un modelo de datos en concreto vamos a apoyarnos sobre el módulo User, que forma parte del nucleo de Drupal.
Abrimos el fichero «modules/user/user.install» desde Aptana para ver su contenido, pulsando doble clic sobre él. Y nos encontramos con el siguiente código en la función user_schema():
/**
 * Implements hook_schema().
 */
function user_schema() {
  $schema[‘authmap’] = array(
    ‘description’ => ‘Stores distributed authentication mapping.’,
    ‘fields’ => array(
      ‘aid’ => array(
        ‘description’ => ‘Primary Key: Unique authmap ID.’,
        ‘type’ => ‘serial’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
      ),
      ‘uid’ => array(
        ‘type’ => ‘int’,
        ‘not null’ => TRUE,
        ‘default’ => 0,
        ‘description’ => «User’s {users}.uid.»,
      ),
      ‘authname’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 128,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => ‘Unique authentication name.’,
      ),
      ‘module’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 128,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => ‘Module which is controlling the authentication.’,
      ),
    ),
    ‘unique keys’ => array(
      ‘authname’ => array(‘authname’),
    ),
    ‘primary key’ => array(‘aid’),
    ‘foreign keys’ => array(
      ‘user’ => array(
        ‘table’ => ‘users’,
        ‘columns’ => array(‘uid’ => ‘uid’),
      ),
    ),
  );

  $schema[‘role_permission’] = array(
    ‘description’ => ‘Stores the permissions assigned to user roles.’,
    ‘fields’ => array(
      ‘rid’ => array(
        ‘type’ => ‘int’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
        ‘description’ => ‘Foreign Key: {role}.rid.’,
      ),
      ‘permission’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 128,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => ‘A single permission granted to the role identified by rid.’,
      ),
      ‘module’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 255,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => «The module declaring the permission.»,
      ),
    ),
    ‘primary key’ => array(‘rid’, ‘permission’),
    ‘indexes’ => array(
      ‘permission’ => array(‘permission’),
    ),
    ‘foreign keys’ => array(
      ‘role’ => array(
        ‘table’ => ‘roles’,
        ‘columns’ => array(‘rid’ => ‘rid’),
      ),
    ),
  );

  $schema[‘role’] = array(
    ‘description’ => ‘Stores user roles.’,
    ‘fields’ => array(
      ‘rid’ => array(
        ‘type’ => ‘serial’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
        ‘description’ => ‘Primary Key: Unique role ID.’,
      ),
      ‘name’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 64,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => ‘Unique role name.’,
        ‘translatable’ => TRUE,
      ),
      ‘weight’ => array(
        ‘type’ => ‘int’,
        ‘not null’ => TRUE,
        ‘default’ => 0,
        ‘description’ => ‘The weight of this role in listings and the user interface.’,
      ),
    ),
    ‘unique keys’ => array(
      ‘name’ => array(‘name’),
    ),
    ‘primary key’ => array(‘rid’),
    ‘indexes’ => array(
      ‘name_weight’ => array(‘name’, ‘weight’),
    ),
  );

  $schema[‘users’] = array(
    ‘description’ => ‘Stores user data.’,
    ‘fields’ => array(
      ‘uid’ => array(
        ‘type’ => ‘int’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
        ‘description’ => ‘Primary Key: Unique user ID.’,
        ‘default’ => 0,
      ),
      ‘name’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 60,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => ‘Unique user name.’,
      ),
      ‘pass’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 128,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => «User’s password (hashed).»,
      ),
      ‘mail’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 254,
        ‘not null’ => FALSE,
        ‘default’ => »,
        ‘description’ => «User’s e-mail address.»,
      ),
      ‘theme’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 255,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => «User’s default theme.»,
      ),
      ‘signature’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 255,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => «User’s signature.»,
      ),
      ‘signature_format’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 255,
        ‘not null’ => FALSE,
        ‘description’ => ‘The {filter_format}.format of the signature.’,
      ),
      ‘created’ => array(
        ‘type’ => ‘int’,
        ‘not null’ => TRUE,
        ‘default’ => 0,
        ‘description’ => ‘Timestamp for when user was created.’,
      ),
      ‘access’ => array(
        ‘type’ => ‘int’,
        ‘not null’ => TRUE,
        ‘default’ => 0,
        ‘description’ => ‘Timestamp for previous time user accessed the site.’,
      ),
      ‘login’ => array(
        ‘type’ => ‘int’,
        ‘not null’ => TRUE,
        ‘default’ => 0,
        ‘description’ => «Timestamp for user’s last login.»,
      ),
      ‘status’ => array(
        ‘type’ => ‘int’,
        ‘not null’ => TRUE,
        ‘default’ => 0,
        ‘size’ => ‘tiny’,
        ‘description’ => ‘Whether the user is active(1) or blocked(0).’,
      ),
      ‘timezone’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 32,
        ‘not null’ => FALSE,
        ‘description’ => «User’s time zone.»,
      ),
      ‘language’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 12,
        ‘not null’ => TRUE,
        ‘default’ => »,
        ‘description’ => «User’s default language.»,
      ),
      ‘picture’ => array(
        ‘type’ => ‘int’,
        ‘not null’ => TRUE,
        ‘default’ => 0,
        ‘description’ => «Foreign key: {file_managed}.fid of user’s picture.»,
      ),
      ‘init’ => array(
        ‘type’ => ‘varchar’,
        ‘length’ => 254,
        ‘not null’ => FALSE,
        ‘default’ => »,
        ‘description’ => ‘E-mail address used for initial account creation.’,
      ),
      ‘data’ => array(
        ‘type’ => ‘blob’,
        ‘not null’ => FALSE,
        ‘size’ => ‘big’,
        ‘serialize’ => TRUE,
        ‘description’ => ‘A serialized array of name value pairs that are related to the user. Any form values posted during user edit are stored and are loaded into the $user object during user_load(). Use of this field is discouraged and it will likely disappear in a future version of Drupal.’,
      ),
    ),
    ‘indexes’ => array(
      ‘access’ => array(‘access’),
      ‘created’ => array(‘created’),
      ‘mail’ => array(‘mail’),
    ),
    ‘unique keys’ => array(
      ‘name’ => array(‘name’),
    ),
    ‘primary key’ => array(‘uid’),
    ‘foreign keys’ => array(
      ‘signature_format’ => array(
        ‘table’ => ‘filter_format’,
        ‘columns’ => array(‘signature_format’ => ‘format’),
      ),
    ),
  );

  $schema[‘users_roles’] = array(
    ‘description’ => ‘Maps users to roles.’,
    ‘fields’ => array(
      ‘uid’ => array(
        ‘type’ => ‘int’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
        ‘default’ => 0,
        ‘description’ => ‘Primary Key: {users}.uid for user.’,
      ),
      ‘rid’ => array(
        ‘type’ => ‘int’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
        ‘default’ => 0,
        ‘description’ => ‘Primary Key: {role}.rid for role.’,
      ),
    ),
    ‘primary key’ => array(‘uid’, ‘rid’),
    ‘indexes’ => array(
      ‘rid’ => array(‘rid’),
    ),
    ‘foreign keys’ => array(
      ‘user’ => array(
        ‘table’ => ‘users’,
        ‘columns’ => array(‘uid’ => ‘uid’),
      ),
      ‘role’ => array(
        ‘table’ => ‘roles’,
        ‘columns’ => array(‘rid’ => ‘rid’),
      ),
    ),
  );

  return $schema;
}

Como puede verse en el ejemplo, básicamente está utilizando una variable llamada «$schema» que al final de la función devuelve. Dicha variable es un array que contiene un índice por cada tabla que necesita generar.
Por ejemplo si queremos generar la tabla ‘users’, indicamos que sobre el array $schema metemos un nuevo elemento con el índice ‘users’ y como valor metemos otro array.
El primer elemento del array valor de la tabla ‘users’ será la descripción de la tabla, cuyo índice será ‘description’ y cuyo valor será una cadena de caracteres con la descripción de la tabla.
El segundo elemento tendrá como índice el nombre de ‘fields’ y contiene un array con las defniciones de los campos de la tabla.
Así tendremos un array $schema definido de esta manera:
$schema[‘users’] = array(
    ‘description’ => ‘Stores user data.’,
    ‘fields’ => array()
);
En dicho array de campos (‘fields’), vamos introducciendo cada campo como un elemento cuyo índice es el nombre del campo y su valor es otro array con los metadatos del campo que queremos meter en la tabla, como el caso del campo ‘uid’…
$schema[‘users’] = array(
    ‘description’ => ‘Stores user data.’,
    ‘fields’ => array(
      ‘uid’ => array(
        ‘type’ => ‘int’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
        ‘description’ => ‘Primary Key: Unique user ID.’,
        ‘default’ => 0,
      )
     )
);
En este caso, el campo uid, tiene los siguientes elementos definidos:

  • type: tipo de campo definido por drupal
  • unasigned: valor booleano que permite definir si el campo es con o sin signo. Sólo disponible para campos numéricos.
  • not_null: valor booleano que nos indica si es campo puede ser null o no
  • description: descripción del campo
  • default: valor por defecto del campo

Como puede verse dicha definición de campo es una estructuración en forma de array de las típias configuraciones que solemos hacer en la propia base de datos cuando creamos un campo nuevo.
De esta manera ñadiríamos todos los campos que queremos que tenga la tabla, como distintos elementos del valor del array ‘fields’.
A continuación seguramente será necesario indicar de todos los campos cual (o cuales) es la clave primaria, en el caso de la tabla de users el campo ‘uid’ es el campo de clave primaria de la tabla, por lo que tenemos que insertar un nuevo elemento en el array principal $schema[‘users’] llamado ‘primary_key’ cuyo valor es un array con el nombre de los campos que son clave primaria. Por lo que el código quedaría así:
$schema[‘users’] = array(
    ‘description’ => ‘Stores user data.’,
    ‘fields’ => array(
      ‘uid’ => array(
        ‘type’ => ‘int’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
        ‘description’ => ‘Primary Key: Unique user ID.’,
        ‘default’ => 0,
      )
     ),
    ‘primary key’ => array(‘uid’)
);
 En el caso de la tabla users, tambiñen necesita hacer uso de índices sobre campos, para ello introduce también dentro del array $schema[‘users’] un elemento cuyo índice es ‘indexes’ cuyo valor debería ser un array con el nombre del índice y su valor un array con los nombres de los campos que queremos introducir en el índice. Así quedaría el array de la siguiente manera…
$schema[‘users’] = array(
    ‘description’ => ‘Stores user data.’,
    ‘fields’ => array(
      ‘uid’ => array(
        ‘type’ => ‘int’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
        ‘description’ => ‘Primary Key: Unique user ID.’,
        ‘default’ => 0,
      )//aquí introduciríamos el resto de elementos para definir el resto de campos de la tabla
     ),
    ‘primary key’ => array(‘uid’) ,
    ‘indexes’ => array(
      ‘access’ => array(‘access’),
      ‘created’ => array(‘created’),
      ‘mail’ => array(‘mail’),
    )
);
En este ejemplo, define 3 índices, sobre los campos access, created y mail. Por otra parte podemos definir índices únicos sobre campos, para ello debemos introducir un elemento más con índice ‘unique keys’ cuyo valor es un array con los nombres del índice y el valor de ese elemento es otro array con los campos que pertenecen a dicho array, en el ejemplo…
$schema[‘users’] = array(
    ‘description’ => ‘Stores user data.’,
    ‘fields’ => array(
      ‘uid’ => array(
        ‘type’ => ‘int’,
        ‘unsigned’ => TRUE,
        ‘not null’ => TRUE,
        ‘description’ => ‘Primary Key: Unique user ID.’,
        ‘default’ => 0,
      )//aquí introduciríamos el resto de elementos para definir el resto de campos de la tabla

     ),
    ‘primary key’ => array(‘uid’) ,
    ‘indexes’ => array(
      ‘access’ => array(‘access’),
      ‘created’ => array(‘created’),
      ‘mail’ => array(‘mail’),
    ),
    ‘unique keys’ => array(
      ‘name’ => array(‘name’),
    )
);
En el ejemplo crea un índice único llamado ‘name’  sobre el campo ‘name’. Dejamos para otro momento el índice ‘foreing keys’ por que tendríamos que explicar el modelo entero de users.

Debemos pensar que Drupal utilizará este hook para crear las tablas necesarias en la base de datos para el módulo, pero seguiríamos necesitando modificar el hook_install para introducir los datos iniciales en las tablas definidas en el hook_schema, como en el ejemplo…
// Insert a row for the anonymous user.
  db_insert(‘users’)
    ->fields(array(
      ‘uid’ => 0,
      ‘name’ => »,
      ‘mail’ => »,
    ))
    ->execute();
  Debido que al realizar la desinstalación del módulo user no hay que realizar más acciones que el borrado de las tablas generadas con la definición del hook_schema, el módulo user no necesita un hook_uninstall().

Práctica

  1. Genera un nuevo módulo en base a unos requisitos de base de datos dados.
  2. Define el hook_schema definiendo el modelo de base de datos
  3. Define el hook_install para introducir los datos iniciales en las tablas
  4. Prueba a realizar la instalación e activación del módulo, comprueba si las tablas se han generado correctamente.
  5. prueba a desactivar y desinstalar el módulo y mira a ver si ha borrado correctamente las tablas en la BBDD.

Referencias

Licencia Creative Commons