Ten artykuł poświęcony jest tworzeniu i używaniu interfejsów Baz Danych (DB Interfaces). Interfejsy te sprawiają, że rozbudowa aplikacji staje się łatwiejsza i szybsza. Dzieje się tak za sprawą umieszczenia kilku rozproszonych operacji DML (polecenia modyfikujące dane: wstaw, zmień, usuń - przyp. tłum.) w jednym współdzielonym narzędziu, jakim jest klasa. Klasa taka łączy przetwarzanie danych, ich integralność i ochronę w jednym instrumencie, który może być udostępniony poprzez aplikacje.
W ciągu ostatnich kilku lat powstało wiele narzędzi, zaradzających ograniczeniom PHP w czasie budowy dużych aplikacji, korzystającym z baz danych. Można je podzielić na dwie kategorie:
Interfejsy Baz Danych są czymś nowym, narzędziem działającym pomiędzy logiką biznesową, a bazodanową.
PHP zostało zaprojektowane jako "szybki i prosty" język służący do tworzenia dynamicznych stron internetowych. Jednakże, jego skalowalność jest znacznie obniżona, w przypadku dużych aplikacji, bez uprzedniej dużej ilości przygotowań i planowania. W czasie, gdy małe strony internetowe zbudowe przy pomocy PHP są "szybkie i proste", to aplikacje już niejednokrotnie stają się "szybkie i nieczytelne".
Kiedy aplikacja przekracza pewien rozmiar, reguły wg których powinna być zbudowana zmieniają się raptownie. Zasady projektowania małej strony HTML z odrobiną PHP znacznie się różnią od aplikacji, gdzie jej wielkość sięga 15 000 linijek kodu. Wraz ze wzrostem złożoności projektu, staje się on coraz trudniejszy w zarządzaniu. Chociaż język PHP został stworzony do wstawiania pomiędzy znaczniki HTML, ta zdolność staje się uciążliwa w czasie rozrastania się aplikacji.
Zagnieżdzony SQL podlega tym samym ograniczeniom co zagnieżdzony PHP. Im większy projekt, tym mniejsza łatwość zarządzania nim.
Oddzielenie trzech głownych elementów aplikacji PHP jest najlepszym rozwiązaniem. Tymi elementami są:
Narzędzia takie jak ADODB, czy Smarty wspomagają wdrażanie tego pomysłu w życie. ADODB dostarcza aplikacji wsparcie przez wiele różnych baz danych. Smarty natomiast oddziela treść (logikę aplikacji) od wyglądu (layout).
Łatwiejszym we wdrożeniu rozwiązaniem jest użycie interfejsu bazodanowego w czasie działań na bazie danych. Interfejsy te odseparowują logikę bazy danych od logiki aplikacji. Ścislej mówiąc, odseparowują operacje DML od reszty kodu, co czyni go bardziej przejrzystym.
Najlepiej używać interfejsów, operując wyrażeniami DML bezpośrednio na tabelach. Zapewnia to lepszy poziom bezpieczeństwa i spójności danych.
Oto przykład w którym interfejs bazodanowy zastąpił zagnieżdżone operacje DML:
<?php /* Update the client's contact information with the data from $_POST */ $userID = (int) $_POST['userID']; $email = trim(addslashes($_POST['email'])); $firstname = trim(addslashes($_POST['firstname'])); $lastname = trim(addslashes($_POST['lastname'])); $address1 = trim(addslashes($_POST['address1'])); $address2 = trim(addslashes($_POST['address2'])); $city = trim(addslashes($_POST['city'])); $province = trim(addslashes($_POST['province'])); $country = trim(addslashes($_POST['country' ])); $DML = 'UPDATE clients SET '. "email = '$email',". "firstname = '$firstname',". "lastname = '$lastname',". "address1 = '$address1',". "address2 = '$address2',". "city = '$city',". "province = '$province',". "country = '$country',". "WHERE userID=$userID"; if ($db->Execute($DML)) { // do error handling } ?>
<?php $client = new Client(); $client->setUserID ( $_POST['userID' ]); $client->setEmail ( $_POST['email' ]); $client->setFirstname ( $_POST['firstname']); $client->setLastname ( $_POST['lastname' ]); $client->setAddress1 ( $_POST['address1' ]); $client->setAddress2 ( $_POST['address2' ]); $client->setCity ( $_POST['city' ]); $client->setProvince ( $_POST['province' ]); $client->setCountry ( $_POST['country' ]); if ($client->submit($db) !== true) { // do error handling } ?>
Powyższy przykład demonstruje redukcje w logice aplikacji w stosunku do przykładu go poprzedzjącego. Interfejs zajmuje się komunikacją z bazą danych w czasie, gdy programista może się skupić jedynie na wynikach dokonanych operacji. Pisanie mniejszej ilości kodu w stosunku do tego samego zadania jest najbardziej korzystne, gdy różne części aplikacji używają tych samych poleceń DML. Wtedy zamiast powtarzania zapytań do bazy danych, można zwyczajnie użyć odpowiednich interfejsów.
Inną zaletą interfejsów bazodanowych jest mniejszy wpływ na aplikację zmian dokonanych w strukturze bazy. Zmiana w jednym tylko interfejsie jest dużo prostsza, niż wyszukiwanie i modyfikowanie kodu PHP i SQL w całym projekcie.
Istnieje kilka główmych wytycznych, którymi powinieneś się kierować w trakcie projektowania interfejsu.
Każdy wymagany intefejs powinien być oparty na klasie. Klasa taka powinna być logicznym odwzorowaniem struktury odpowiedniej tabeli w bazie danych. Właściwości klasy reprezentują osobne kolumny w tabeli. Metody klasy powinny charakteryzować operacje DML i DQL (polecenia służące do pobierania danych - przyp. tłum.) na rekordach tabeli. Przykład poniżej ilustruje jak operacje DDL (polecenia służące do definiowania danych - przyp. tłum.) i DQL są zaimplementowane w metodach load(), submit() i delete().
<?php class Client { var $clientID = 0; var $firstName = ''; var $lastName = ''; var $emailAddress = ''; function Client() {} function load(&$db,$clientID) { $DQL = 'SELECT clientID,firstName,lastName,emailAddress '. 'FROM client '. "WHERE clientID=$clientID"; if ($row = $db->GetOne()) { $clientID = $row[ 'clientID' ]; $firstName = $row[ 'firstName' ]; $lastName = $row[ 'lastName' ]; $emailAddress = $row[ 'emailAddress' ]; return true; } else { return false; } } function submit(&db) { // clean up the data. $clientID = (int) $this->clientID; $firstName = addslashes(trim( $firstName )); $lastName = addslashes(trim( $lastName )); $emailAddress = addslashes(trim( $emailAddress )); if ($clientID == 0) { $DML = 'INSERT INTO client (clientID,firstName,lastName, '. 'emailAddress) VALUES (NULL,'. "'$firstName','$lastName','$emailAddress')"; if ($db->Execute($DML)) { $this->clientID = $db->Insert_ID(); return true; } else { return false; } } else { $DML = 'UPDATE client SET '. "firstName = '$firstName ,' ". "lastName = '$lastName ,' ". "emailAddress = '$emailAddress ,' ". "WHERE clientID= $clientID"; if ($db->Execute($db)) { return true; } else { return false; } } } function delete(&$db) { $DML = 'DELETE FROM client WHERE clientID='.$this->clientID; if ($db->Execute($db)) { return true; } else { return false; } } function getClientID() { return $this->clientID; } function setClientID($clientID) { $this->clientID = $clientID; } function getFirstName() { return $this->firstName; } function setFirstName($firstName) { $this->firstName = $firstName; } function getLastName() { return $this->lastName; } function setLastName($lastName) { $this->lastName = $lastName; } function getEmailAddress() { return $this->emailAddress; } function setEmailAddress($emailAddress) { $this->emailAddress = $emailAddress; } } ?>
Buduj interfejs z zamiarem wykorzystania go w jednym konkretnym celu. Jest nim zazwyczaj tworzenie, aktualizowanie lub usuwanie wierszy z tablicy. Interfejsy bazodanowe powinny być samodzielne jak to tylko możliwe, ponieważ ułatwia to wykorzystywanie wielu z nich jednocześnie przy bardziej rozbudowanych zadaniach. Zespołowe użycie interfejsów jest znacznie uproszczone, kiedy każdy z nich ma ściśle określone zadania. (Zobacz przykład poniżej.)
Posiadanie przez duże aplikacje wielu tabel w bazie danych, skutkuje w dużej liczbie interfejsów. Ich ustandaryzowana budowa ułatwia pracę i czyni szybszym zaznajomienie się z nimi. Stosuj stałe nazewnictwo, układ i sposób implementacji w celu uproszczenia ich (interfejsów) łączenia w czasie skomplikowanych działań.
Pojedynczy interfejs bazodanowy sam w sobie ma dosyć ograniczoną użyteczność. Jego możliwości zaobserujemy dopiero, kiedy uzyjemy go w wraz z pozostałymi interfejsami w celu wykonania bardziej złożonej operacji. Oto przykład, w którym korzystamy z kilku interfejsów, w celu dodania nowego postu do forum.
<?php /* Notes: $db - instance of ADOdb connection object. $user - instance of the User DB Interface $topic - instance of the Topic DB Interface */ $db->StartTrans(); // update the user's total # of posts $user->setNumPosts($user->getNumPosts() + 1); $user->submit($db); // update the topics # of messages $topic->setNumMessages($topic->getNumMessage() + 1); $topic->submit($db); // create the new message $message = new Message(); $message->setTopicID($topic->getTopicID()); $message->setTopic($_POST['userTopic']); $message->setMessage($_POST['message']); $message->setPoster($user->getUserID()); $message->submit($db); $db->CompleteTrans(); ?>
Ten artykuł miał na celu zapoznanie czytelnika z pojęciem interfejsu bazodanowego i jego użycia w aplikacjach. Gdy aplikacje PHP stają się coraz bardziej złożone, zarządzanie nimi - nieuchronnie - staje się trudniejsze. Interfejsy bazodanowe dostarczają mechanizmy i metodykę budowania rozbudowanych aplikacji znacznie łatwiej i szybciej.
[code]
function submit(&db)
{
[ciach]
}
[/code]
a tak powinno być
[code]
function submit(&$db)
{
[ciach]
}
[/code]
Artykuł w praktyczny sposób pokazuję jak uporać się z obsługą baz danych, prawda. Zauważmy jednak, że operacje wykonywane są na pojedynczych tabelach. Co się będzie działo, kiedy zażyczymy sobie wysłać do bazdy danych zaawansowane query, w którym wykożystać trzeba będzie kilka tabel, aby otrzymać precyzyjne informacje. Oczywiście może napisać klasę, która dziedziczyć będzie kilka klas odpowiadających interfejsom tabel, i wykonać kilka metod, ale wydaje mi się, że skrypt będzie wydajniejszy, gdy wykonamy jedno zapytanie do bazy, niz miało by być ich dziesięć. Czekam na kontynuację.
Przecież to jest właśnie Active Record???
jak poprzednicy uwazam ze ten sposob nie jest za dobrym rozwiazaniem ze wzgledow koncepcyjnych.
lepiej rozwazyc ORM. duzo lepsze rozwiazanie.
Ja osobiście kożystam ze wzorca ActiveRecord do obsługi bazy danych ( został przedstawiony w PHP Solutions ). Jest znacznie bardziej uniwersalny i prostszy w zastosowaniu niż przykład podany w artykule.
To jakas tragedia konceptualna ...
Cos wydaje mi sie ze chyba raczej takich
bzdetow jako przyklady nie powinno sie zamieszczac tutaj, ktora ma sugerowac dobre wzory ...