Files
yii/docs/guide/pt/database.dao.txt
2009-12-13 16:48:49 +00:00

240 lines
9.9 KiB
Plaintext

Data Access Objects (DAO)
=========================
Data Access Objects (DAO, Objetos de Acesso a Dados), fornecem uma API genérica
para acessar dados em diferentes tipos de bancos de dados. Como resultado, pode-se
alterar o sistema de banco de dados sem haver a necessidade de alterar o código
que utiliza DAO para fazer o acesso.
O DAO do Yii é feito utilizando a extensão [PHP Data Objects (PDO)](http://php.net/manual/en/book.pdo.php),
que fornece um acesso de dados unificado para muitos SGBD populares, tais como
MySQL e PostgreSQL. Por esse motivo, para utilizar o DAO no Yii, a extensão PDO
deve estar instalada, bem como o driver PDO específico para o banco de dados
utilizado (por exemplo, `PDO_MYSQL`).
O DAO no Yii, consiste, basicamente, das quatro classes seguinte:
- [CDbConnection]: representa uma conexão com o banco de dados.
- [CDbCommand]: representa uma instrução SQL a ser executada no banco de dados.
- [CDbDataReader]: representa um conjunto de registros retornados, navegável apenas para frente.
- [CDbTransaction]: representa uma transação (transaction) no banco de dados.
A seguir, apresentaremos a utilização do DAO no Yii em diferente cenários.
Estabelecendo uma Conexão com o Banco de Dados
----------------------------------------------
Para estabelecer uma conexão com o banco de dados, criamos uma instância de
[CDbConnection] e a ativamos. É necessário o nome da fonte de dados (data source
name, DSN) para conectar-se ao banco. Também podem ser necessários o nome de
usuário e senha para o acesso. Uma exceção será disparada caso ocorra um erro
ao estabelecer a conexão (por exemplo, um DSN incorreto, ou usuário/senha inválidos).
~~~
[php]
$connection=new CDbConnection($dsn,$username,$password);
// estabelece a conexão. Você pode utilizar um try... catch tratar exceções
$connection->active=true;
......
$connection->active=false; // fecha a conexão
~~~
O formato do DSN depende do driver PDO em uso. Geralmente, o DSN é formado pelo nome
do driver PDO, seguido por ":", seguido pela sintaxe de conexão específica do driver.
Veja [PDO documentation](http://www.php.net/manual/en/pdo.construct.php) para mais
informações. Abaixo temos uma lista dos formatos de DSN mais utilizados:
- SQLite: `sqlite:/path/to/dbfile`
- MySQL: `mysql:host=localhost;dbname=testdb`
- PostgreSQL: `pgsql:host=localhost;port=5432;dbname=testdb`
- SQL Server: `mssql:host=localhost;dbname=testdb`
- Oracle: `oci:dbname=//localhost:1521/testdb`
Como a classe [CDbConnection] estende a classe [CApplicationComponent], podemos
utiliza-la como um [componente da aplicação](/doc/guide/basics.application#application-component).
Para isso, configure um componente chamado `db` (ou qualquer outro nome) na
[configuração da aplicação](/doc/guide/basics.application#application-configuration),
como no código a seguir:
~~~
[php]
array(
......
'components'=>array(
......
'db'=>array(
'class'=>'CDbConnection',
'connectionString'=>'mysql:host=localhost;dbname=testdb',
'username'=>'root',
'password'=>'password',
'emulatePrepare'=>true, // necessário em algumas instalações do MySQL
),
),
)
~~~
Podemos então acessar a conexão com o banco via `Yii::app()->db`, que é
ativada automaticamente, a não ser que se configure a propriedade
[CDbConnection::autoConnect] para false. Dessa maneira, uma única conexão com o
banco de dados pode ser compartilhada entre diversas partes de seu código.
Executando Instruções SQL
-------------------------
Uma vez que a conexão com o banco de dados tenha sido estabelecida, comandos SQL
podem ser executados utilizando-se a classe [CDbCommand]. Você pode criar uma
instância de [CDbCommand] utilizando o método [CDbConnection::createCommand()],
com a instrução SQL desejada:
~~~
[php]
$command=$connection->createCommand($sql);
// se necessário, a instrução SQL pode ser alterada da seguinte maneira:
// $command->text=$newSQL;
~~~
Uma instrução SQL pode ser executada via [CDbCommand] de duas maneiras:
- [execute()|CDbCommand::execute]: executa uma instrução SQL que não retorna
resultados, tal como `INSERT`, `UPDATE` e `DELETE`. Em caso de sucesso, retorna
a quantidade de registros afetados pela consulta.
- [query()|CDbCommand::query]: executa uma instrução que retorna registros,
tal como `SELECT`. Em caso de sucesso, retorna uma instância de [CDbDataReader],
que pode ser utilizada para acessar os registros encontrados. Por conveniência,
um conjunto de métodos `queryXXX()` também está implementado, e retornam
diretamente o resultado da consulta.
Uma exceção será disparada caso ocorram erros durante a execução de instruções
SQL.
~~~
[php]
$rowCount=$command->execute(); // executa uma consulta que não retorna resultados
$dataReader=$command->query(); // executa uma consulta SQL
$rows=$command->queryAll(); // consulta e retorna todos os resultados encontrados
$row=$command->queryRow(); // consulta e retorna apenas o primeiro registro do resultado
$column=$command->queryColumn(); // consulta e retorna a primeira coluna do resultado
$value=$command->queryScalar(); // consulta e retorna o primeiro campo do primeiro registro
~~~
Obtendo Resultados de Consultas
-------------------------------
Depois que o método [CDbCommand::query()] gerar uma instância de [CDbDataReader],
você pode recuperar os registros do resultado através do método [CDbDataReader::read()],
repetidamente. Você também pode utilizar um [CDbDataReader] dentro de um loop
`foreach`, para recuperar os registros, um a um:
~~~
[php]
$dataReader=$command->query();
// executando read() repetidamente, até que ele retorne false
while(($row=$dataReader->read())!==false) { ... }
// utilizando foreach para "navegar" por cada registro encontrado
foreach($dataReader as $row) { ... }
// recuperando todos os registros de uma vez, em um vetor
$rows=$dataReader->readAll();
~~~
> Note|Nota: Diferente do método [query()|CDbCommand::query], todos os métodos
`queryXXX()`, retornam os dados diretamente. Por exemplo, o método
[queryRow()|CDbCommand::queryRow] retorna um vetor representando o primeiro
registro do resultado da consulta.
Utilizando Transações (Transactions)
------------------------------------
Quando uma aplicação executa algumas consultas, seja lendo ou gravando informações
no banco de dados, é importante garantir que todas as consultas tenham sido executadas.
Nesse caso, uma transação, representada por uma instância de [CDbTransaction],
pode ser iniciada:
- Inicie a transação.
- Execute as consultas, uma a uma. Todas as atualizações no banco de dados
não são visíveis aos outros.
- Encerre a transação. Nesse momento, as atualizações tornam-se visíveis, caso a
transação tenha encerrado com sucesso.
- Se uma das consultas falhar, toda a transação é desfeita.
O fluxo acima pode ser implementado como no código a seguir:
~~~
[php]
$transaction=$connection->beginTransaction();
try
{
$connection->createCommand($sql1)->execute();
$connection->createCommand($sql2)->execute();
//.... outras execuções de comandos SQL
$transaction->commit();
}
catch(Exception $e) // uma exceção é disparada caso uma das consultas falhe
{
$transaction->rollBack();
}
~~~
Vinculando (Binding) Parâmetros
-------------------------------
Para evitar ataques de [SQL injection](http://en.wikipedia.org/wiki/SQL_injection)
e aumentar a performance ao executar instruções SQL repetidamente, você pode
"preparar" um comando SQL com marcadores opcionais que serão substituídos pelos
valores reais, durante o processo de vinculação de parâmetros.
Os marcadores de parâmetros podem ser nomeados (representados por tokens únicos)
ou anônimos (representados por interrogações). Execute o método [CDbCommand::bindParam()]
ou [CDbCommand::bindValue()] para substituir esses marcadores pelos parâmetros reais.
Eles não precisam estar entre aspas: o próprio driver do banco de dados faz isso para você.
A vinculação de parâmetros deve ser realizada antes da instrução SQL ser executada.
~~~
[php]
// uma consulta com dois marcadores ":username" e ":email"
$sql="INSERT INTO users(username, email) VALUES(:username,:email)";
$command=$connection->createCommand($sql);
// substitui o marcador ":username" com o valor atual de $username
$command->bindParam(":username",$username,PDO::PARAM_STR);
// substitui o marcador ":email" com o valor atual de $email
$command->bindParam(":email",$email,PDO::PARAM_STR);
$command->execute();
// insere um novo registro com um novo conjunto de parâmetros
$command->bindParam(":username",$username2,PDO::PARAM_STR);
$command->bindParam(":email",$email2,PDO::PARAM_STR);
$command->execute();
~~~
Os métodos [bindParam()|CDbCommand::bindParam] e
[bindValue()|CDbCommand::bindValue] são similares. A única diferença entre eles
é que o primeiro vincula um parâmetro utilizando uma referência para a variável
enquanto o outro utilizar um valor. Para parâmetros que representem uma grande
quantidade de dados em memória, o primeiro é mais recomendado, devido a uma melhor
performance.
Para mais detalhes sobre a vinculação de parâmetros, veja a
[documentação do PHP](http://www.php.net/manual/en/pdostatement.bindparam.php).
Vinculando Colunas
------------------
Ao recuperar os resultados de uma consulta, você também pode vincular colunas à
variáveis, de forma que elas sejam automaticamente preenchidas cada vez que um
novo registro é recuperado:
~~~
[php]
$sql="SELECT username, email FROM users";
$dataReader=$connection->createCommand($sql)->query();
// vincula a 1ª coluna (username) à variável $username
$dataReader->bindColumn(1,$username);
// vincula a 2ª coluna (email) à variável $email
$dataReader->bindColumn(2,$email);
while($dataReader->read()!==false)
{
// $username e $email contém o nome de usuário e a senha do registro atual
}
~~~
<div class="revision">$Id: database.dao.txt 1479 2009-10-23 13:24:20Z qiang.xue $</div>