Gestión del esquema

Se han examinado algunos de los nuevos enfoques disponibles para interactuar con los datos. Por supuesto, existen circunstancias específicas en las que puede ser necesario interactuar directamente con la base de datos.

El adaptador de la base de datos

El adaptador de la base de datos predeterminado de XF2 se basa en extensiones mysqli de MySQL y PHP. El adaptador de la base de datos configurado es accesible desde cualquier clase de XF usando lo siguiente:

$db = \XF::db();
                

El adaptador tiene varios métodos disponibles con los que ejecutará consultas de SQL para luego formatear el resultado en una matríz. Por ejemplo, para acceder a un solo registro de usuario:

$db = \XF::db();
$user = $db->fetchRow('SELECT * FROM xf_user WHERE user_id = ?', 1);
                

La variable $user contendrá una matríz con todos los valores de la primera fila encontrada en el resultado de la consulta. Para obtener un solo valor de esta consulta, como el nombre de usuario, hay que hacer los siguiente:

$username = $user['username'];
                

Advertencia

Las consultas escriben directamente en la base de datos y su paso al adaptador de la base de datos no es automáticamente "seguro". Constituye un riesgo de vulnerabilidad por inyección de SQL si la entrada del usuario no se desinfecta y pasa a la consulta sin estar preparada. El camino de hacer esto con propiedad es usar estamentos preparados, como en el ejemplo de arriba. Los parámetros están representados en la propia consulta usando el marcador de posición ?. Este marcador de posición se reemplaza con los valores del siguiente argumento tras haber sido limpiados apropiadamente. Si se tiene la necesidad de usar más de un solo parámetro, ésto debe pasarse al método de tipo Fetch (extraer) como una matríz. Caso de surgir necesidad, se puede limpiar o citar valores directamente usando $db->quote($value).

Puede encontrarse más información sobre estamentos preparados aquí.

También es posible hacer una consulta para un sólo valor de un registro. Por ejemplo:

$db = \XF::db();
$username = $db->fetchOne('SELECT username FROM xf_user WHERE user_id = ?', 1);
                

Si se tiene una consulta que necesita devolver varias filas, se puede usar también fetchAll:

$db = \XF::db();
$users = $db->fetchAll('SELECT * FROM xf_user LIMIT 10');
                

o fetchAllKeyed:

$db = \XF::db();
$users = $db->fetchAllKeyed(
    'SELECT * FROM xf_user LIMIT 10',
    'user_id'
);
                

Ambos métodos devolverán una matríz de matrices que representan a cada registro de usuario. La diferencia entre los métodos fetchAll y fetchAllKeyed es que la matríz devuelta tiene claves diferentes. Con fetchAll la matríz obtendrá sus claves con enteros numéricamente consecutivos. Con fetchAllKeyed la matríz obtendrá sus claves del nombre de los campos denominados en el segundo argumento.

Nota

Si se usa fetchAllKeyed hay que advertir que el segundo argumento es el campo al que va la clave de la matríz, pero el tercer argumento es donde se pasan los parámetros del(os) valor(es) para que coincida con el marcador de posición ?.

Existen otros métodos disponibles de extracción de datos incluyendo fetchAllColumn para recuperar de todas las filas devueltas los valores de columnas específicas en una matríz:

$db = \XF::db();
$usernames = $db->fetchAllColumn('SELECT username FROM xf_user LIMIT 10');
                

El ejemplo anterior devolverá una matríz de los 10 nombres de usuario encontrados de la consulta resultante.

Finalmente, es posible que no se quiera ni se necesite dato devuelto alguno, en cuyo caso puede hacerse una consulta plana:

$db = \XF::db();
$db->query('DELETE FROM xf_user WHERE user_id = ?', 1);
                

Gestionando el esquema

XF2 incluye nuevas vías de gestión del esquema de la base de datos que adopta un enfoque orientado a objetos para realizar ciertas operaciones de tabla. Veremos primero el tradicional alter usando el adaptador de base de datos como está arriba:

$db = \XF::db();
$db->query(" ALTER TABLE xf_alguna_tabla_existente ADD COLUMN nueva_columna INT(10) UNSIGNED NOT NULL DEFAULT 0, MODIFY COLUMN alguna_columna_existente varchar(250) NOT NULL DEFAULT '' ");
                

También se verá la típica consulta create table:

$db = \XF::db();
$sm = $db->getSchemaManager();
$defaultTableConfig = $schemaManager->getTableConfigSql();
$db->query(" CREATE TABLE xf_alguna_tabla ( algun_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, algun_nombre VARCHAR(50) NOT NULL, PRIMARY KEY (user_id) )  ");
                

El método preferido y alternativo de XF2 usa el nuevo objeto SchemaManager. Veremos ambas consultas, cómo las realiza el gestor del esquema, comenzando por alter:


$sm = \XF::db()->getSchemaManager();
$sm->alterTable('xf_some_existing_table', function(\XF\Db\Schema\Alter $table)
    {
        $table->addColumn('nueva_columna', 'int')->setDefault(0);
        $table->changeColumn('alguna_columna_existente')->length(250);
    }
);
                

Y la creación de tablas:


$sm = \XF::db()->getSchemaManager();
$sm->createTable('xf_alguna_tabla', 
    function(\XF\Db\Schema\Create $table)
    {
        $table->addColumn('algun_id', 'int')->autoIncrement();
        $table->addColumn('algun_nombre', 'varchar', 50);
    }
);
                

Ambos ejempos generan exáctamente la misma consulta, como sus contrapartes más directas arriba. Aunque notarse que algunas cosas no están (deliberadamente). Por ejemplo, ninguno de los ejemplos especifica para los campos int una logitud. Simplemente se ha omitido, MySQL los proveerá de forma predeterminada, que es 10 para enteros sin firma. Hablando de eso, tampoco se especifica que la columna algun_id está sin firmar. El uso de enteros sin firma en XF es, con mucho, el caso más común, ya que se agregan automáticamente. Si se precisare enteros negativos, se especificará con el método ->unsigned(false). Otra omisión es la falta de definición NOT NULL para todo. De nuevo, ésto se aplica automáticamente, aunque puede especificarse con ->nullable(true).

No puede quedar muy claro en el ejemplo anterior ya que al cambiar campos existentes se retiene automáticamente la definición del campo existente. Esto significa que, en lugar de tener que especificar la definición completa de la columna, incluyendo todos los elementos que realmente no cambian, puede especificarse una definición parcial sólo de las partes que cambian.

Existen otras inferencias automáticas con respecto a las claves primarias. Puede explícitamente definirse la clave primaria (o cualquier otro tipo de clave) si se quiere, aunque a menudo los campos auto incrementales se corresponderán generalmente con la clave primaria de la tabla. En el ejemplo crear tabla, el campo algun_id se asigna automáticamente como clave primaria de la tabla.

Finalmente, en el método crear tabla puede cambiarse fácilmente la correcta configuración del motor de almacenamiento de la tabla a otros tipos de motor, especificándolo (predeterminado InnoDB).