mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-06 00:04:07 +01:00
233 lines
9.2 KiB
Plaintext
233 lines
9.2 KiB
Plaintext
Data Access Objects (DAO)
|
|
=========================
|
|
|
|
DAO (Obiecte accesare date) pune la dispozitie un API generic pentru accesul
|
|
datelor stocate in diverse DBMS (Sisteme de Management Baze de Date).
|
|
Ca urmare, DBMS-ul poate fi schimbat oricand cu altul, fara sa fie nevoie
|
|
sa schimbam codul nostru in care folosim DAO sa accesam datele.
|
|
|
|
Yii DAO este construit pe baza [PDO](http://php.net/manual/en/book.pdo.php) (obiecte date PHP)
|
|
care este o extensie PHP ce pune la dispozitie accesul unificat la date stocate
|
|
in diverse DBMS cunoscute, precum MySQL si PostgreSQL. De aceea, pentru a folosi
|
|
Yii DAO, trebuie instalate extensia PDO si driverul PDO de baze de date specific
|
|
(ex. `PDO_MYSQL`).
|
|
|
|
Yii DAO este format in principal din urmatoarele patru clase:
|
|
|
|
- [CDbConnection]: reprezinta conexiunea la o baza de date.
|
|
- [CDbCommand]: reprezinta o instructiune SQL de executat.
|
|
- [CDbDataReader]: reprezinta un flux doar de citire de randuri dintr-un set de rezultate.
|
|
- [CDbTransaction]: reprezinta o tranzactie DB.
|
|
|
|
In cele ce urmeaza, explicam folosirea Yii DAO in diverse scenarii.
|
|
|
|
Stabilirea conexiunii la baza de date
|
|
-------------------------------------
|
|
|
|
Pentru a stabili o conexiune, cream o instanta [CDbConnection] si o activam.
|
|
Avem nevoie de un DSN (nume pentru sursa de date) pentru a specifica
|
|
informatiile necesare pentru conectarea la baza de date. Pot fi necesare si
|
|
un nume si o parola pentru stabilirea conexiunii. Va fi generata o exceptie
|
|
in cazul in care apare o eroare la stabilirea conexiunii (ex. DSN gresit sau
|
|
nume/parola gresite).
|
|
|
|
~~~
|
|
[php]
|
|
$connection=new CDbConnection($dsn,$username,$password);
|
|
// stabilirea conexiunii. Putem incerca try-catch pentru a identifica exceptii posibile
|
|
$connection->active=true;
|
|
......
|
|
$connection->active=false; // inchidere conexiune
|
|
~~~
|
|
|
|
Formatul DSN-ului depinde de driverul PDO folosit. In general,
|
|
DSN este format din numele driver-ului PDO, urmat de semnul `:`, urmat de sintaxa
|
|
conexiunii specifice driver-ului. Pentru informatii complete, trebuie vazuta
|
|
[documentatia PDO](http://www.php.net/manual/en/pdo.construct.php).
|
|
Mai jos este o lista de format-uri obisnuite pentru DSN:
|
|
|
|
- SQLite: `sqlite:/path/to/dbfile`
|
|
- MySQL: `mysql:host=localhost;dbname=testdb`
|
|
- PostgreSQL: `pgsql:host=localhost;port=5432;dbname=testdb`
|
|
|
|
Pentru ca [CDbConnection] este derivata din clasa [CApplicationComponent], o putem
|
|
folosi de asemenea pe postul de [componenta aplicatie](/doc/guide/basics.application#application-component).
|
|
Pentru a face acest lucru, configuram componenta aplicatie
|
|
`db` (sau alta componenta aplicatie, daca se doreste)
|
|
din [configurarea aplicatiei](/doc/guide/basics.application#application-configuration) dupa cum urmeaza:
|
|
|
|
~~~
|
|
[php]
|
|
array(
|
|
......
|
|
'components'=>array(
|
|
......
|
|
'db'=>array(
|
|
'class'=>'CDbConnection',
|
|
'connectionString'=>'mysql:host=localhost;dbname=testdb',
|
|
'username'=>'root',
|
|
'password'=>'password',
|
|
),
|
|
),
|
|
)
|
|
~~~
|
|
|
|
Putem dupa aceea sa accesam conexiunea DB prin `Yii::app()->db`, care este
|
|
activata automat (putem interzice acest comportament prin setarea cu false a
|
|
proprietatii [CDbConnection::autoConnect]. Folosind aceasta metoda
|
|
conexiunea DB poate fi utilizata oriunde in cod.
|
|
|
|
Executarea instructiunilor SQL
|
|
------------------------------
|
|
|
|
O data ce este stabilita o conexiune DB, instructiunile SQL pot fi executate
|
|
folosind [CDbCommand]. Cream o instanta [CDbCommand] prin apelarea
|
|
[CDbConnection::createCommand()] cu instructiunea SQL specificata:
|
|
|
|
~~~
|
|
[php]
|
|
$command=$connection->createCommand($sql);
|
|
// daca este necesar, instructiunea SQL poate fi actualizata asa:
|
|
// $command->text=$newSQL;
|
|
~~~
|
|
|
|
O instructiune SQL este executata prin [CDbCommand] in unul din urmatoarele doua moduri:
|
|
|
|
- [execute()|CDbCommand::execute]: executa o instructiune SQL,
|
|
precum `INSERT`, `UPDATE` si `DELETE`. Daca are succes, returneaza
|
|
numarul de randuri afectate.
|
|
|
|
- [query()|CDbCommand::query]: executa o instructiune SQL care returneaza
|
|
randuri de date, precum `SELECT`. Daca are succes, returneaza o instanta [CDbDataReader]
|
|
pe care putem sa o parcurgem pentru a folosi randurile de date rezultate.
|
|
Pentru usurinta, este implementat de asemenea un set de metode `queryXXX()`
|
|
care returneaza direct rezultatele cererii.
|
|
|
|
Va fi generata o exceptie daca apare vreo eroare in timpul executiei instructiunilor SQL.
|
|
|
|
~~~
|
|
[php]
|
|
$rowCount=$command->execute(); // executa SQL
|
|
$dataReader=$command->query(); // executa o cerere SQL
|
|
$rows=$command->queryAll(); // o cerere care returneaza toate randurile rezultate
|
|
$row=$command->queryRow(); // o cerere care returneaza primul rand dintre rezultate
|
|
$column=$command->queryColumn(); // o cerere care returneaza prima coloana din rezultate
|
|
$value=$command->queryScalar(); // o cerere care returneaza primul camp din primul rand
|
|
~~~
|
|
|
|
Extragerea rezultatelor cererii
|
|
-------------------------------
|
|
|
|
Dupa ce [CDbCommand::query()] genereaza instanta [CDbDataReader], putem extrage
|
|
randurile cu datele rezultate prin apelarea repetata a [CDbDataReader::read()].
|
|
Putem de asemenea folosi [CDbDataReader] intr-un `foreach` pentru a extrage fiecare rand in parte.
|
|
|
|
~~~
|
|
[php]
|
|
$dataReader=$command->query();
|
|
// apelam repetat read() pana cand returneaza false
|
|
while(($row=$dataReader->read())!==false) { ... }
|
|
// folosim foreach pentru a trece prin fiecare rand de date
|
|
foreach($dataReader as $row) { ... }
|
|
// extragem toate randurile o data intr-un singur array
|
|
$rows=$dataReader->readAll();
|
|
~~~
|
|
|
|
> Note|Nota: Spre deosebire de [query()|CDbCommand::query], toate metodele `queryXXX()`
|
|
returneaza date direct. De exemplu, [queryRow()|CDbCommand::queryRow]
|
|
returneaza un array care reprezinta primul rand din rezultatele cererii.
|
|
|
|
Folosirea tranzactiilor
|
|
-----------------------
|
|
|
|
Cand o aplicatie executa cateva cereri, operatii de citire sau/si scriere
|
|
in baza de date, este important sa ne asiguram ca baza de date sa contina toate schimbarile
|
|
facute de aceste operatii. In aceste cazuri, poate fi initiata o tranzactie,
|
|
reprezentata prin instanta [CDbTransaction] din Yii:
|
|
|
|
- Incepem tranzactia.
|
|
- Executam cererile una cate una. Orice actualizare nu este vizibila in exteriorul bazei de date.
|
|
- Executam tranzactia. Actualizarile devin vizibile daca tranzactia a avut succes.
|
|
- Daca o cerere esueaza, intreaga tranzactie este derulata inapoi.
|
|
|
|
Fluxul de lucru de mai sus poate fi implementat folosind urmatorul cod:
|
|
|
|
~~~
|
|
[php]
|
|
$transaction=$connection->beginTransaction();
|
|
try
|
|
{
|
|
$connection->createCommand($sql1)->execute();
|
|
$connection->createCommand($sql2)->execute();
|
|
//.... alte executii SQL
|
|
$transaction->commit();
|
|
}
|
|
catch(Exception $e) // daca o cerere esueaza, este generata o exceptie
|
|
{
|
|
$transaction->rollBack();
|
|
}
|
|
~~~
|
|
|
|
Conectarea de parametri (Binding)
|
|
---------------------------------
|
|
|
|
Pentru a evita [atacurile SQL injection] (http://en.wikipedia.org/wiki/SQL_injection) si pentru a
|
|
imbunatati performanta executiilor cererilor SQL folosite des, putem "prepara"
|
|
o instructiune SQL cu placeholder-e de parametri optionali care vor fi inlocuiti
|
|
cu parametrii reali in timpul procesului de conectare de parametri.
|
|
|
|
Placeholder-ele de parametri pot avea nume (token-uri unice)
|
|
sau pot fi anonime (prin semne de intrebare). Apelam
|
|
[CDbCommand::bindParam()] sau [CDbCommand::bindValue()] pentru a inlocui aceste
|
|
placeholder-e cu parametrii reali. Conectarea parametrilor trebuie facuta inainte
|
|
ca instructiunea SQL sa fie executata.
|
|
|
|
~~~
|
|
[php]
|
|
// o cerere SQL cu 2 placeholdere ":username" si ":email"
|
|
$sql="INSERT INTO users(username, email) VALUES(:username,:email)";
|
|
$command=$connection->createCommand($sql);
|
|
|
|
// inlocuim placeholder-ul ":username" cu valoarea reala username
|
|
$command->bindParam(":username",$username,PDO::PARAM_STR);
|
|
|
|
// inlocuim placeholder-ul ":email" cu valoarea reala email
|
|
$command->bindParam(":email",$email,PDO::PARAM_STR);
|
|
$command->execute();
|
|
|
|
// inseram un alt rand cu un nou set de parametri
|
|
$command->bindParam(":username",$username2,PDO::PARAM_STR);
|
|
$command->bindParam(":email",$email2,PDO::PARAM_STR);
|
|
$command->execute();
|
|
~~~
|
|
|
|
Metodele [bindParam()|CDbCommand::bindParam] si [bindValue()|CDbCommand::bindValue] sunt foarte
|
|
asemanatoare. Singura diferenta este ca [bindParam()|CDbCommand::bindParam] conecteaza un parametru
|
|
cu o referinta a unei variabile PHP, in timp ce [bindValue()|CDbCommand::bindValue] conecteaza
|
|
un parametru cu o valoare. Pentru parametri care reprezinta blocuri mai de date memorate, este de preferat
|
|
sa folosim [bindParam()|CDbCommand::bindParam] din considerente de perfomanta.
|
|
|
|
Pentru mai multe detalii despre conectarea de parametrii, trebuie vazuta
|
|
[sectiunea din documentatia PHP](http://www.php.net/manual/en/pdostatement.bindparam.php).
|
|
|
|
Conectarea coloanelor (Binding)
|
|
-------------------------------
|
|
|
|
Cand extragem rezultatele cererii, putem sa conectam si coloane la variabile PHP pentru a fi
|
|
populate automat cu ultimele date, de fiecare data cand se extrage un rand nou.
|
|
|
|
~~~
|
|
[php]
|
|
$sql="SELECT username, email FROM users";
|
|
$dataReader=$connection->createCommand($sql)->query();
|
|
// conectam prima coloana (username) cu variabila $username
|
|
$dataReader->bindColumn(1,$username);
|
|
// conectam a doua coloana (email) cu variabila $email
|
|
$dataReader->bindColumn(2,$email);
|
|
while($dataReader->read()!==false)
|
|
{
|
|
// $username si $email contin username si email din randul curent
|
|
}
|
|
~~~
|
|
|
|
<div class="revision">$Id: database.dao.txt 367 2008-12-16 20:18:30Z qiang.xue $</div> |