PHP MVCDOCUMENTAÇÃO
v2.0.0

Database e PDO

Consultas parametrizadas e transações quando Model/Repository não cobrem o caso necessário.

Escolha a camada de acesso

Use Model e Repository para operações de domínio, filtros e paginação. Framework\Database\Database é o acesso PDO direto para casos em que a API pequena do Model não expressa a consulta. Não há abstração SQLite nesta configuração: o driver entregue é MySQL.

Conexão e instruções preparadas

Database::getInstance() fornece a instância singleton. query($sql) prepara a instrução; encadeie bind($placeholder,$value,$type=null) e depois execute(). Os valores vão em parâmetros PDO, não por concatenação na string SQL.

use Framework\Database\Database;

$db = Database::getInstance();
$db->query('SELECT id, name FROM users WHERE email = :email')
   ->bind(':email', $email)
   ->execute();

$user = $db->fetch(); // object|false

Depois da execução, fetchAll() retorna linhas em array, fetch() retorna um objeto ou false, fetchColumn() retorna um valor misto, rowCount() um inteiro e lastInsertId() uma string. A configuração PDO usa exceções e hidrata linhas como objetos.

Transação com callback

Use a transação quando várias gravações precisarem ter êxito juntas. O callback recebe a instância Database; sucesso confirma, qualquer Throwable reverte e é relançado. A implementação não cria transações aninhadas.

$db->transaction(function (Database $tx) use ($email, $name): void {
    $tx->query('INSERT INTO users (email, name) VALUES (:email, :name)')
       ->bind(':email', $email)
       ->bind(':name', $name)
       ->execute();

    // Se outra operação lançar Throwable, o callback é revertido.
});

Métodos e retornos

MétodoRetornoUso/limite
query(string $sql): staticInstância encadeávelPrepara e seleciona a instrução.
bind(string $param, mixed $value, ?int $type = null): staticInstância encadeávelVincula parâmetro e tipo PDO opcional.
execute(): boolSucesso da execuçãoExecute após query e bind.
fetch(): object|falseUma linha ou falseUse após executar uma consulta com resultado.
fetchAll(): arrayLista de objetosUse para coleções.
fetchColumn(int $col = 0): mixedValor da colunaÍndice de coluna da próxima linha, começando em 0.
transaction(callable $callback): mixedRetorno do callbackCommit no sucesso; rollback e relança Throwable em falha.
execMigration(string $sql): int|falseLinhas afetadas ou falseExecução direta, destinada a DDL/migrations; não recebe bindings.
getPdo(): PDOConexão PDOEscape hatch; usar apenas quando a API do wrapper não basta.
SQL dinâmico: bindings protegem valores, não nomes de tabela/coluna nem trechos SQL. Schema e Blueprint interpolam identificadores em DDL; use identificadores constantes e confiáveis. execMigration() executa SQL cru sem prepared statement e não deve receber entrada do usuário.

Para consultas comuns, prefira Query Builder do Model; para evolução de schema, use migrations; para inserção de dados controlada, consulte seeders.

Fetch é uma operação terminal

fetch(), fetchAll() e fetchColumn() executam a consulta por conta própria. Não chame execute() antes e depois tente buscar o resultado como se o cursor fosse mantido nessa sequência; encadeie bindings diretamente ao terminal desejado:

$user = $db->query('SELECT id, email FROM users WHERE id = :id')
          ->bind(':id', $id)
          ->fetch();

Transação manual e callback

Além de transaction(callable $callback): mixed, a classe expõe beginTransaction(): bool, commit(): bool, rollback(): bool e inTransaction(): bool. Use o fluxo manual quando o escopo precisa atravessar várias operações explícitas:

$db->beginTransaction();
try {
    $db->query('UPDATE accounts SET balance = balance - :v WHERE id = :id')
       ->bind(':v', $amount)->bind(':id', $from)->execute();
    $db->query('UPDATE accounts SET balance = balance + :v WHERE id = :id')
       ->bind(':v', $amount)->bind(':id', $to)->execute();
    $db->commit();
} catch (\Throwable $e) {
    if ($db->inTransaction()) $db->rollback();
    throw $e;
}

beginTransaction() não implementa transações aninhadas/savepoints; não o chame como mecanismo de nesting. Para um bloco autocontido, prefira transaction(), que executa o callback e faz o controle de commit/rollback.