The online documentation is produced by a web publishing technology created by us to read the documents origins in OpenOffice Writer (ODT) and Microsoft Word (docx) formats and produces native web and PDF versions. In this way we maintain Louder project documentation update and in sync on each of its formats.
Kumbia Enterprise Framework implementa una doble capa de abstracción para la manipulación de la persistencia de la aplicación cuando se utilizan bases de datos. El componente Db administra todo lo relacionado con la interacción a bajo nivel con los gestores relacionales de base de datos, esto incluye abstraer detalles de conexión, utilización de lenguaje SQL, cursores, transacciones, etc.
Esta independencia se logra mediante la implementación de adaptadores que crean puntos de compatibilidad a los motores de bases de datos de tal forma que sin importar el gestor utilizado se garantice que las operaciones sobre ellos va a ser consistente logrando el resultado esperado.
Mientras que el Kumbia PHP Framework ofrece múltiples opciones para conectarse a bases de datos, Kumbia Enterprise Framework recomienda su uso en producción a los adaptadores de MySQL y Oracle, aunque algunos otros tienen una madurez aceptable.
Capas de acceso
El componente Db puede utilizar multiples capas de abstracción existentes para el acceso a gestores relacionales, de esta forma se aumentan las posibilidades y capacidades de aprovechar la funcionalidad del motor desde una aplicación.
Las capas de acceso soportadas son las siguientes:
Tabla: Capas de acceso a gestores relacionales soportadas por Kumbia Enterprise
Nombre
Descripción
Native
Sin capa intermedia. Utiliza las extensiones PHP escritas en lenguaje C que implementan acceso directo a los motores de base de datos.
PDO
Utiliza la capa PHP Data Objects (PDO) escrita en lenguaje C que implementa acceso uniforme a los principales motores de base de datos de código abierto y cerrado.
JDBC
Utiliza la capa de acceso a bases de datos Java Database Connectivity (JDBC) de Java. Con lo que es possible utilizar drivers JDBC y la funcionalidad de estos. Solo disponible cuando se usa IBM WebSphere sMash.
Adaptadores del componente Db
En la siguiente tabla se detalla los adaptadores de la distribución de Kumbia Enterprise Framework junto con sus características y estado de madurez:
Tabla: Adaptadores del componente Db y madurez actual
Nombre
Capa de Acceso
Tipo
Estado de Madurez
MySQL
Nativo (MySQL)
SQL
Estable
MySQLi
Nativo (MySQLi)
SQL
Estable
Oracle
Nativo (oci8)
SQL
Estable
PostgreSQL
Nativo
Beta
Microsoft SQL Server
PDO
Estable
IBM Informix
PDO
Estable
SQLite
PDO
Estable
Oracle
PDO
Estable
Oracle
JDBC
Estable
Firebird/Interbase
Nativo
SQL
Beta
Firebird/Interbase
PDO
SQL
Beta
MongoDB
Nativo
NoSQL
Beta
Apache Cassandra
Nativo/PHP
NoSQL
Beta
Sybase
Nativo
SQL
Beta
Cada adaptador nativo hereda de la clase DbBase la cual implementa métodos utiles validos para cualquier gestor relacional en forma de capa de abstracción intermedia. La interface DbBaseInterface es implementada por cada adaptador de tal forma que cada uno mantenga una estructura consistente que permita efectuar operaciones básicas y avanzadas sin incurrir en detalles de bajo nivel ó dependientes de cada gestor relacional.
La estructura de la interface DbBaseInterface es la siguiente:
<?php
interface DbBaseInterface {
public function __construct($descriptor='');
public function connect($descriptor='');
public function query($sqlStatement);
public function fetchArray($resultQuery='', $opt='');
public function close();
public function numRows($resultQuery='');
public function fieldName($position, $resultQuery='');
public function dataSeek($position, $resultQuery='');
public function affectedRows($resultQuery='');
public function error($errorInfo='', $resultQuery='');
public function noError($resultQuery='');
public function inQuery($sqlStatement, $type=db::DB_BOTH);
public function inQueryAssoc($sql);
public function inQueryNum($sql);
public function fetchOne($sql);
public function fetchAll($sql);
public function insert($tableName, $values, $fields='', $automaticQuotes=true);
public function update($tableName, $fields, $values, $whereCondition=null, $automaticQuotes=true);
public function delete($tableName, $whereCondition='');
public function limit($sqlStatement, $number);
public function forUpdate($sqlQuery);
public function sharedLock($sqlQuery);
public function begin();
public function rollback();
public function commit();
public function listTables($schemaName='');
public function describeTable($tableName, $schemaName='');
public function getRequiredSequence($tableName='', $identityColumn='', $sequenceName='');
public function lastInsertId($tableName='', $identityColumn='', $sequenceName='');
public function createTable($tableName, $definition, $index=array(), $tableOptions=array());
public function dropTable($tableName, $ifExists=false);
public function tableExists($tableName, $schema='');
public function getDateUsingFormat($date, $format='YYYY-MM-DD');
public function getHaveAutoCommit();
public function setIsolationLevel($isolationLevel);
public function getCurrentDate();
public function getLastResultQuery();
public function getConnectionId();
public function getDatabaseName();
public function getUsername();
public function getHostName();
}
Generación de SQL
Cada gestor relacional sigue estándares del lenguaje SQL, principalmente de las especificaciones ANSI92 y ANSI99. Muchos motores de base de datos agregan extensiones al lenguaje ó no implementan adecuadamente los estándares establecidos por diversas razones. Cuando se escriben aplicaciones multi-motor es posible encontrar ciertas incompatibilidades que podrían conllevar a reescrituras de código que reabren el ciclo del software y podrian generar sobrecostos. La capa de abstracción de Kumbia Enterprise Framework se encarga de los detalles y genera la mayor parte de las sentencias de DML que soporta un gestor relacional.
A nivel de aplicación el lenguaje PHP ofrece una extensa biblioteca de funciones que permiten conectarse y efectuar operaciones sobre una gran variedad de gestores relacionales. Sin embargo, la forma en que estan implementadas estas funciones no es estándar y consistente por lo que el cambio de un gestor a otro conlleva a reescribir código y se presentan las situaciones mencionadas anteriormente.
Ejemplo: Conexión tradicional a gestores relacionales usando PHP
//Conexión a Oracle
$connId = oci_connect("scott", "tiger", "//192.168.0.40/XE");
//Conexión a Informix
$connId = ifx_connect("stores@ol_srv1", "informix", "pass");
//Conexión en PostgreSQL
$connId = pg_connect("host=192.62.10.1 port=5432 dbname=bankdb user=dma password=2fe051871");
Clausulas que extendienden el lenguaje SQL como LIMIT en SELECT, estan soportadas por algunos gestores relacionales y en otros es necesario implementarlos de tal forma que sea transparente y funcionen como se espera.
Ejemplo: Incompatibilidad de algunas extensiones del lenguage SQL en gestores relacionales
//LIMIT en SQLServer ó Sybase
SELECT * FROM (SELECT TOP 10 * FROM (SELECT TOP 10 customers.categoryId FROM customers) AS itable) AS otable
//LIMIT en MySQL
SELECT customers.categoryId FROM customers LIMIT 10
El componente DBR implementa en cada uno de los adaptadores métodos que generan SQL optimizado para cada gestor relacional soportado aumentando las capacidades de cada aplicación desarrollada con el mismo.
Conexiones a gestores relacionales por defecto
Cada aplicación proporciona el archivo de configuración environment.ini en donde se pueden establecer los parámetros de conexión de acuerdo a los entornos de las fases de desarrollo de la aplicación.
El archivo de configuración environment.ini predeterminado tiene la siguiente estructura:
Ejemplo: Archivo de configuración enviroment.ini predeterminado
Los parámetros de conexión tienen el prefijo databse y pueden variar de acuerdo al gestor relacional utilizado. Para indicar el adaptador a usar se utiliza el parámetro database.type. A continuación se explican las consideraciones de conexión para los motores soportados:
Consideraciones para Oracle
Oracle es muy conocido por sus capacidades de escalamiento y características, además es lider en bases de datos y está disponible en varias plataformas.
El adaptador de conexión a Oracle requiere que la extensión de PHP oci8 este disponible, mediante esta es posible conectarse a Oracle en sus versiones 8i, 9i, 10g y 11g. Adicional a esto es necesario instalar el Oracle Instant Client apropiado a la plataforma requerida.
Las variables de entorno ORACLE_HOME, ORACLE_SID, LD_PRELOAD Y NLS_LANG deben estar definidas para realizar la conexión a Oracle.
Parámetros de configuración de la extensión OCI8 como oci8.max_persistent, oci8.persistent_timeout y oci8.default_prefetch también deberían tenerse en cuenta.
De acuerdo a la versión de la extensión OCI8 podría ó no haber compatibilidad con el gestor relacional requerido. En la siguiente tabla se presenta la compatibilidad de acuerdo a la versión de OCI8:
Tabla: Matriz de compatibilidad entre PHP, OCI8 y cliente Oracle
Distribución
Versión PHP
Versión de OCI8
Versiones del cliente Oracle soportado
PHP CVS
5.2.7+
1.2.5
8i, 9i, 10g, 11g
PHP Binario para Windows
5.27+
1.2.5
10g, 11g
PECL OCI8 CVS
Se puede construir desde PHP 4.3.9
1.3.4
9iR2, 10g, 11g
Zend Core for Oracle 2.5
5.2.5
1.2.3
Incluye el Oracle Instant Client 10 por lo que se soportan: 8i, 9i, 10g, 11g
Este adaptador no soporta múltiples transacciones simultaneas, esto quiere decir que al tratar de crear una transacción cuando ya hay una activa se generará una excepción.
Los parámetros de conexión al conectarse a Oracle son:
Tabla: Parámetros de conexión a Oracle usando adaptador Nativo
Parámetro
Descripción
database.username
Los usuarios en Oracle son propiedad de schemas que tienen el mismo nombre del usuario. Este parámetro permite indicar el nombre del usuario ó ambiguamente el schema.
database.host
Nombre de la maquina ó dirección IP donde se encuentra el servidor Oracle.
database.password
Contraseña del usuario con el que se realiza la conexión.
database.instance
Nombre de la instancia de Oracle ó del servicio del TNS Listener. Cuando se usa Oracle Database Express este es 'XE' por defecto.
database.port
Puerto del servicio TNS Listener. Por defecto es 1521.
database.sort
Este parámetro permite establecer como se hará el ordenamiento de columnas que contengan valores alfanuméricos como CHAR ó VARCHAR2. Su valor por defecto es spanish_m. En paises hispano-hablantes las letras ch, ll y ñ son consideradas parte del alfabeto y esta variable permite que el ordenamiento sea adecuado a la localización utilizada.
database.comp
Es la forma en la que se realizan las comparaciones entre valores constantes y columnas de las tablas. El valor por defecto linguistic permite que las comparaciones no sean sensibles a mayúsculas/minúsculas.
database.charset
Permite establecer el charset en el que se almacenan/devolveran valores en las bases de datos. El valor Al32UTF8 es el nombre de Oracle para el charset UTF8.
database.territory
Permite establecer el territorio en el que se encuentra la aplicación. Dependiendo de este los formatos de fechas y de valores númericos se ajusta a la localización requerida. Por defecto es 'spain'.
database.language
El idioma en el que se presentarán los mensajes de error del motor y se formatearán los resultados numéricos y de fechas. Por defecto es 'spanish'.
Conectar a Oracle mediante JDBC
También es posible realizar conexiones a Oracle usando el adaptador JDBC cuando la aplicación ha sido implementada en un contenedor de aplicaciones IBM WebSphere sMash.
El archivo JAR ojdbc14.jar debe estar ubicado en el directorio lib de la aplicación sMash siguiendo las convenciones de arquitectura de la maquina. Por ejemplo si se ejecuta en Linux sobre un procesador arquitectura x86 entonces la ubicación es:
SQL Server es el motor de base de datos relacional de Microsoft. La conexión a este motor es realizada via PHP Data Objects (PDO). Este adaptador solo soporta conexiones a SQL Server desde Windows usando conexiones ODBC mediante el driver php_pdo_odbc. Las versiones de SQL Server soportadas van desde la 7.x hasta la 2008.
Creación de un DSN ODBC para SQL Server
A continuación se ilustra el proceso de creación de una conexión a SQL Server mediante ODBC. Utilizando un usuario con credenciales administrativas se abre el Administrador de Origenes de Datos ODBC desde Panel de Control -> Herramientas Administrativas.
En esta pantalla se selecciona la pestaña 'DSN de usuario' y se da click en el botón 'Agregar…' para crear una nuevo origen de datos:
A continuación se selecciona el tipo de driver utilizado, se busca 'SQL Server' y se da click en siguiente:
Se da click en 'Finalizar' para abrir el asistente de origenes de datos para SQLServer. Se presenta la siguiente pantalla:
El campo nombre hace referencia nombre al origen de datos ó Data Source Name (DSN) que será utilizado luego para realizar la conexión en la aplicación. El campo servidor indica el nombre de la instancia y maquina donde está instalado SQL Server. Se da click en siguiente para continuar. El tipo de autenticación se debe tener en cuenta cuando se realice la conexión desde Kumbia Enterprise. Si se selecciona autenticaciónn de Windows NT no será necesario indicar el parámetro UID y PWD del usuario de conexión. En este caso el usuario con el que se ejecute el proceso del servidor web se utilizará para autenticarse en SQL Server. Si se selecciona autenticación de SQL Server se deben indicar los parámetros mencionados anteriormente.
En la siguiente pantalla se puede configurar la base de datos predeterminada. Las opciones 'Usar identificadores entrecomillados ANSI' y 'Usar nulos, rellenos y advertencias ANSI' deben estar seleccionados.
En esta pantalla se pueden activar otras opciones, al terminar se da click en 'Finalizar':
La última pantalla permite probar la conexión, si todo esta bien no habrá problema al efectuar una conexión desde Kumbia Enterprise.
Los parámetros requeridos de conexión al conectarse con el adaptador "mssql" son:
Tabla: Parámetros de conexión a Microsoft SQL Server usando PDO
Parámetro
Descripción
database.pdo
Indica que se debe cargar un Adaptador PDO. Su valor debe ser On para que tenga efecto.
database.dsn
Indica los parámetros del Data Source Name (DSN) del origen datos. SERVER es la maquina donde está instalada la instancia del framework. DATABASE es el nombre de la base de datos de trabajo. UID es el nombre del usuario con el que se hará la conexión. PWD es el password del usuario. DRIVER es el nombre del driver ODBC para SQL Server, normalmente es 'SQL Server'.
Consideraciones para MySQL
MySQL es uno de los motores Open Source más populares y con mayor presencia en aplicaciones para Internet. Existen 2 adaptadores que permiten la conexión a MySQL, el primero es "mysql" que usa la extensión de PHP nativa del mismo nombre y que permite la conexión usando librerias cliente desde la versión 4.1. La segunda es "mysqli" que utiliza la extensión del mismo nombre y que tiene una funcionalidad y rendimiento superior a la de la extensión "mysql". Ambos adaptadores soportan transacciones en sesiones de conexión diferentes.
Kumbia Enterprise Framework puede trabajar con MySQL cuando está en modo SQL estricto y no estricto. En modo estricto se generarán excepciones DbInvalidFormatException cuando se trate de insertar un valor que no tenga un formato adecuado al tipo de dato requierido de la columna de este.
Los parámetros requeridos de conexión al conectarse con el adaptador "mysql" son:
Ejemplo: Parámetros de conexión requeridos usando el adaptador nativo de mysql
Los posibles parámetros de conexión al conectarse con el adaptador "mysql" son:
Ejemplo: Posibles parámetros de conexión a mysql
[production]
database.type = mysql
database.host = localhost
database.username = root
database.password = my_password
database.name = production_db
database.port = 3306
database.autocommit = Off
database.compression = Off
database.ssl = Off
database.interactive = Off
La descripción de los parámetros anteriores es la siguiente:
Tabla: Parámetros de conexión a MySQL usando el adaptador "mysql"
Parámetro
Descripción
database.username
El nombre de usuario de MySQL con el que se efectuará la conexión.
database.password
El password del usuario de MySQL.
database.host
Servidor de MySQL. Se puede utilizar el string de conexión hostname:puerto ó :/path/al/socket cuando se trata de localhost.
database.name
Nombre de la base de datos.
database.port
Puerto del servidor de MySQL al especificarse se hace la conexión por TCP/IP.
database.autocommit
Cuando el valor es On. Indica si la sesión de MySQL debe establecerse en modo AUTOCOMMIT, esto significa que se debe hacer un COMMIT obligatoriamente para que se tenga efecto los cambios realizados sobre la base de datos. Por defecto es Off.
database.compression
Indica si el cliente MySQL debe comprimir todo el tráfico de red entre la aplicación y el servidor de base de datos. Por defecto es Off
database.ssl
Indica si se debe encriptar el tráfico entre la aplicación y el servidor de base de datos mediante SSL. Por defecto es Off.
database.interactive
Indica si se debe crear una sesión interactiva en vez de una conexión temporal. Por defecto es Off.
Los parámetros requeridos de conexión al conectarse con el adaptador "mysqli" son:
Ejemplo: Parámetros de conexión requeridos para mysqli
Los parámetros adicionales que soporta el adaptador "mysqli" son:
Tabla: Parámetros de conexión soportados usando mysqli
Parámetro
Descripción
database.socket
Aplica cuando el host el localhost y permite establecer el path al socket UNIX ó al named pipe en Windows.
database.charset
Permite establecer el charset utilizado por el cliente MySQL para enviar la información al servidor.
database.key
La ruta a donde se encuentra el archivo de llave compartida. Este parámetro solo aplica cuando la opción SSL está On. Por defecto su valor es NULL.
database.cert
La ruta al archivo de certificado. Este parámetro solo aplica cuando la opción SSL está On. Por defecto su valor es NULL.
database.ca
La ruta al archivo certificate authority. Este parámetro solo aplica cuando la opción SSL está On. Por defecto su valor es NULL.
database.capath
La ruta al archivo que contiene certificados SSL validos en formato PEM. Este parámetro solo aplica cuando la opción SSL está On. Por defecto su valor es NULL. Por defecto su valor es NULL.
database.cipher
Una lista de métodos de cifrado para usar en la encriptación SSL. Este parámetro solo aplica cuando la opción SSL está On. Por defecto su valor es NULL.
Consideraciones para IBM Informix
Kumbia Enterprise utiliza PHP Data Objects (PDO) para acceder a bases de datos IBM Informix. Es posible realizar conexiones a Informix (IDS) versión 7.x, Universal Server (IUS) 9.x y a Informix Dynamic Server 2000, 10 y 11. Los siguientes requisitos son necesarios para realizar una conexión satisfactoria a este motor:
PHP debe estar compilado con la extensión pdo_informix, esta puede ser obtenida via PECL ó al compilar PHP desde el código fuente.
Cuando se compila desde el código fuente la opción de configuración debe incluir ./configure --with-pdo-informix=/path/to/SDK[,shared]
La extensión PECL puede ser instalada usando el comando pecl install pdo_informix en entornos Unix. Para una compilación satisfactoria de la extensión el cliente SDK de IBM para Informix debe estar instalado en la maquina ó el servidor Informix en si mismo.
La variable de entorno INFORMIXDIR debe apuntar al directorio de instalación de informix ó del client SDK.
ESQL/C es necesario para trabajar con informix. El Informix Client SDK contiene este software. El client SDK para IBM Informix puede ser descargado desde el sitio web de soporte de IBM en http://www-306.ibm.com/software/data/informix/tools/csdk/ . Si está utilizando Informix versión 10 ó 11 no es necesario instalar CSDK ya que este viene incluido en la distribución del servidor.
El servidor de Informix debe estar configurado para aceptar conexiones mediante tcp mediante el módulo onsoctcp.
Una vez las extensiones php_pdo y php_pdo_informix se encuentren disponibles la conexión puede realizarse de la siguiente forma:
Ejemplo: Configuración de la conexión a IBM Informix
Tabla:Parámetros de conexión a IBM Informix con PDO
Parámetro
Descripción
database.pdo
Indica que se debe cargar un adaptador PDO. Su valor debe ser On para que tenga efecto.
database.dsn
Los parámetros de conexión del Data Source Name. El parámetro host indica el nombre del maquina ó dirección IP donde está instalado el Informix. Service es el puerto donde se realizará la conexión TCP/IP. Database es el nombre de la base de datos. Server es nombre de la instancia de informix. Protocol debe ser siempre onsoctcp. EnableScrollableCursors debe ser igual a 1 para permitir el uso de cursores que se pueden recorrer en cualquier orden, esto puede mejorar el rendimiento cuando se usan paginadores por ejemplo.Otras opciones que se pueden enviar en el DSN son: TraslationOption, permite utilizar una librería de traducción de mensajes, con valor 0 permite solucionar un problema común en unixODBC.IsolationLevel: Indica el nivel de isolación de la conexión. 0 es Predeterminado, 1 es Read Uncommited, 2 es Read Commited, 3 es Repeteable Read, 4 es Serializable y 5 es LastCommited.CursorBehavior: Cuando es 0 el cursor se cierra automáticamente al recorrer los registros, cuando es 1 se preserva.ClienteLocale: Permite establecer la localización del cliente. Por defecto es en_US.CP1251DatabaseLocale: Permite establecer la localización de la base datos por defecto es: en_US.819AutoCommitOptimization: Indica si el driver debe efectuar optimización para conexiones no-transaccionales.
database.username
Nombre del usuario que realizará la conexión.
database.password
Contraseña del usuario.
Configuración del Servidor
Es posible que deba cambiar el usuario con el que se ejecutan los procesos del servidor web al usuario informix ó un usuario del grupo informix. En el caso de Apache Web Server puede modificar esto cambiando los parámetros User y Group así:
User informix
Group informix
Si el servidor está instalado en Windows y se usa Microsoft IIS se debe entrar a la consola de administración de servicios. Puede ingresar a ella mediante el comando services.msc en el cuadro de dialogo ejecutar. Se da click derecho en el servicio "Informix IDS – Nombre" y luego en propiedades. En la pestaña inicio de sesión se coloca el usuario con permisos del motor y luego click en 'Aceptar'.
La siguiente es una configuración de las variables de entorno para un profile para el usuario "informix" en un servidor Unix ó Windows:
Ejemplo: Variables de entorno recomendadas para realizar una conexión a IBM Informix
El archivo INFORMIXSQLHOSTS debe tener al menos un servicio tcp/ip disponible:
ol_server onsoctcp localhost informixserver
El archivo /etc/services debe incluir la descripción TCP para el servicio creado:
informixserver 9800/tcp # Informix Dynamic Server
Consideraciones con Transacciones
El desarrollador debe activar el logging de la base de datos a Unbuffered Logging ó Buffered Logging usando la herramienta onmonitor ó mediante el comando ontape –B dbname, de lo contrario el adaptador generará una excepción al tratar de realizar un commit ó un rollback a una transacción.
Informix no genera un timeout cuando registros que se vayan a modificar ó leer esten siendo modificados en otra transacción. Kumbia Enterprise generará una excepción como [Informix][Informix ODBC Driver][Informix]Could not do a physical-order read to fetch next row. sqlerrm(t) (SQLFetchScroll[-244] at /root/PDO_INFORMIX/informix_statement.c:889)] (-244) de tipo DbLockAdquisitionTimeout.
Todos los niveles de isolación son soportados en runtime. El nivel de isolación CURSOR SCALABILITY es validado con ISOLATION_SERIALIZABLE.
Nota: IBM Informix no soporta la extensión del lenguaje SQL LIMIT por lo que el desarrollador debe asegurarse que los resultados devuelva el número de registros requeridos via condiciones en la clausula WHERE.
Consideraciones con SQLite
SQLite es un motor de base de datos escrito en C que es embebible en aplicaciones web de baja concurrencia. La librería SQLite permite administrar bases de datos que se crean en un solo archivo y que se pueden distribuir junto con la aplicación.
Como se mencionó anteriormente las bases de datos SQLite no están recomendadas para grandes aplicaciones con alto tráfico y acceso concurrente elevado.
Kumbia Enterprise soporta SQLite versión 3 mediante la capa de abstracción PDO (PHP Data Objects) por lo que se requiere que las extensiones de PHP pdo y pdo_sqlite esten disponibles por la aplicación. Este adaptador no soporta múltiples transacciones simultáneas.
Tabla: Parámetros de conexión del adaptador de SQLite con PDO
Parámetro
Descripción
database.layer
Indica que se debe cargar un Adaptador PDO. Su valor debe ser "pdo" para que tenga efecto.
database.dsn
Cuando se trata de SQLite indica la ruta al archivo base de datos. La extensión .db es opcional pero es más representativa. El PATH del archivo puede ser un path absoluto desde el directorio donde está instalada la instancia ó un path relativo.
Pool de Conexiones
El componente DbBase mediante la implementación de un Singleton controla que cada vez que se solicite la conexión a la base de datos se devuelva la misma conexión evitando la creación de múltiples conexiones al gestor relacional de forma innecesaria aumentando los recursos requeridos por la aplicación.
El método estático Database::rawConnect() devuelve la misma conexión activa sin importar el número de veces que sea invocado, si aun no existe una conexión entonces la crea. Los parámetros de conexión son los establecidos por entorno activo en environment.ini. Si se requiere una nueva conexión al gestor se puede enviar true como primer parámetro y si se requiere renovar la conexión es decir reemplazar la conexión del Singleton se envia true como segundo parámetro.
Conexiones de Bajo Nivel
Es posible establecer conexiones de bajo nivel a múltiples motores independientemente del gestor relacional requerido. El subcomponente DbLoader permite tanto cargar el adaptador activo establecido en enviroment.ini como uno cualquiera usando el método estático factory.
El primer parámetro corresponde al nombre del adaptador requerido para efectuar la conexión, el segundo es un vector que contiene las opciones de conexión. Estas son las mismas utilizadas en una sección de un archivo de configuración enviroment.ini.
Ejemplo: Establecer una conexión a un gestor relacional mediante DbLoader::factory
La propiedad de las conexiones de generar trazas permite obtener una lista de todas las operaciones SQL de bajo nivel ejecutadas en una sessión al gestor relacional.
Para activar la traza en una conexión se debe llamar al método setTracing con parámetro true apartir del momento donde se desea empezar la traza:
Ejemplo: Activar y obtener la traza de seguimiento en un procedimiento con gestores relacionales
<?php
$db = DbBase::rawConnect();
$db->setTracing(true);
$results1 = $db->fetchAll("SELECT * FROM customers");
$results2 = $db->fetchAll("SELECT * FROM customers WHERE status = 'Active'");
foreach($db->getTracedSQL() as $sqlStatement){
echo $sqlStatement."\n";
}
Generar Profiles de ejecución de SQL
Los objetos del componente Db permiten generar Profiles de la ejecución de sentencias SQL que se envian al gestor relacional. La información generada incluye los tiempos en milisegundos que duró la ejecución de cada sentencia y así poder identificar cuellos de botella en la aplicación.
Ejemplo: Activar el profiling desde objeto de conexión a un gestor relacional
Internamente una instancia de DbProfiler es instanciada para generar los profiles de las operaciones SQL. El desarrollador puede definir su propio profiler estableciendo una instancia de la clase que implemente la interfaz DbProfilerInterface como parámetro de setProfiling().
Ejemplo: Definir una clase de profile personalizada
La interface DbProfilerInterface exige la implementación de:
interface DbProfileInterface {
public function startProfile($sqlStatement);
public function stopProfile();
public function getNumberTotalStatements();
public function getTotalElapsedSeconds();
public function getProfiles();
public function reset();
public function getLastProfile();
}
Manejar Excepciones de Db
Crear la instancia del adaptador ó directamente en el constructor del mismo crea automáticamente una conexión a la base de datos. Si ocurren problemas al hacer la conexión ó alguno de los parámetros es invalido se genera una excepción en la misma la cual debe ser controlada por el desarrollador.
Las excepciones son controladas mediante un bloque try/catch que capture una excepción del tipo DbException:
Ejemplo: Capturar una excepción DbException generada por el adaptador de conexión al gestor relacional
Tipos de Excepciones lanzadas por el componente Db
Excepción
Descripción
DbException
Excepción generica lanzada por adaptador de conexión al gestor relacional utilizado.
DbLockAdquisitionException
Excepción lanzada cuando la transacción actual en la conexión no puede efectuar un bloqueo sobre algún recurso por ejemplo una tabla ó una serie de registros.
DbSQLGrammarException
Excepción lanzada cuando se envia una sentencia SQL mal formada ó con errores de sintaxis.
DbContraintViolationException
Excepción lanzada cuando la operación de modificación ó actualización viola un constraint de llave foránea.
DbInvalidFormatException
Excepción lanzada cuando se trata de insertar ó actualizar un valor en una tabla con un formato erroneo.
Información extendida de excepciones generadas por Db
Las excepciones generadas por el componente Db ofrecen información extendida del origen de una excepción. Cuando la aplicación se encuentra en modo debug esta información se puede visualizar en pantalla. La referencia de la pantalla de excepciones es la siguiente:
En la esquina superior derecha se presenta el tipo de excepción generada:
Después de esta el mensaje que ha enviado el gestor relacional y la sentencia SQL que generó la excepción. En este caso tanto el tipo de excepción como el mensaje de error indica que la sentencia SQL esta mal formada ó tiene errores de sintaxis.
El id de conexión es un código interno que identifica el recurso utilizado para conectarse al motor de base de datos. El mensaje de la excepción informa que conexión estaba activa cuando se produjo la excepción. El id aparece al final como "Resource id #64".
El codigo de error enviado por el motor también puede resultar de ayuda en algunos casos. Este se muestra al final del mensaje de error entre paréntesis.
Como la aplicación se encuentra en modo debug se visualiza la traza de ejecución de la excepción. Si Kumbia Enteprise detecta que la excepción se ha generado en un archivo de la aplicación entonces se muestra el fragmento de código resaltando la línea exacta donde se generó la excepción:
Debajo de la traza se encuentra el cuadro "Datos de la conexión activa" y presenta atributos del estado de la conexión en el momento de la excepción:
En este caso la traza se encuentra desactivada, al activarla se obtendría todas las intrucciones SQL que se ejecutaron en la misma conexión previamente a que se produjera la excepción. La traza se puede activar declarativamente en el modo activo en config/environment.ini ó programacionalmente pasando el parámetro "tracing" => true al constructor del objeto conexión.
El archivo config/environment.ini entonces quedaría así:
Ejemplo: Activar la traza en el archivo config/environment.ini
Al ejecutar nuevamente el procedimiento se puede visualizar la traza de la conexión:
El campo "Traza" dice "SI" y debajo de este el nuevo campo "Contenido de la Traza" muestra en orden cronológico las sentencias SQL generadas en la conexión activa.
Más debajo se visualiza el cuadro datos de entrada, en él se detalla la información que fue enviada al procedimiento desde el formulario ó enlace anterior. El objetivo del cuadro es identificar si los datos de entrada pueden ser los causantes del problema:
Los valores de entrada se muestran en modo detallado ayudando así a conocer su contenido más fácilmente.
Si la información generada no es suficiente para identificar la causa de la excepción puede utilizar el componente Debug el cual proporciona ayudas para realizar procedimientos tradicionales de rastreo de procesos.
Tipos de Resultado al Obtener de Registros
Cada adaptador implementa los mismos tipos de vector al obtener registros, esto se refiere a la forma en la que los vectores devueltos estan indexados. Los métodos inQuery, fetchOne y fetchAll permiten establecer en su segundo parámetro los valores de las constantes que permiten cambiar la forma en la que estan dispuestos los resultados al obtenerlos.
Tabla: Tipos de constantes para obtener los registros de un resultado
Constante
Descripción
Db::DB_NUM
Devuelve cada registro como un vector indexado solamente numéricamente.
Db::DB_ASSOC
Devuelve cada registro como un vector indexado solamente asociativamente. Las claves utilizadas como indices corresponden a los nombres de las columnas de la sentencia SELECT ejecutada. Cuando se realizan JOINs en múltiples tablas es posible que el nombre de los indices se repita por lo cual es necesario implementar alias para las columnas repetidas.Para todos los gestores relacionales los indices se encuentran en minúsculas.
Db::DB_BOTH
Devuelve cada registro indexado tanto numéricamente como asociativamente. El número de elementos por vector resultado es el doble del número de columnas devuelto en la sentencia SELECT.
Leer registros
Los siguientes métodos corresponden al API del componente Db que permiten leer registros de las entidades:
public resource|false query(string $sqlQuery) Envia una sentencia SQL al gestor relacional. La sentencia puede devolver registros o no devolverlos.
Ejemplo: Enviar una sentencia SQL al gestor relacional mediante el método query()
public array find(string $tableName, string $whereClause, string $fields="", string $orderBy="1") Realiza una consulta SELECT en una tabla en forma abstraida.
Ejemplo: Realizar una búsqueda usando el método find()
<?php
//Mostrar todos los clientes activos
$db = DbBase::rawConnect();
$resultset = $db->find("customers", "status = 'Active'");
foreach($resulset as $row){
echo $row['name']."\n";
}
public array inQuery(string $sqlQuery, int $fetchType=db::DB_BOTH) Devuelve los resultados de una consulta SQL en un array. El parámetro $fetchType se refiere a las constantes db::DB_ASSOC, db::DB_NUM y db::DB_BOTH que es el tipo de indexamiento del vector devuelto por registro.
public array fetchAll(string $sqlQuery, int $fetchType=db::DB_BOTH) Obtiene todos los resultados de una consulta SQL en un array. Es un alias para el método inQuery.
public array inQueryAssoc(string $sqlQuery) Obtiene todos los resultados de una consulta SQL en un array. Cada registro es un array indexado asociativamente.
Ejemplo: Realizar un consulta que devuelve los registros como vectores indexados asociativamente
<?php
$db = db::rawConnect();
$customers = $db->inQueryAssoc("SELECT id, name FROM customers ORDER BY id");
foreach($customers as $customer) {
echo $customer['name']."\n";
}
public array inQueryNum(string $sqlQuery) Obtiene todos los resultados de una consulta SQL en un array. Cada registro es un array indexado numéricamente.
Ejemplo: Realizar un consulta que devuelve los registros como vectores indexados numéricamente
<?php
$db = db::rawConnect();
$customers = $db->inQueryNum("SELECT id, name FROM customers ORDER BY id");
foreach($customers as $customer) {
echo $customer[1]."\n"; //Imprime el nombre
}
public array fetchOne(string $sqlQuery, int $fetchType=db::DB_BOTH) Devuelve un solo registro en un array de la consulta SELECT en $sqlQuery. El parámetro $type se refiere a las constantes db::DB_ASSOC, db::DB_NUM y db::DB_BOTH que es el tipo de indexamiento del array devuelto por registro.
Ejemplo: Obtener un resultado para consultas que devuelven un solo registro
<?php
$db = DbBase::rawConnect();
$customer = $db->fetchOne("SELECT * FROM customers WHERE id = 124");
public array fetchArray(resource $resultQuery) Obtiene un registro del ultimo recurso de consulta generado en el objeto adaptador ó el indicado mediante el recurso $resultQuery. El resultado devuelto depende del fetchMode establecido con setFetchMode.
public void numRows(resource $resultQuery=null) Devuelve el número de filas obtenidas en la ultima consulta SQL ejecutada en el objeto adaptador. Es posible establecer el recurso devuelto por el método query para obtener esta información.
Ejemplo: Obtener el número de registros que devuelve una consulta
<?php
$db = Db::rawConnect();
$result = $db->query("SELECT id, name FROM customer WHERE status = 'Active'");
echo "Hay ".$result->numRows($result)." clientes activos";
public boolean dataSeek(int $number, resource $resultQuery=null) Permite establecer la posición en el cursor interno ó el establecido por $resultQuery haciendo que el próximo registro que obtenga fetchArray sea el número $number.
Ejemplo: Mover el puntero del resultado de una consulta
<?php
$db = DbLoader::factory('MySQL', array(
"host" => "127.0.0.1",
"username" => "root",
"password" => "hea101",
"name" => "bankdb"
));
$db->query("SELECT id, name FROM customer WHERE category_id = 1");
if($db->numRows()>10){
//Empezar desde el 10 registro
$db->dataSeek(10);
while($row = $db->fetchArray()){
echo $row['name']."\n";
}
}
public resource getLastResultQuery() Obtiene el último recurso generado en una consulta SQL mediante el objeto.
Ejemplo: Obtener el último resulset generado con Db::getLastResultQuery
<?php
$db = Db::rawConnect();
$db->query("SELECT id, name FROM customer WHERE status = 'A'");
$result = $db->getLastResultQuery();
while($row = $db->fetchArray()){
echo $row['name']."\n";
}
public string limit(string $sqlQuery, int $number) La extensión del la sentencia SQL SELECT llamada LIMIT permite especificar al gestor relacional que no debe devolver más del numero de registros limitados a $number. No todos los gestores relacionales implementan esta extensión y otros permiten hacerlo utilizando otros procedimientos.
Este método permite crear una sentencia SQL que reproduzca la funcionalidad LIMIT en forma transparente.
Ejemplo: Aplicar la extensión del lenguaje SQL LIMIT a una consulta
<?php
$db = Db::rawConnect();
$sqlQuery = $db->limit("SELECT id, name FROM customer WHERE status = 'A'", 10);
$db->query($sqlQuery);
$result = $db->getLastResult();
while($row = $db->fetchArray()){
echo $row['name']."\n";
}
Manipular Registros
Los siguientes métodos permiten la generación y ejecución de sentencias SQL que permiten la manipulación de registros:
public boolean insert(string $table, array $values, array $fields=array(), boolean $automaticQuotes=false) Permite realizar una inserción sin usar SQL directamente. El SQL es generado está de acuerdo al gestor relacional utilizado. Notese que por defecto el método espera que los valores a insertar esten correctamente escapados, el parámetro $automaticQuotes permite que se agregen comillas simples y se escapen los valores usando la función addslaches() en forma automática.
Las columnas que son omitidas se les aplica la regla del gestor relacional DEFAULT si esta existe, en caso contrario se insertan valores nulos.
Ejemplo: Realizar una inserción con $automaticQuotes y sin ellas
Cuando se agrega el parámetro $automaticQuotes y se requiere insertar expresiones ó ejecución de funciones de la base de datos es necesario indicar estos usando instancias de la clase DbRawValue.
Ejemplo: Insertar un valor expresión de la base de datos
public boolean update(string $table, array $fields, array $values, string $whereClause=null, boolean $automaticQuotes=false) Permite realizar una actualización sin usar SQL directamente. El SQL es generado de acuerdo al gestor relacional utilizado. Notese que por defecto el método espera que los valores a actualizar esten correctamente escapados, el parámetro $automaticQuotes permite que se agregen comillas simples y se escapen los valores usando la función addslaches().
public void delete(string $table, string $whereCondition="") Permite realizar una eliminación de registros sin usar SQL directamente. El SQL es generado de acuerdo al gestor relacional utilizado.
Ejemplo: Realizar una eliminación de datos
<?php
$db = DbBase::rawConnect();
//Eliminar todos los registros de la tabla customer
if($db->delete("customer")==true){
Flash::success("Se eliminaron correctamente todos los registros");
}
//Eliminar usando condiciones
if($db->delete("customer", "status = 'Active'")==true){
Flash::success("Se eliminaron correctamente los registros");
}
public integer affectedRows(Resource $resultQuery=null) Devuelve el numero de filas afectadas por una operación de inserción, actualización ó borrado. El parámetro $resultQuery permite cambiar el recurso devuelto por otra ejecución del método query ó exec.
Ejemplo: Obtener información de los registros afectados en una operación de manipulación de datos
<?php
$db = Db::rawConnect();
$db->query("DELETE FROM customer WHERE status = 'I'");
echo "Filas borradas = ".$db->affectedRows();
Administrar Transacciones
public boolean begin() Permite iniciar una transacción en la conexión utilizada.
public boolean rollback() Permite anular una transacción en la conexión utilizada.
public boolean commit() Permite hacer commit a una transacción pendiente en la conexión actual.
public string forUpdate(string $sqlQuery) Genera un SQL que efectúa un bloqueo no-compartido del grupo de registros seleccionados.
public string sharedLock(string $sqlQuery) Genera un SQL que efectúa un bloqueo compartido del grupo de registros seleccionados.
public void setIsolationLevel(int $isolationLevel) Permite establecer el nivel de isolación de la conexión. Los niveles de isolación deben estar disponibles en el gestor relacional, consulte la documentación si tiene dudas de ello. El valor del parámetro $isolationLevel es alguna de las constantes:
Tabla: Descripción de constantes de niveles de Isolación
Valor
Nombre
Descripción
1
ISOLATION_READ_UNCOMMITED
Los SELECTs se ejecutan en un modo de no-bloqueo.
2
ISOLATION_READ_COMMITED
Las consultas se ejecutan un un modo de lecturas consistentes con no-bloqueo.
3
ISOLATION_REPEATABLE_READ
Gestores transaccionales normalmente trabajan sobre este modo de isolación.
4
ISOLATION_SERIALIZABLE
Algunos gestores relacionales como Oracle soportan nativamente este modo, otros como MySQL convierten todas las instrucciones SELECT en SELECT … LOCK IN SHARE MODE bloqueando el grupo de registros obtenidos en una consulta a modo-solo lectura.
public boolean isUnderTransaction() Permite conocer si la conexión se encuentra bajo una transacción activa.
public void getHaveAutoCommit() Permite conocer si la conexión tiene auto-commit ó nivel de isolación READ UNCOMMITED.
Crear, Cerrar y obtener información de conexiones
public Db rawConnect(boolean $newConnection=false, boolean $renovate=false) Obtiene un objeto conexión a la base de datos del entorno actual con los parámetros establecidos en el archivo config/enviroment.ini. Este método implementa el patrón Singleton controlando que solo una instancia de la conexión se cree cada vez que se hace el llamado al mismo desde cualquier parte de la aplicación.
Ejemplo: Obtener la conexión por defecto al gestor relacional
<?php
//Crear o obtener la última conexión creada
$db = DbBase::rawConnect();
//Crear una nueva conexión sin cambiar la conexión del Singleton
$db = DbBase::rawConnect(true);
//Crear una nueva conexión renovando la conexión del Singleton
$db = DbBase::rawConnect(true, true);
public ResourceConnection connect(stdClass $descriptor) Establece la conexión al gestor relacional.
Ejemplo: Crear una conexión usando el método Db::connect
public resource getConnectionId() Obtiene el recurso interno de bajo nivel con el que se identifica la conexión al gestor relacional.
public void close() Cierra la conexión actual con el gestor relacional. Si la conexión es persistente no se cerrará.
public void setReadOnly(boolean $readOnly) Establece si la conexión será de solo lectura. En este estado se generará una excepción cuando se trate de realizar una inserción, modificación ó eliminación de datos.
public void isReadOnly() Permite saber si la conexión es de solo lectura ó no.
Información de Errores
public string error(string $errorString='', resource $resultQuery=null) Devuelve información del último error generado en el adaptador.
public integer noError(resource $resultQuery=null) Devuelve el número del último error generado.
Obtener el valor de la columna identidad
Algunos gestores relacionales soportan columnas identidad, es decir, que manejan un consecutivo auto-numérico para diferenciar unívocamente cada registro en una tabla.
public integer lastInsertId(string $table='', string $identityField="") Obtiene el último valor insertado en una columna identidad. Algunos gestores relacionales no soportan este tipo de columnas y por ello es necesario obtener el valor buscando el máximo valor insertado en el campo llave primaria.
public boolean tableExists(string $table, string $schema="") Permite consultar si una relación con el nombre $table existe en el schema de la conexión actual ó el indicado usando el parámetro $schema.
Obtener información de Tablas
public array getFieldsFromTable(string $tableName) Este método obtiene los campos de una tabla en un vector. El vector puede ser indexado numéricamente ó asociativamente:
Ejemplo: Obtener los campos de una tabla con Db::getFieldsFromTable
public string fieldName(int $number, Resource $resultQuery=null) Obtiene el nombre de un campo en la posición establecida por $number del resultado $resultQuery.
public array listTables(string $schemaName='') Devuelve un array con las tablas que hay en la schema actual ó en el que se indique en $schemaName. En algunos gestores relacionales también se devuelven las vistas a las que tenga acceso el usuario de la conexión activa.
public array describeTable(string $tableName='', string $schemaName='') Devuelve un array con la descripción de los campos de una tabla junto con sus tipos de datos.
Crear y Eliminar Tablas
public boolean createTable(string $tableName, array $definition, array $index=array(), array $tableOptions=array()) Permite crear tablas físicas ó temporales en la conexión activa. El parámetro $definition es un vector con la lista de campos de la tabla y sus atributos. El parámetro $index permite indicar indices que se deban crear junto con la tabla y por último $tableOptions permite indicar opciones de la tabla a crear tales como el Engine en el caso de MySQL, el charset ó el tablespace en el caso de Oracle. Devuelve un valor booleano indicando el éxito de la operación.
Ejemplo: Crear una tabla usando un adaptador en especial
Los tipos de atributos con los que se puede describir un campo en la definición de las columnas es la siguiente:
Tabla: Tipos de atributos para describir una tabla con Db::createTable
Atributo
Descripción
type
El tipo de dato que se almacenará en la columna, se puede utilizar un string con el tipo de dato ó usar las constantes del adaptador lo que es más recomendable.
notNull
Indica si la columna debe permitir nulos o no.
primary
Indica si el campo hace parte de la llave primaria de la tabla.
auto
Indica si el campo es identidad. Solo puede haber un campo autonumérico en la tabla.
size
Tamaño del campo.
scale
Permite establecer la escala del campo.
precision
Permite establecer la precisión del campo.
default
Permite establecer el valor por defecto de la columna cuando se inserta un valor nulo en ella.
public boolean dropTable(string $tableName, $ifExists=false) Elimina una tabla del schema actual de la conexión. El parámetro $ifExists permite establecer si se debe comprobar que la tabla exista antes de ser eliminada lo que evita una excepción generada por el gestor relacional. Devuelve un valor booleano indicando el éxito de la operación.
public string getDateUsingFormat(string $date, string $format="YYYY-MM-DD") Devuelve la fecha del gestor relacional en un determinado formato.
public string getCurrentDate() Obtiene la fecha actual desde el gestor relacional.
public string addQuotes(string $value) Agrega comillas especiales soportadas por el gestor relacional a un valor $value.
Debug, Seguimiento y Traza
protected void log(string $msg, int $type=Logger::DEBUG) Envia un valor al log interno del objeto conexión. La variable $type debe tener el valor de una de las constantes del componente Logger.
protected void debug(string $sqlStatement) Realiza un debug de la instrucción SQL $sqlStatement enviandola a pantalla. Generalmente no es usado externamente y se invoca cuando la conexión se encuentra en modo debug.
public void setDebug(boolean $debug) Permite imprimir en pantalla las operaciones internas de SQL generadas en el objeto.
public void setTracing(boolean $tracing) Establece si el objeto está en modo traza ó no.
public array getTracedSQL() Devuelve un vector con las operaciones SQL ejecutadas en la conexión mientras se encontraba en modo traza.
public void setLogger(mixed $logger) Establece el nombre del archivo con el que se hará seguimiento a las operaciones SQL generadas en la conexión. Si se envia true como parámetro se creará un log con la convención dbYYYYMMDD.txt. Si se establece una instancia de un adaptador de logger este es tomado para hacer el seguimiento.