Rozdział 9. Zend_Db
Poprzedni |  | Następny

## Rozdział 9. Zend_Db

## 9.1. Zend_Db_Adapter

### 9.1.1. Wprowadzenie

`Zend_Db_Adapter` jest uniwersalnym interfejsem dostępu do baz danych dla Zend Framework. Bazuje on na PDO. Używając interfejsu `Zend_Db_Adapter` możesz połączyć się z dowolnym wspieranym systemem bazodanowym używając tego samego API. Wspierane systemy to między innymi Microsoft SQL Server, MySQL, PostgreSQL, SQLite, i inne.

Aby utworzyć instancję interfejsu `Zend_Db_Adapter` dla określonego systemu bazodanowego, musisz wywołać metodę `Zend_Db::factory()` przekazując jej nazwę systemu bazodanowego oraz tablicę parametrów potrzebnych do połączenia. Na przykład, aby połączyć się z bazą MySQL nazwaną "camelot" znajdującą się pod adresem lokalnym, jako użytkownik "malory" możesz zrobić tak:

    <?php

    require_once 'Zend/Db.php';

    $params = array ('host'     => '127.0.0.1',
                     'username' => 'malory',
                     'password' => '******',
                     'dbname'   => 'camelot');

    $db = Zend_Db::factory('PDO_MYSQL', $params);

    ?>

Podobnie, aby połączyć się z bazą SQLite nazwaną "camelot.sq3":

    <?php

    require_once 'Zend/Db.php';

    $params = array ('dbname' => 'camelot.sq3');

    $db = Zend_Db::factory('PDO_SQLITE', $params);

    ?>

Podobnie, aby połączyć się z bazą danych SQLite2 o nazwie "camelot.sq2": Dla bazy sqlite opartej na pamięci nie określaj prefiksu dsn i użyj bazy danych o nazwie ":memory:".

    <?php

    require_once 'Zend/Db.php';

    $params = array ('dbname' => 'camelot.sq2',
                     'dsnprefix' => 'sqlite2');

    $db = Zend_Db::factory('PDO_SQLITE', $params);

    ?>

W każdym z tych przypadków będziesz mógł używać takiego samego API aby tworzyć zapytania do bazy.

### 9.1.2. Zapobieganie atakom SQL Injection

Powinieneś zawsze cytować wartości, które będą użyte w wyrażeniu SQL; zapobiega to atakom SQL Injection. `Zend_Db_Adapter` zapewnia dwie metody (poprzez obiekt PDO) aby pomóc Ci manualnie cytować wartości.

Pierwsza z nich to metoda `quote()`. Zacytuje ona wartość skalarną odpowiednio dla twojego adaptera bazy danych; jeśli spróbujesz cytować tablicę, metoda zwróci łańcuch znaków zawierający wartości elementów tablicy oddzielone przecinkami. Każda wartość zostanie odpowiednio zacytowana. (Jest to użyteczne dla funkcji przyjmujących parametr w postaci listy).

    <?php

    // tworzymy obiekt $db, zakładając, że adapter to Mysql

    // cytujemy łańcuch znaków
    $value = $db->quote('St John"s Wort');
    // $value ma teraz wartość '"St John\"s Wort"' (zwróć uwagę na otaczające ją cudzysłowy)

    // cytujemy tablicę
    $value = $db->quote(array('a', 'b', 'c');
    // $value ma teraz wartość '"a", "b", "c"' (elementy tablicy oddzielone przecinkami)

    ?>

Druga metoda to `quoteInto()`. Przekazujesz do niej podstawowy łańcuch znaków ze znacznikiem w postaci znaku zapytania, a następnie jedną wartość skalarną lub tablicę która ma być wstawiona. Jest to użyteczne przy tworzeniu zapytań i warunków po kolei. Wartości skalarne i tablice działają tak samo jak w metodzie `quote()`.

    <?php

    // tworzymy obiekt $db, zakładając, że adapter to Mysql

    // cytujemy łańcuch znaków dla warunku WHERE
    $where = $db->quoteInto('id = ?', 1);
    // $where ma teraz wartość 'id = "1"' (zwróć uwagę na otaczające ją cudzysłowy)

    // cytujemy tablicę dla warunku WHERE
    $where = $db->quoteInto('id IN(?)', array(1, 2, 3));
    // $where ma teraz wartość 'id IN("1", "2", "3")' (elementy tablicy oddzielone przecinkami)

    ?>

### 9.1.3. Bezpośrednie zapytania

Gdy posiadasz instancję `Zend_Db_Adapter`, możesz wykonywać zapytania bezpośrednio jako SQL. `Zend_Db_Adapter` przekazuje te zapytania do obiektu PDO, który je przygotowuje i wykonuje, a następnie zwraca Ci obiekt PDOStatement abyś mógł manipulować danymi wynikowymi (jeśli jekieś są).

    <?php

    // tworzymy obiekt $db, a następnie wykonujemy
    // odpowiednio zacytowane zapytanie SQL.
    $sql = $db->quoteInto(
        'SELECT * FROM example WHERE date > ?',
        '2006-01-01'
    );
    $result = $db->query($sql);

    // używamy PDOStatement aby pobrać wszystkie wiersze w postaci tablicy
    $rows = $result->fetchAll();

    ?>

Możesz dołączać dane do zapytania automatycznie. Oznacza to, że możesz użyć dowolną ilość nazwanych znaczników w zapytaniu, a następnie przekazać tablicę danych które odpowiadają tym znacznikom. Odpowiadające wartości są automtycznie cytowane, lepiej zabezpieczając przed atakami SQL injection.

    <?php

    // tworzymy obiekt $db, a następnie wykonujemy zapytanie
    // tym razem używając podmieniania znaczników
    $result = $db->query(
        'SELECT * FROM example WHERE date > :placeholder',
        array('placeholder' => '2006-01-01')
    );

    // używamy PDOStatement aby pobrać wszystkie wiersze w postaci tablicy
    $rows = $result->fetchAll();

    ?>

Opcjonalnie możesz przygotować i dołączyć dane do zapytań SQL ręcznie. Aby to zrobić użyj metody `prepare()` aby otrzymać przygotowane zapytanie `PDOStatement`, przy którym możesz bezpośrednio manipulować.

    <?php

    // tworzymy obiekt $db, a następnie wykonujemy zapytanie
    // tym razem przygotowujemy PDOStatement do ręcznego dołączania.
    $stmt = $db->prepare('SELECT * FROM example WHERE date > :placeholder');
    $stmt->bindValue('placeholder', '2006-01-01');
    $stmt->execute();

    // używamy PDOStatement aby pobrać wszystkie wiersze w postaci tablicy
    $rows = $stmt->fetchAll();

    ?>

### 9.1.4. Transakcje

Domyślnie, PDO (a więc i `Zend_Db_Adapter`) działają w trybie "auto-commit". Oznacza to, że wszystkie zapytania są realizowane natychmiast po ich wykonaniu. Jeśli chcesz je wykonać wewnątrz transakcji, w prosty sposób wywołak metodę `beginTransaction()`, a następnie `commit()` aby zrealizować zapytania lub `rollBack()` aby je cofnąć. `Zend_Db_Adapter` wraca wtedy do trybu "auto-commit" dopóki znów nie wywołasz metody `beginTransaction()`.

    <?php

    // utwórz obiekt $db, a następnie rozpocznij transakcję
    $db->beginTransaction();

    // próbujemy wykonać zapytanie
    // jeśli uda się, zatwierdzamy zapytanie;
    // jeśli nie uda się, cofamy zapytanie.
    try {
        $db->query(...);
        $db->commit();
    } catch (Exception $e) {
        $db->rollBack();
        echo $e->getMessage();
    }

    ?>

### 9.1.5. Wstawianie wierszy

Dla wygody możesz użyć metody `insert()`, która utworzy zapytanie INSERT oraz dołączy do niego dane, które mają wstawione. (Dołączone dane zostaną automatycznie zacytowane aby pomóc zapobiegać atakom SQL injection.)

Zwracana wartość nie jest ostatnio wstawionym numerem ID, ponieważ tabela nie musi posiadać automatycznie inkrementowanej kolumny; zwracana wartość jest liczbą wstawionych wierszy (najczęściej 1). Jeśli chcesz otrzymać wartość ID ostatnio wstawionego rekordu, wywołaj metodę `lastInsertId()` po wstawieniu rekordu.

    <?php

    //
    // INSERT INTO round_table
    //     (noble_title, first_name, favorite_color)
    //     VALUES ("King", "Arthur", "blue");
    //

    // tworzymy obiekt $db, a następnie...
    // dane do wstawienia w postaci nazwa_kolumny => wartość
    $row = array (
        'noble_title'    => 'King',
        'first_name'     => 'Arthur',
        'favorite_color' => 'blue',
    );

    // nazwa tabeli do której ma być wstawiony wiersz
    $table = 'round_table';

    // wstawiamy wiersz i pobieramy jego ID
    $rows_affected = $db->insert($table, $row);
    $last_insert_id = $db->lastInsertId();

    ?>

### 9.1.6. Aktualizowanie wierszy

Dla wygody możesz użyć metody `update()`, która utworzy zapytanie UPDATE oraz dołączy do niego dane które mają być uaktualnione. (Dołączone dane zostaną automatycznie zacytowane aby pomóc zapobiegać atakom SQL injection.)

Możesz przekazać do metody opcjonalny warunek WHERE aby określić, które wiersze chcesz usunąć. (Zauważ, że warunek WHERE nie jest dołączanym parametrem, więc musisz sam zacytować jego wartości.)

    <?php

    //
    // UPDATE round_table
    //     SET favorite_color = "yellow"
    //     WHERE first_name = "Robin";
    //

    // tworzymy obiekt $db, a następnie...
    // dane do aktualizowania w postaci nazwa_kolumny => wartość
    $set = array (
        'favorite_color' => 'yellow',
    );

    // nazwa tabeli w której ma być aktualizowany wiersz
    $table = 'round_table';

    // warunek WHERE
    $where = $db->quoteInto('first_name = ?', 'Robin');

    // uaktualniamy tabelę i pobieramy liczbę uaktualnionych wierszy
    $rows_affected = $db->update($table, $set, $where);

    ?>

### 9.1.7. Usuwanie wierszy

Dla wygody możesz użyć metody `delete()`, która utworzy zapytanie DELETE; możesz przekazać do metody opcjonalny warunek WHERE aby określić, które wiersze chcesz usunąć. (Zauważ, że warunek WHERE nie jest dołączanym parametrem, więc musisz sam zacytować jego wartości.)

    <?php

    //
    // DELETE FROM round_table
    //     WHERE first_name = "Patsy";
    //

    // tworzymy obiekt $db, a następnie...
    // nazwa tabeli z której usuwamy wiersz
    $table = 'round_table';

    // warunek WHERE
    $where = $db->quoteInto('first_name = ?', 'Patsy');

    // usuwamy wiersz i pobieramy liczbę usuniętych wierszy
    $rows_affected = $db->delete($table, $where);

    ?>

### 9.1.8. Pobieranie wierszy

Chociaż możesz wykonać zapytanie bezpośrednio za pomocą metody `query()`, często wszystko czego potrzebujesz to wybrać wiersze i pobrać wyniki. Seria metod `fetch*()` robi to dla ciebie. Do każdej z metod `fetch*()`, przekazujesz zapytanie SQL SELECT; jeśli użyjesz nazwanych znaczników w zapytaniu, możesz przekazać tablicę wartości, które mają być zacytowane i zamienione w zapytaniu. Metody `fetch*()` to:

- `fetchAll()`

- `fetchAssoc()`

- `fetchCol()`

- `fetchOne()`

- `fetchPairs()`

- `fetchRow()`

    <?php

    // tworzymy obiekt $db, a następnie...

    // pobieramy wszystkie kolumny wszystkich wierszy jako sekwencyjną tablicę
    $result = $db->fetchAll(
        "SELECT * FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // pobieramy wszystkie kolumny wszystkich wierszy jako tablicę
    // asocjacyjną; pierwsza kolumna jest używana jako klucz tablicy
    $result = $db->fetchAssoc(
        "SELECT * FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // pobieramy pierwszą kolumnę wszystkich zwróconych wierszy
    $result = $db->fetchCol(
        "SELECT first_name FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // pobieramy tylko pierwszą zwróconą wartość
    $result = $db->fetchOne(
        "SELECT COUNT(*) FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // pobieramy serię par klucz-wartość; pierwsza kolumna jest
    // kluczem tablicy, a druga jest wartością
    $result = $db->fetchPairs(
        "SELECT first_name, favorite_color FROM round_table WHERE noble_title = :title",
        array('title' => 'Sir')
    );

    // pobieramy tylko pierwszy zwrócony wiersz
    $result = $db->fetchRow(
        "SELECT * FROM round_table WHERE first_name = :name",
        array('name' => 'Lancelot')
    );

    ?>

Poprzedni |  | Następny
8.5. Constants for General Date Functions | Spis treści | 9.2. Zend_Db_Profiler