Capa de Abstracción de Base de Datos

Resumen
The components under the Phalcon\Db
namespace are the ones responsible for powering the Phalcon\Mvc\Model class - the Model
in MVC for the framework. Consiste en una capa de abstracción independiente de alto nivel para sistemas de base de datos escrita completamente en C.
Este componente permite una manipulación de base de datos de más bajo nivel que usando modelos tradicionales.
Adaptadores
Este componente hace uso de adaptadores para encapsular los detalles específicos del sistema de base de datos. Phalcon usa PDO para conectar a bases de datos. Se soportan los siguientes motores de base de datos:
Clase |
Descripción |
Phalcon\Db\Adapter\Pdo\Mysql |
Es el sistema de gestión de bases de datos relacionales (RDBMS) más utilizado en el mundo que se ejecuta como un servidor que provee acceso multiusuario a un número de bases de datos |
Phalcon\Db\Adapter\Pdo\Postgresql |
PostgreSQL es un sistema de base de datos relacional de código abierto muy potente. Tiene más de 15 años de desarrollo activo y una arquitectura probada que se ha ganado una sólida reputación por la fiabilidad, la integridad y exactitud de los datos. |
Phalcon\Db\Adapter\Pdo\Sqlite |
SQLite es una biblioteca de software que implementa un motor de base de datos SQL transaccional independiente, sin servidor, sin configuración |
Constantes
The Phalcon\Db\Enum class exposes a number of constants that can be used on the DB layer.
FETCH_ASSOC
= \Pdo::FETCH_ASSOC
FETCH_BOTH
= \Pdo::FETCH_BOTH
FETCH_BOUND
= \Pdo::FETCH_BOUND
FETCH_CLASS
= \Pdo::FETCH_CLASS
FETCH_CLASSTYPE
= \Pdo::FETCH_CLASSTYPE
FETCH_COLUMN
= \Pdo::FETCH_COLUMN
FETCH_FUNC
= \Pdo::FETCH_FUNC
FETCH_GROUP
= \Pdo::FETCH_GROUP
FETCH_INTO
= \Pdo::FETCH_INTO
FETCH_KEY_PAIR
= \Pdo::FETCH_KEY_PAIR
FETCH_LAZY
= \Pdo::FETCH_LAZY
FETCH_NAMED
= \Pdo::FETCH_NAMED
FETCH_NUM
= \Pdo::FETCH_NUM
FETCH_OBJ
= \Pdo::FETCH_OBJ
FETCH_PROPS_LATE
= \Pdo::FETCH_PROPS_LATE
FETCH_SERIALIZE
= \Pdo::FETCH_SERIALIZE
FETCH_UNIQUE
= \Pdo::FETCH_UNIQUE
Additional constants are available in the Phalcon\Db\Column object. Este objeto se usa para describir una columna (o campo) en una tabla de base de datos. Estas constantes también definen qué tipos soporta el ORM.
Tipos de Enlace
Tipo |
Descripción |
BIND_PARAM_BLOB |
Blob |
BIND_PARAM_BOOL |
Bool |
BIND_PARAM_DECIMAL |
Decimal |
BIND_PARAM_INT |
Integer |
BIND_PARAM_NULL |
Null |
BIND_PARAM_STR |
Cadena |
BIND_SKIP |
Skip binding |
Tipos de Columna
Tipo |
Descripción |
TYPE_BIGINTEGER |
Big integer |
TYPE_BINARY |
Binary |
TYPE_BIT |
Bit |
TYPE_BLOB |
Blob |
TYPE_BOOLEAN |
Boolean |
TYPE_CHAR |
Char |
TYPE_DATE |
Date |
TYPE_DATETIME |
Datetime |
TYPE_DECIMAL |
Decimal |
TYPE_DOUBLE |
Double |
TYPE_ENUM |
Enum |
TYPE_FLOAT |
Float |
TYPE_INTEGER |
Integer |
TYPE_JSON |
JSON |
TYPE_JSONB |
JSONB |
TYPE_LONGBLOB |
Long Blob |
TYPE_LONGTEXT |
Long Text |
TYPE_MEDIUMBLOB |
Medium Blob |
TYPE_MEDIUMINTEGER |
Medium Integer |
TYPE_MEDIUMTEXT |
Medium Text |
TYPE_SMALLINTEGER |
Small Integer |
TYPE_TEXT |
Text |
TYPE_TIME |
Time |
TYPE_TIMESTAMP |
Timestamp |
TYPE_TINYBLOB |
Tiny Blob |
TYPE_TINYINTEGER |
Tiny Integer |
TYPE_TINYTEXT |
Tiny Text |
TYPE_VARBINARY |
Varbinary |
TYPE_VARCHAR |
Varchar |
NOTE: Depending on your RDBMS, certain types will not be available (e.g. JSON
is not supported for Sqlite).
Métodos
public function addColumn(
string $tableName,
string $schemaName,
ColumnInterface $column
): bool
Añade una columna a una tabla
public function addIndex(
string $tableName,
string $schemaName,
IndexInterface $index
): bool
Añade un índice a una tabla
public function addForeignKey(
string $tableName,
string $schemaName,
ReferenceInterface $reference
): bool
Añade una clave ajena a una tabla
public function addPrimaryKey(
string $tableName,
string $schemaName,
IndexInterface $index
): bool
Añade una clave primaria a una tabla
public function affectedRows(): int
Devuelve el número de filas afectadas por el último INSERT
/UPDATE
/DELETE
informado por el sistema de base de datos
public function begin(
bool $nesting = true
): bool
Inicia una transacción en la conexión
public function close(): void
Cierra la conexión activa devolviendo éxito. Phalcon automáticamente cierra y destruye las conexiones activas
public function commit(
bool $nesting = true
): bool
Confirma la transacción activa en la conexión
public function connect(
array $descriptor = []
): void
This method is automatically called in Phalcon\Db\Adapter\Pdo\AbstractPdo constructor. Llámelo cuando necesite restaurar una conexión de base de datos
public function createSavepoint(
string $name
): bool
Crea un nuevo punto de guardado
public function createTable(
string $tableName,
string $schemaName,
array $definition
): bool
Crea una tabla
public function createView(
string $viewName,
array $definition,
string $schemaName = null
): bool
Crea una vista
public function delete(
mixed $table,
string $whereCondition = null,
array $placeholders = [],
array $dataTypes = []
): bool
Borra datos de una tabla usando sintaxis SQL del RBDMS personalizada
public function describeColumns(
string $table,
string $schema = null
): ColumnInterface[]
Devuelve un vector de objetos Phalcon\Db\Column que describen una tabla
public function describeIndexes(
string $table,
string $schema = null
): IndexInterface[]
Lista los índices de la tabla
public function describeReferences(
string $table,
string $schema = null
): ReferenceInterface[]
Lista las referencias de la tabla
public function dropColumn(
string $tableName,
string $schemaName,
string $columnName
): bool
Elimina una columna de una tabla
public function dropForeignKey(
string $tableName,
string $schemaName,
string $referenceName
): bool
Elimina una clave ajena de una tabla
public function dropIndex(
string $tableName,
string $schemaName,
string $indexName
): bool
Elimina un índice de una tabla
public function dropPrimaryKey(
string $tableName,
string $schemaName
): bool
Elimina una clave primaria de una tabla
public function dropTable(
string $tableName,
string $schemaName = null,
bool $ifExists = true
): bool
Elimina una tabla de un esquema/base de datos
public function dropView(
string $viewName,
string $schemaName = null,
bool $ifExists = true
): bool
Elimina una vista
public function escapeIdentifier(
mixed identifier
): string
Escapa un nombre de columna/tabla/esquema.
public function escapeString(string $str): string
Escapa un valor para evitar inyecciones SQL
public function execute(
string $sqlStatement,
array $bindParams = [],
array $bindTypes = []
): bool
Envía sentencias SQL al servidor de base de datos devolviendo el estado de éxito. Use este método sólo cuando las sentencias SQL enviadas al servidor no devuelvan ninguna fila
public function fetchAll(
string $sqlQuery,
int $fetchMode = 2,
array $bindParams = [],
array $bindTypes = []
): array
Vuelca el resultado completo de una consulta en un vector
public function fetchColumn(
string $sqlQuery,
array $placeholders = [],
mixed $column = 0
): string | bool
Devuelve el n-ésimo campo de la primera fila en un resultado de consulta SQL
$invoicesCount = $connection
->fetchColumn('SELECT count(*) FROM co_invoices')
print_r($invoicesCount)
$invoice = $connection->fetchColumn(
'SELECT inv_id, inv_title
FROM co_invoices
ORDER BY inv_created_at DESC',
1
)
print_r($invoice)
public function fetchOne(
string $sqlQuery,
int $fetchMode = 2,
array $bindParams = [],
array $bindTypes = []
): array
Devuelve la primera fila en un resultado de consulta SQL
public function forUpdate(
string $sqlQuery
): string
Devuelve un SQL modificado con una cláusula FOR UPDATE
public function getColumnDefinition(
ColumnInterface $column
): string
Devuelve la definición de columna SQL para una columna
public function getColumnList(
mixed $columnList
): string
Obtiene una lista de columnas
public function getConnectionId(): string
Obtiene el identificador único de conexión activo
public function getDefaultValue(): RawValue
Return the default value to make the RBDM use the default value declared in the table definition
public function getDescriptor(): array
Devuelve el descriptor usado para conectar a la base de datos activa
public function getDialect(): DialectInterface
Devuelve la instancia interna del dialecto
public function getDialectType(): string
Devuelve el nombre del dialecto usado
public function getDefaultIdValue(): RawValue
Devuelve el valor de la identidad predeterminado para insertar en una columna de identidad
public function getErrorInfo(): array
Return the last error information
public function getInternalHandler(): mixed
Devuelve el manejador PDO interno
public function getNestedTransactionSavepointName(): string
Devuelve el nombre del punto de guardado a usar en transacciones anidadas
public function getRealSQLStatement(): string
Sentencia SQL activa en el objeto sin reemplazar parámetros enlazados
public function getSQLStatement(): string
Sentencia SQL activa en el objeto
public function getSQLBindTypes(): array
Sentencia SQL activa en el objeto
public function getSQLVariables(): array
Sentencia SQL activa en el objeto
public function getType(): string
Devuelve el tipo de sistema de base de datos para el que se usa el adaptador
public function insert(
string $table,
array $values,
mixed $fields = null,
mixed $dataTypes = null
): bool
Inserta datos en una tabla usando sintaxis SQL personalizada del RDBMS
public function insertAsDict(
string $table,
mixed $data,
mixed $dataTypes = null
): bool
Inserta datos en una tabla usando sintaxis SQL personalizada del RBDM
$success = $connection->insertAsDict(
'co_invoices',
[
'inv_cst_id' => 1,
'inv_title' => 'Invoice for ACME Inc.',
]
)
// SQL
// INSERT INTO `co_invoices`
// ( `inv_cst_id`, `inv_title` )
// VALUES
// ( 1, 'Invoice for ACME Inc.' )
public function isNestedTransactionsWithSavepoints(): bool
Devuelve si las transacciones anidadas deberían usar puntos de guardado
public function isUnderTransaction(): bool
Comprueba si la conexión está bajo una transacción de base de datos
public function lastInsertId(
mixed $sequenceName = null
): string | bool
Devuelve el id insertado en una columna auto_increment en la última sentencia SQL
public function limit(
string $sqlQuery,
int $number
): string
Añade una cláusula LIMIT al argumento sqlQuery
public function listTables(
string $schemaName = null
): array
Lista todas las tablas de una base de datos
public function listViews(
string $schemaName = null
): array
Lista todas las vistas de una base de datos
public function modifyColumn(
string $tableName,
string $schemaName,
ColumnInterface $column,
ColumnInterface $currentColumn = null
): bool
Modifica una columna de base de datos basada en una definición
public function query(
string $sqlStatement,
array $bindParams = [],
array $bindTypes = []
): ResultInterface | bool
Envía sentencias SQL al servidor de base de datos devolviendo el estado de éxito. Use este método sólo cuando las sentencias SQL enviadas al servidor devuelvan filas
public function releaseSavepoint(
string $name
): bool
Lanza el punto de guardado dado
public function rollback(
bool $nesting = true
): bool
Deshace la transacción activa en la conexión
public function rollbackSavepoint(
string $name
): bool
Deshace el punto de guardado dado
public function sharedLock(
string $sqlQuery
): string
Devuelve un SQL modificado con la cláusula LOCK IN SHARE MODE
public function setNestedTransactionsWithSavepoints(
bool $nestedTransactionsWithSavepoints
): AdapterInterface
Establece si las transacciones anidadas deberían usar puntos de guardado
public function supportsDefaultValue(): bool
Check whether the database system supports a default value
public function supportSequences(): bool
Comprueba si el sistema de base de datos necesita una secuencia para producir valores autonuméricos
public function tableExists(
string $tableName,
string $schemaName = null
): bool
Generates SQL checking for the existence of a schema.table
public function tableOptions(
string $tableName,
string $schemaName = null
): array
Obtiene las opciones de creación de una tabla
public function update(
string $table,
mixed $fields,
mixed $values,
mixed $whereCondition = null,
mixed $dataTypes = null
): bool
Actualiza datos en una tabla usando sintaxis SQL personalizada del RDBMS
public function updateAsDict(
string $table,
mixed $data,
mixed $whereCondition = null,
mixed $dataTypes = null
): bool
Actualiza datos en una tabla usando sintaxis SQL personalizada del RBDM. Otra sintaxis más conveniente
$success = $connection->updateAsDict(
'co_invoices',
[
'inv_title' => 'Invoice for ACME Inc.',
],
'inv_id = 1'
)
// SQL
// UPDATE `co_invoices`
// SET `inv_title` = 'Invoice for ACME Inc.'
// WHERE inv_id = 1
public function useExplicitIdValue(): bool
Comprueba si el sistema de base de datos necesita un valor explícito para columnas identidad
public function viewExists(
string $viewName,
string $schemaName = null
): bool
Genera SQL que comprueba la existencia de un esquema vista
Personalizado
The Phalcon\Db\AdapterInterface interface must be implemented in order to create your own database adapters or extend the existing ones. Additionally, you can extend the Phalcon\Db\AbstractAdapter that already has some implementation for your custom adapter.
Escape
El escapado de identificadores está habilitado por defecto. Sin embargo, si necesita deshabilitar esta característica, puede hacerlo usando el método setup()
:
<?php
\Phalcon\Db::setup(
[
'escapeIdentifiers' => false,
]
);
Fábrica (Factory)
newInstance()
Although all adapter classes can be instantiated using the new
keyword, Phalcon offers the Phalcon\Db\Adapter\PdoFactory class, so that you can easily instantiate PDO adapter instances. Todos los adaptadores de arriba están registrados en la fábrica y son cargados perezosamente cuando se llaman. La fábrica le permite registrar clases de adaptadores (personalizados) adicionales. Lo único a considerar es elegir el nombre del adaptador en comparación con los existentes. Si define el mismo nombre, sobreescribirá el integrado. Los objetos son cacheados en la fábrica, así que si llama al método newInstance()
con los mismos parámetros durante la misma petición, recibirá el mismo objeto de vuelta.
The reserved names are:
El siguiente ejemplo muestra como puede crear un adaptador MySQL con la palabra clave new
o la fábrica:
<?php
use Phalcon\Db\Adapter\Pdo\MySQL;
$connection = new MySQL(
[
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'test',
]
);
<?php
use Phalcon\Db\Adapter\PdoFactory;
$factory = new PdoFactory();
$connection = $factory
->newInstance(
'mysql',
[
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'test',
]
)
;
load()
También puede usar el método load()
para crear un adaptador usando un objeto de configuración o un vector. El siguiente ejemplo usa un fichero ini
para instanciar la conexión de base de datos usando load()
.
[database]
host = TEST_DB_MYSQL_HOST
username = TEST_DB_MYSQL_USER
password = TEST_DB_MYSQL_PASSWD
dbname = TEST_DB_MYSQL_NAME
port = TEST_DB_MYSQL_PORT
charset = TEST_DB_MYSQL_CHARSET
adapter = mysql
<?php
use Phalcon\Config\Adapter\Ini;
use Phalcon\Di\Di;
use Phalcon\Db\Adapter\PdoFactory;
$container = new Di();
$config = new Ini('config.ini');
$container->set('config', $config);
$container->set(
'db',
function () {
return (new PdoFactory())->load($this->config->database);
}
);
Dialectos
Integrado
Phalcon encapsula los detalles específicos de cada motor de base de datos en dialectos. Phalcon\Db\Dialect provides common functions and SQL generator to the adapters.
Personalizado
The Phalcon\Db\DialectInterface interface must be implemented in order to create your own database dialects or extend the existing ones. También puede mejorar su dialecto actual añadiendo más comandos/métodos que PHQL entenderá. Por ejemplo cuando usa el adaptador MySQL, podría querer permitir que PHQL reconozca la sintaxis MATCH ... AGAINST ...
. Asociamos esa sintaxis con MATCH_AGAINST
Instanciamos el dialecto. Añadimos la función personalizada para que PHQL sepa que hacer cuando la encuentra durante el proceso de análisis. En el siguiente ejemplo, registramos una nueva función personalizada llamada MATCH_AGAINST
. Después de esto, todo lo que tenemos que hacer es añadir el objeto de dialecto personalizado a nuestra conexión.
<?php
use Phalcon\Db\Dialect\MySQL as SqlDialect;
use Phalcon\Db\Adapter\Pdo\MySQL as Connection;
$dialect = new SqlDialect();
$dialect->registerCustomFunction(
'MATCH_AGAINST',
function ($dialect, $expression) {
$arguments = $expression['arguments'];
return sprintf(
' MATCH (%s) AGAINST (%s)',
$dialect->getSqlExpression($arguments[0]),
$dialect->getSqlExpression($arguments[1])
);
}
);
$connection = new Connection(
[
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'test',
'dialectClass' => $dialect,
]
);
Ahora podemos usar esta nueva función en PHQL, que a su vez la traducirá a la sintaxis SQL apropiada:
<?php
$phql = '
SELECT *
FROM Invoices
WHERE MATCH_AGAINST(title, :pattern:)';
$posts = $modelsManager->executeQuery(
$phql,
[
'pattern' => $pattern,
]
);
NOTE: There are more examples on how to extend PHQL in the PHQL document.
Conectar
Para crear una conexión es necesario instanciar la clase adaptador. Sólo necesita un vector con los parámetros de conexión. El siguiente ejemplo muestra como crear una conexión pasando tanto parámetros obligatorios como opcionales:
Adaptador |
Parámetro |
Estado |
MySQL |
host |
obligatorio |
|
username |
obligatorio |
|
password |
obligatorio |
|
dbname |
obligatorio |
|
persistent |
opcional |
PostgreSQL |
host |
obligatorio |
|
username |
obligatorio |
|
password |
obligatorio |
|
dbname |
obligatorio |
|
schema |
opcional |
Sqlite |
dbname |
obligatorio |
Conectar a cada adaptador se puede lograr mediante la fábrica como se ha demostrado anteriormente o pasando las opciones relevantes al constructor de cada clase.
<?php
use Phalcon\Db\Adapter\Pdo\Mysql;
use Phalcon\Db\Adapter\Pdo\Postgresql;
use Phalcon\Db\Adapter\Pdo\Sqlite;
$config = [
'host' => '127.0.0.1',
'username' => 'mike',
'password' => 'sigma',
'dbname' => 'test_db',
];
$connection = new Mysql($config);
$config = [
'host' => 'localhost',
'username' => 'postgres',
'password' => 'secret1',
'dbname' => 'template',
];
$connection = new Postgresql($config);
$config = [
'dbname' => '/path/to/database.db',
];
$connection = new Sqlite($config);
Opciones PDO adicionales
Puede establecer opciones PDO en tiempo de conexión pasando el parámetro options
:
<?php
use Phalcon\Db\Adapter\Pdo\Mysql;
$connection = new Mysql(
[
'host' => 'localhost',
'username' => 'root',
'password' => 'sigma',
'dbname' => 'test_db',
'options' => [
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'",
PDO::ATTR_CASE => PDO::CASE_LOWER,
]
]
);
Crear
Para insertar una fila en la base de datos, puede usar SQL bruto o usar métodos presentes en el adaptador:
<?php
$sql = "
INSERT INTO `co_invoices`
( `inv_cst_id`, `inv_title` )
VALUES
( 1, 'Invoice for ACME Inc.' )
";
$success = $connection->execute($sql);
SQL en Bruto
<?php
$sql = '
INSERT INTO `co_invoices`
( `inv_cst_id`, `inv_title` )
VALUES
( ?, ? )
';
$success = $connection->execute(
$sql,
[
1,
'Invoice for ACME Inc.',
]
);
Marcadores de Posición
<?php
$success = $connection->insert(
'co_invoices',
[
1,
'Invoice for ACME Inc.',
],
[
'inv_cst_id',
'inv_title',
]
);
Generación dinámica
<?php
$success = $connection->insertAsDict(
'co_invoices',
[
'inv_cst_id' => 1,
'inv_title' => 'Invoice for ACME Inc.',
]
);
Generación dinámica (sintaxis alternativa)
Actualizar
Para actualizar una fila en la base de datos, puede usar SQL bruto o usar los métodos presentes en el adaptador:
<?php
$sql = "
UPDATE
`co_invoices`
SET
`inv_cst_id`= 1,
`inv_title` = 'Invoice for ACME Inc.'
WHERE
`inv_id` = 4
";
$success = $connection->execute($sql);
SQL en Bruto
<?php
$sql = "
UPDATE
`co_invoices`
SET
`inv_cst_id`= ?,
`inv_title` = ?
WHERE
`inv_id` = ?
";
$success = $connection->execute(
$sql,
[
1,
'Invoice for ACME Inc.',
4,
]
);
Marcadores de Posición
<?php
$success = $connection->update(
'co_invoices',
[
'inv_cst_id',
'inv_title',
],
[
1,
'Invoice for ACME Inc.',
],
'inv_id = 4'
);
Generación dinámica
NOTE: With the syntax above, the variables for the where
part of the update
(inv_id = 4
) is not escaped!
<?php
$success = $connection->updateAsDict(
'co_invoices',
[
'inv_cst_id' => 1,
'inv_title' => 'Invoice for ACME Inc.',
],
'inv_id = 4'
);
Generación dinámica (sintaxis alternativa)
NOTE: With the syntax above, the variables for the where
part of the update
(inv_id = 4
) is not escaped!
<?php
$success = $connection->update(
'co_invoices',
[
'inv_cst_id',
'inv_title',
],
[
1,
'Invoice for ACME Inc.',
],
[
'conditions' => 'id = ?',
'bind' => [
4
],
'bindTypes' => [
\PDO::PARAM_INT
],
]
);
Con condicionales escapados
<?php
$success = $connection->updateAsDict(
'co_invoices',
[
'inv_cst_id' => 1,
'inv_title' => 'Invoice for ACME Inc.',
],
[
'conditions' => 'id = ?',
'bind' => [
4
],
'bindTypes' => [
\PDO::PARAM_INT
],
]
);
Con condicionales escapados (sintaxis alternativa)
Eliminar
<?php
$sql = '
DELETE
`co_invoices`
WHERE
`inv_id` = 4
';
$success = $connection->execute($sql);
SQL en Bruto
<?php
$sql = '
DELETE
`co_invoices`
WHERE
`inv_id` = ?
';
$success = $connection->execute(
$sql,
[
4
]
);
Marcadores de Posición
<?php
$success = $connection->delete(
'co_invoices',
'inv_id = ?',
[
4,
]
);
Generación dinámica
Parámetros
Los adaptadores Phalcon\Db
proporcionan varios métodos para consultar filas desde tablas. En este caso se necesita la sintaxis SQL especifica para el motor de base de datos destino:
<?php
$sql = '
SELECT
inv_id,
inv_title
FROM
co_invoices
ORDER BY
inv_created_at
';
$result = $connection->query($sql);
while ($invoice = $result->fetch()) {
echo $invoice['inv_title'];
}
$invoices = $connection->fetchAll($sql);
foreach ($invoices as $invoice) {
echo $invoice['inv_title'];
}
$invoice = $connection->fetchOne($sql);
By default, these calls create arrays with both associative and numeric indexes. Puede cambiar este comportamiento usando Phalcon\Db\Result::setFetchMode()
. Este método recibe una constante, que define qué tipo de índice se necesita.
Constante |
Descripción |
Phalcon\Db\Enum::FETCH_NUM |
Devuelve un vector con índices numéricos |
Phalcon\Db\Enum::FETCH_ASSOC |
Devuelve un vector con índices asociativos |
Phalcon\Db\Enum::FETCH_BOTH |
Devuelve un vector con ambos índices asociativos y numéricos |
Phalcon\Db\Enum::FETCH_OBJ |
Devuelve un objeto en vez de un vector |
<?php
$sql = '
SELECT
inv_id,
inv_title
FROM
co_invoices
ORDER BY
inv_created_at
';
$result = $connection->query($sql);
$result->setFetchMode(
Phalcon\Db\Enum::FETCH_NUM
);
while ($invoice = $result->fetch()) {
echo $invoice[0];
}
The query()
method returns an instance of Phalcon\Db\Result\Pdo. Estos objetos encapsulan toda la funcionalidad relativa a el conjunto de resultados devuelto, ej. recorrer, buscar registros específicos, contar, etc.
<?php
$sql = '
SELECT
inv_id,
inv_title
FROM
co_invoices
ORDER BY
inv_created_at
';
$result = $connection->query($sql);
while ($invoice = $result->fetch()) {
echo $invoice['name'];
}
$result->seek(2);
$invoice = $result->fetch();
echo $result->numRows();
Enlazar
Los parámetros enlazados también se soportan. Although there is a minimal performance impact by using bound parameters, you are highly encouraged to use this methodology to eliminate the possibility of your code being subject to SQL injection attacks. Se soportan tanto cadenas como marcadores de posición.
<?php
$sql = '
SELECT
inv_id,
inv_title
FROM
co_invoices
WHERE
inv_cst_id = ?
ORDER BY
inv_created_at
';
$result = $connection->query(
$sql,
[
4,
]
);
Enlazando con marcadores de posición numéricos
<?php
$sql = "
UPDATE
`co_invoices`
SET
`inv_cst_id`= :cstId,
`inv_title` = :title
WHERE
`inv_id` = :id
";
$success = $connection->query(
$sql,
[
'cstId' => 1,
'title' => 'Invoice for ACME Inc.',
'id' => 4,
]
);
Enlazando con marcadores de posición nombrados
Cuando se usan marcadores de posición numéricos, necesitará definirlos como enteros, ej. 1
o 2
. En este caso '1'
o '2'
se consideran cadenas y no números, con lo que el marcador de posición no se podría reemplazar correctamente. With any adapter, data are automatically escaped using PDO Quote. This function takes into account the connection charset, therefore it is recommended to define the correct charset in the connection parameters or in your database server configuration, as a wrong charset will produce undesired effects when storing or retrieving data.
Además, puede pasar sus parámetros directamente a los métodos execute
o query
. En este caso los parámetros enlazados se pasan directamente a PDO:
<?php
$sql = '
SELECT
inv_id,
inv_title
FROM
co_invoices
WHERE
inv_cst_id = ?
ORDER BY
inv_created_at
';
$result = $connection->query(
$sql,
[
1 => 4,
]
);
Enlazando con marcadores de posición PDO
Tipado
Los marcadores de posición le permiten enlazar parámetros para evitar inyecciones SQL:
<?php
$phql = '
SELECT
inv_id,
inv_title
FROM
Invoices
WHERE
inv_cst_id = :customerId:
ORDER BY
inv_created_at
';
$invoices = $this
->modelsManager
->executeQuery(
$phql,
[
'customerId' => 4,
]
)
;
Sin embargo, algunos sistemas de base de datos requieren acciones adicionales cuando se usan marcadores de posición como especificar el tipo del parámetro enlazado:
<?php
use Phalcon\Db\Column;
// ...
$phql = '
SELECT
inv_id,
inv_title
FROM
Invoices
WHERE
inv_cst_id = :customerId:
ORDER BY
inv_created_at
';
$invoices = $this
->modelsManager
->executeQuery(
$phql,
[
'customerId' => 4,
],
Column::BIND_PARAM_INT
)
;
Puede usar marcadores de posición tipados en sus parámetros, en vez de especificar el tipo de enlace en executeQuery()
:
<?php
$phql = '
SELECT
inv_id,
inv_title
FROM
Invoices
WHERE
inv_cst_id = {customerId:int}
ORDER BY
inv_created_at
';
$invoices = $this
->modelsManager
->executeQuery(
$phql,
[
'customerId' => 4,
],
)
;
$phql = '
SELECT
inv_id,
inv_title
FROM
Invoices
WHERE
inv_title <> {title:str}
ORDER BY
inv_created_at
';
$invoices = $this
->modelsManager
->executeQuery(
$phql,
[
'title' => 'Invoice for ACME Inc',
],
)
;
También puede omitir el tipo si no necesita especificarlo:
<?php
$phql = '
SELECT
inv_id,
inv_title
FROM
Invoices
WHERE
inv_cst_id = {customerId}
ORDER BY
inv_created_at
';
$invoices = $this
->modelsManager
->executeQuery(
$phql,
[
'customerId' => 4,
],
)
;
Los marcadores de posición tipados también son más poderosos, ya que ahora podemos enlazar un vector estático sin tener que pasar cada elemento independientemente como marcador de posición:
<?php
$phql = '
SELECT
inv_id,
inv_title
FROM
Invoices
WHERE
inv_cst_id IN ({ids:array})
ORDER BY
inv_created_at
';
$invoices = $this
->modelsManager
->executeQuery(
$phql,
[
'ids' => [1, 3, 5],
],
)
;
Están disponibles los siguientes tipos:
Tipo de enlace |
Constante de Tipo de Enlace |
Ejemplo |
str |
Column::BIND_PARAM_STR |
{name:str} |
int |
Column::BIND_PARAM_INT |
{number:int} |
double |
Column::BIND_PARAM_DECIMAL |
{price:double} |
bool |
Column::BIND_PARAM_BOOL |
{enabled:bool} |
blob |
Column::BIND_PARAM_BLOB |
{image:blob} |
null |
Column::BIND_PARAM_NULL |
{exists:null} |
array |
Vector de Column::BIND_PARAM_STR |
{codes:array} |
array-str |
Vector de Column::BIND_PARAM_STR |
{names:array-str} |
array-int |
Vector de Column::BIND_PARAM_INT |
{flags:array-int} |
Cambio de Tipo
By default, bound parameters are not cast in the PHP userland to the specified bind types. Esta opción le permite hacer que Phalcon convierta los valores antes de enlazarlos con PDO. Un escenario común es pasar una cadena en un marcador de posición LIMIT
/OFFSET
:
<?php
$number = '100';
$phql = '
SELECT
inv_id,
inv_title
FROM
Invoices
LIMIT
{number:int}
';
$invoices = $modelsManager->executeQuery(
$phql,
[
'number' => $number,
]
);
Esto causa la siguiente excepción:
Fatal error: Uncaught exception 'PDOException' with message
'SQLSTATE[42000]: Syntax error or access violation: 1064.
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right
syntax to use near ''100'' at line 1' in ....
Esto ocurre porque '100'
es una variable cadena. Es fácil de arreglar al convertir primero el valor a entero:
<?php
$number = '100';
$phql = '
SELECT
inv_id,
inv_title
FROM
Invoices
LIMIT
{number:int}
';
$invoices = $modelsManager->executeQuery(
$phql,
[
'number' => (int) $number,
]
);
However, this solution requires that the developer pays special attention about how bound parameters are passed and their types. Para facilitar la tarea y evitar excepciones inesperadas puede instruir a Phalcon para que haga la conversión de tipos por usted:
<?php
\Phalcon\Db::setup(
[
'forceCasting' => true,
]
);
Las siguientes acciones se realizan de acuerdo al tipo de enlace especificado:
Tipo de enlace |
Acción |
Column::BIND_PARAM_STR |
Convierte el valor como una cadena PHP nativa |
Column::BIND_PARAM_INT |
Convierte el valor como un entero PHP nativo |
Column::BIND_PARAM_BOOL |
Convierte el valor como un booleano PHP nativo |
Column::BIND_PARAM_DECIMAL |
Convertir el valor como un número de doble precisión PHP nativo |
Hidración
Los valores devueltos del sistema de base de datos siempre se representan como valores cadena por el PDO, no importa si el valor pertenece a una columna de tipo numérico
o booleano
. Esto ocurre porque algunos tipos de columna no se pueden representar con sus correspondientes tipos nativos de PHP debido a sus limitaciones de tamaño. Por ejemplo, un BIGINT
en MySQL puede almacenar números enteros que no se pueden representar como un entero de 32bit en PHP. Por eso, PDO y ORM por defecto, toman la decisión segura de dejar todos los valores como cadenas.
Puede configurar el ORM para que automáticamente convierta aquellos tipos a sus correspondientes tipos nativos de PHP:
<?php
use Phalcon\Mvc\Model;
Model::setup(
[
'castOnHydrate' => true,
]
);
De esta forma puede usar operaciones estrictas o hacer suposiciones sobre el tipo de las variables:
<?php
$invoice = Invoices::findFirst();
if (11 === $invoice->inv_id) {
echo $invoice->inv_title;
}
NOTE: If you wish to return the primary key when using the lastInsertId
as an integer
, you can use the castLastInsertIdToInt => true
feature on the model.
Transacciones
Working with transactions is supported the same way as with PDO. Usar transacciones incrementa el rendimiento en la mayoría de sistemas de base de datos y también asegura la integridad de los datos:
<?php
try {
$connection->begin();
$connection->execute('DELETE `co_invoices` WHERE `inv_id` = 1');
$connection->execute('DELETE `co_invoices` WHERE `inv_id` = 2');
$connection->execute('DELETE `co_invoices` WHERE `inv_id` = 3');
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
}
In addition to standard transactions, the adapters offer provides built-in support for nested transactions, if the database system used supports them. Cuando llama begin()
por segunda vez se crea una transacción anidada:
<?php
try {
$connection->begin();
$connection->execute('DELETE `co_invoices` WHERE `inv_id` = 1');
try {
$connection->begin();
$connection->execute('DELETE `co_invoices` WHERE `inv_id` = 2');
$connection->execute('DELETE `co_invoices` WHERE `inv_id` = 3');
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
}
$connection->execute('DELETE `co_invoices` WHERE `inv_id` = 4');
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
}
Eventos
Los adaptadores también envían eventos a un Gestor de Eventos si está presente. Si un evento devuelve false
puede detener la operación actual. Se soportan los siguientes eventos:
Nombre de evento |
Disparado |
Puede detenerse |
afterQuery |
Después de ejecutar una consulta |
No |
beforeQuery |
Antes de ejecutar una consulta |
Si |
beginTransaction |
Antes de iniciar una transacción |
No |
createSavepoint |
Antes de crear un punto de guardado |
No |
commitTransaction |
Antes de confirmar una transacción |
No |
releaseSavepoint |
Antes de lanzar un punto de guardado |
No |
rollbackTransaction |
Antes de deshacer una transacción |
No |
rollbackSavepoint |
Antes de deshacer un punto de guardado |
No |
Si enlaza un Gestor de Eventos a la conexión de base de datos, se activarán y dispararán todos los eventos con el tipo db
para los oyentes relevantes.
<?php
use Phalcon\Events\Manager;
use Phalcon\Db\Adapter\Pdo\Mysql;
$manager = new Manager();
$manager->attach('db', $listener);
$connection = new Mysql(
[
'host' => 'localhost',
'username' => 'root',
'password' => 'secret',
'dbname' => 'tutorial',
]
);
$connection->setEventsManager($manager);
Puede usar el poder de estos eventos para proteger su aplicación de operaciones SQL peligrosas.
<?php
use Phalcon\Events\Event;
$manager->attach(
'db:beforeQuery',
function (Event $event, $connection) {
$sql = $connection->getSQLStatement();
if (true === preg_match('/DROP|ALTER/i', $sql)) {
return false;
}
return true;
}
);
Perfilado
The adapter includes the Phalcon\Db\Profiler component, that is used to analyze the performance of database operations to diagnose performance problems and discover bottlenecks.
<?php
use Phalcon\Events\Event;
use Phalcon\Events\Manager;
use Phalcon\Db\Profiler;
$manager = new Manager();
$profiler = new Profiler();
$manager->attach(
'db',
function (Event $event, $connection) use ($profiler) {
if ($event->getType() === 'beforeQuery') {
$sql = $connection->getSQLStatement();
$profiler->startProfile($sql);
}
if ($event->getType() === 'afterQuery') {
$profiler->stopProfile();
}
}
);
$connection->setEventsManager($manager);
$sql = '
SELECT
inv_id,
inv_title
FROM
co_invoices
';
$connection->query($sql);
$profile = $profiler->getLastProfile();
echo 'SQL Statement: ', $profile->getSQLStatement(), PHP_EOL,
'Start Time: ', $profile->getInitialTime(), PHP_EOL,
'Final Time: ', $profile->getFinalTime(), PHP_EOL,
'Total Elapsed Time: ', $profile->getTotalElapsedSeconds(), PHP_EOL;
The profiler exposes the getProfiles()
method, returning an array of Phalcon\Db\Profiler\Item
objects. Each object contains relevant statistics, including calculations for seconds, microseconds and nanoseconds.
You can also create your own profile class based on the Phalcon\Db\Profiler class to record real time statistics of the statements that are sent to the database:
<?php
use Phalcon\Events\Manager;
use Phalcon\Db\Profiler;
use Phalcon\Db\Profiler\Item;
class DbProfiler extends Profiler
{
public function beforeStartProfile(Item $profile)
{
echo $profile->getSQLStatement();
}
public function afterEndProfile(Item $profile)
{
echo $profile->getTotalElapsedSeconds();
}
}
$manager = new Manager();
$listener = new DbProfiler();
$manager->attach('db', $listener);
Registro
Usar componentes de abstracción de alto nivel como los adaptadores Phalcon\Db
para acceder a la base de datos, hace difícil entender qué sentencias se envían al sistema de base de datos. The Phalcon\Logger\Logger component interacts with the Phalcon\Db
adapters offering logging capabilities on the database abstraction level.
<?php
use Phalcon\Events\Event;
use Phalcon\Events\Manager;
use Phalcon\Logger\Logger;
use Phalcon\Logger\Adapter\Stream;
$adapter = new Stream('/storage/logs/queries.log');
$logger = new Logger(
'messages',
[
'main' => $adapter,
]
);
$manager = new Manager();
$manager->attach(
'db:beforeQuery',
function (Event $event, $connection) use ($logger) {
$sql = $connection->getSQLStatement();
$logger->info(
sprintf(
'%s - [%s]',
$connection->getSQLStatement(),
json_encode($connection->getSQLVariables())
)
);
}
);
$connection->setEventsManager($manager);
$connection->insert(
'products',
[
'Hot pepper',
3.50,
],
[
'name',
'price',
]
);
$connection->insert(
'co_invoices',
[
1,
'Invoice for ACME Inc.',
],
[
'inv_cst_id',
'inv_title',
]
);
Como en el ejemplo anterior, el fichero /storage/logs/queries.log
contendrá algo similar a:
[2019-12-25 01:02:03][INFO] INSERT INTO `co_invoices`
SET (`inv_cst_id`, `inv_title`)
VALUES (1, 'Invoice for ACME Inc.')
El oyente también trabajará con modelos y sus operaciones. También incluirá todos los parámetros enlazados que use la consulta al final de la sentencia registrada.
[2019-12-25 01:02:03][INFO] SELECT `co_customers`.`cst_id`,
...,
FROM `co_customers`
WHERE LOWER(`co_customers`.`cst_email`) = :cst_email
LIMIT :APL0 - [{"emp_email":"[email protected]","APL0":1}]
Tablas
Describir
Los adaptadores Phalcon\Db
también proporcionan métodos para obtener información detallada sobre tablas y vistas:
<?php
$tables = $connection->listTables('phalcon_db');
Get tables on the phalcon_db
database
<?php
$exists = $connection->tableExists('co_invoices');
¿Comprueba si hay una tabla llamada co_invoices
en la base de datos?
<?php
$fields = $connection->describeColumns('co_invoices');
foreach ($fields as $field) {
echo 'Column Type: ', $field['Type'];
}
Imprime el nombre y los tipos de datos de la tabla co_invoices
<?php
$indexes = $connection->describeIndexes('co_invoices');
foreach ($indexes as $index) {
print_r(
$index->getColumns()
);
}
Imprime los índices de la tabla co_invoices
<?php
$references = $connection->describeReferences('co_invoices');
foreach ($references as $reference) {
print_r(
$reference->getReferencedColumns()
);
}
Imprime las claves ajenas en la tabla co_invoices
Una descripción de tabla es muy similar al comando de MySQL DESCRIBE
, contiene la siguiente información:
Campo |
Tipo |
Clave |
Null |
Nombre del campo |
Tipo de Columna |
¿La columna forma parte de una clave primaria o índice? |
¿Permite la columna valores nulos? |
También se han implementado métodos para obtener información sobre vistas para cada sistema de base de datos soportado:
<?php
$tables = $connection->listViews('phalcon_db');
Get views on the phalcon_db
database
<?php
$exists = $connection->viewExists('vw_invoices');
Comprueba si hay una vista vw_invoices
en la base de datos
Crear
Diferentes sistemas de base de datos (MySQL, Postgresql etc.) ofrecen la capacidad de crear, alterar o eliminar tablas cuando se usan comandos como CREATE
, ALTER
o DROP
. La sintaxis SQL difiere en base al sistema de base de datos usado. Los adaptadores Phalcon\Db
ofrecen un interfaz unificado para alterar tablas, sin necesidad de diferenciar la sintaxis SQL basada en el sistema de almacenamiento de destino.
A continuación se muestra un ejemplo de como crear una tabla:
<?php
use \Phalcon\Db\Column as Column;
$connection->createTable(
'co_invoices',
null,
[
'columns' => [
new Column(
'inv_id',
[
'type' => Column::TYPE_INTEGER,
'size' => 10,
'notNull' => true,
'autoIncrement' => true,
'primary' => true,
]
),
new Column(
'inv_cst_id',
[
'type' => Column::TYPE_INTEGER,
'size' => 11,
'notNull' => true,
]
),
new Column(
'inv_title',
[
'type' => Column::TYPE_VARCHAR,
'size' => 100,
'notNull' => true,
]
),
]
]
);
El método createTable
acepta un vector asociativo que describe la tabla. Columns are defined with the class Phalcon\Db\Column. La tabla siguiente muestra las opciones disponibles para definir una columna:
Opción |
Descripción |
Opcional |
after |
La columna debe colocarse después de la columna indicada |
Si |
autoIncrement |
Indica si esta columna será autoincrementada por la base de datos. Sólo una columna en la tabla puede tener este atributo. |
Si |
bind |
Una de las constantes BIND_TYPE_* indica como se debe enlazar la columna antes de guardarla |
Si |
default |
Valor predeterminado (cuando se usa con 'notNull' => true ). |
Si |
first |
La columna se debe colocar en la primera posición en el orden de columna |
Si |
notNull |
La columna puede almacenar valores nulos |
Si |
primary |
true si la columna forma parte de la clave primaria de la tabla |
Si |
scale |
Columnas DECIMAL o NUMBER pueden tener una escala para especificar cuántos decimales deben almacenar |
Si |
size |
Algunos tipos de columnas como VARCHAR o INTEGER pueden tener un tamaño específico |
Si |
type |
Tipo de columna. Must be a Phalcon\Db\Column constant (see below for a list) |
No |
unsigned |
Las columnas INTEGER pueden ser signed o unsigned . Esta opción no se aplica a otros tipos de columnas |
Si |
Se soportan por los adaptadores los siguientes tipos de columnas de base de datos:
Phalcon\Db\Column::TYPE_INTEGER
Phalcon\Db\Column::TYPE_DATE
Phalcon\Db\Column::TYPE_VARCHAR
Phalcon\Db\Column::TYPE_DECIMAL
Phalcon\Db\Column::TYPE_DATETIME
Phalcon\Db\Column::TYPE_CHAR
Phalcon\Db\Column::TYPE_TEXT
El vector asociativo pasado en createTable()
puede tener las siguientes claves:
Índice |
Descripción |
Opcional |
columns |
An array with columns defined with Phalcon\Db\Column |
No |
indexes |
An array with indexes defined with Phalcon\Db\Index |
Si |
references |
An array with references (foreign keys) defined with Phalcon\Db\Reference |
Si |
options |
Un vector con opciones de creación. (específicas al sistema de base de datos) |
Si |
Alterar
A medida que su aplicación crece, podría necesitar alterar su base de datos, como parte de una refactorización o añadido de nuevas características. No todos los sistemas de base de datos permiten modificar columnas existentes o añadir columnas entre dos de las existentes. Phalcon\Db is limited by these constraints.
<?php
use Phalcon\Db\Column as Column;
$connection->addColumn(
'co_invoices',
null,
new Column(
'inv_status_flag',
[
'type' => Column::TYPE_INTEGER,
'size' => 1,
'notNull' => true,
'default' => 0,
'after' => 'inv_cst_id',
]
)
);
$connection->modifyColumn(
'co_invoices',
null,
new Column(
'inv_status_flag',
[
'type' => Column::TYPE_INTEGER,
'size' => 2,
'notNull' => true,
]
)
);
$connection->dropColumn(
'co_invoices',
null,
'inv_status_flag'
);
Eliminar
Para eliminar una tabla existente de la base de datos actual, use el método dropTable
. To drop a table from a custom database, you can use the second parameter to set the database name.
<?php
$connection->dropTable('co_invoices');
Elimina la tabla co_invoices
de la base de datos activa
<?php
$connection->dropTable('co_invoices', 'phalcon_db');
Drop the table co_invoices
from the database phalcon_db