mysql2object

autor: arkadiusz maliński - amalinski at gmail dot com

pobierz plik (zip)

Zestaw klas do "mapowania" bazy danych do obiektu PHP 5. Dzięki temu zestawowi klas możemy do bazy danych i poszczególnych pól odwoływać się jakby były one metodami stworzonego obiektu, bądź jego wartościami. Klasy pozwalają także uzyskac informacje na temat bazy jak i poszczególnych pól, takie jak:
- ilość wierszy
- ilość kolumn
- typy danych
- opisy
- wersje
- itd..
Klasy pozwalają również na otrzymywanie wybranych wartości z bazy na podstawie definiowanych przez użytkownika warunków. Oczywiście możliwe jest również dodanie jak i modyfikacja danych. No ale zacznijmy od początku:

1. Tworzenie obiektu...

Aby zacząc zabawę z mysql2object należy rozpakować archiwum i przekopiować pliki do jednego katalogu a następnie załączyć je do skryptu PHP:

require_once('database.class.php');

Obiekt tworzymy jednym poleceniem w którym należy zawrzeć ustawienia bazy danych:

$databaseName = new Database(new DB('mysql://username:password@localhost/databaseName'));         

Od tego momentu możeby odwoływać się poprzez stworzony obiekt do tabel i pól w bazie danych. Oczywiście nalezy pamiętać o umieszczeniu kodu pomiędzy blokiem try {...} catch aby obsłużyć ewentualne błedy bazy lub błędne wywołania metod. Obiekt zwraca wyjątki 3 klas:
- DatabaseException,
- TableException,
- ColumnException.

2. Odwoływanie się do bazy, tabel, pól...

Skrypt ma za zadanie jak najbardziej uprościć formę odwoływania się do bazy MySQL. Podczas projektowania may pełen obraz tego jak baza wyglada, jakie ma tablele oraz jak definiuje pole. Obiekt "mysql2object" pozwala znając strukturę bazy na odwołania typu:

$obiekt->tabela->pole;

czyli w przypadku posiadania tabeli o strukturze:

CREATE TABLE `sd_usergroups` (
 `usergroupid` smallint(5) unsigned NOT NULL auto_increment,
 `forumusergroupid` smallint(5) unsigned NOT NULL default '0',
 `name` varchar(100) NOT NULL default '',
 `adminaccess` tinyint(1) NOT NULL default '0',
 `commentaccess` tinyint(1) NOT NULL default '0',
 `offlinecategoryaccess` tinyint(1) NOT NULL default '0',
 `categoryviewids` text NOT NULL,
 `categorymenuids` text NOT NULL,
 `pluginviewids` text NOT NULL,
 `pluginsubmitids` text NOT NULL,
 `plugindownloadids` text NOT NULL,
 `plugincommentids` text NOT NULL,
 `pluginadminids` text NOT NULL,
 `custompluginviewids` text NOT NULL,
 `custompluginadminids` text NOT NULL,
 PRIMARY KEY  (`usergroupid`),
 KEY `forumusergroupid` (`forumusergroupid`)
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1;


prawidłowe odwołania mogą wyglądać tak:

$database->sd_usergroups->name->all;
$database->sd_usergroups->all;
$database->sd_usergroups->categorymenuids(11);

3. Dane i właściwości...

Jak widać na poprzednim przykładzie, odwołania do danych są proste i przejrzyste. Na każdym poziomie możemy wywołać właściwość 'all', która zwraca:
- w przypadku bazy danych - listę wszystkich tabel
- w przypadku tabeli - listę wszystkich pól
- w przypadku kolumny/pola - wszystkie wartości.

Aby odwołać się do wartości z konkretnego wiersza kolumny należy zaraz za nazwą kolumny w nawiasie wpisać numer indexu, który chcemy otrzymać:

$database->sd_usergroups->name(3);


Obiekt zwróci wyjątek gdy index podany będzie poza zakresem istniejących danych. Natomiast aby otrzymać wszystkie wartości, tak jak zostało już wspomniane, wystarczy wywołać:

$database->sd_usergroups->name->all;

Otrzymamy wtedy wszystkie wartości z wybranego pola. Aby otrzymać wartości ze wszystkich pól można zastosować fragment skryptu:

foreach($database->sd_usergroups->all as $column)
    $returnValues[$column->name] = $column->all;
return $returnValues;

Możemy również otrzymywać wartości z zadanymi przez nas ograniczeniami, tylko z wybranych kolumn, bądź posortowane wg naszego "widzimisie" :).

// wybrane kolumny z wszystkimi wartościami 
$database->sd_usergroups->columns('name', 'usergroupid', 'commentaccess', 'categoryviewids');
                         
// wszystkie kolumny posortowane wg column
$database->sd_usergroups->sort('name desc', 'usergroupid acs');
                         
// wszystkie kolumny z ograniczeniami wg zadanych warunków
$database->sd_usergroups->select(array('usergroupid', '>', 5), array('name', '!=', 'admin'));

Jak widać w metodzie 'columns()' parametrami są nazwy kolumn, których wartości metoda ma zwrócić. W metodzie 'sort()', również parametrami są nazwy kolumn. Jednakże w tym przypadku do każdej nazwy kolumny można dodać parametr mówiący czy sortowanie ma być rosnąco 'asc', czy malejąco 'desc'. W ostatnim przypadku, parametrami są tablice definiujące warunek. Na taką tablicę składają się: nazwa kolumny, operator porównania, wartośc do porównania. Warunek musi by przynajmniej jeden aby metoda 'select()' zwróciła wyniki.

Nasuwa się pytanie: a jak połaczyć wyniki z dwóch tabel ? Można zrobić 'joina' SQL'owego ? A 'union' ? No pewnie :) Popatrzmy na przykłady a wnioski powinny nasunąć się samemu.

// dodanie kolumn do tabeli na podstawie zdefiniowanych pól
$testDatabase->sd_usergroups->join($testDatabase->pp_usergroups, $testDatabase->sd_usergroups->usergroupid, $testDatabase->pp_usergroups->groupid);

// złączenie wyników z dwóch tabel
$testDatabase->sd_usergroups->union($testDatabase->old_pp_users, array('username'=>'old_username','email'=>'old_email', 'groupname'=>'password'));

Metoda 'join()' jako parametry przyjmuje: 1 - obiekt tabeli, 2 - obiekt kolumny z tabeli z której wywołujemy metodę, 3 - obiekt kolumny z tabeli podanej jko parametr pierwszy, 4 - opcjonalny - tabela nazw kolumn z tabeli z pierwszego parametru, które chcemy aby były dołączone do naszego wyniku. Warunek dołączeniowy powstaje na podstawie porównania wartości z kolumn z parametrów drugiego i trzeciego. Skomplikowanie brzmi ale w użyciu jest podobne do SQL'owego 'join'a'.

Metoda 'union()' jako parametr przyjmuje obiekt tabeli z której dane chcemy dodać do tabeli z której wywołujemy metodę. Jeżeli liczba pól w obu tabelach się równa to parametr drugi jest opcjonalny. Jeżeli nie zgadza się to parametrem drugim jest tabela odzworowań: 'pole_z_tabeli_1'=>'pole_z_tabeli_2'.

Jak widać każda metoda daje ciekawe wyniki ale jak je połączyć w całość ??. Wyjście jest proste. można te trzy metody grupować wywołując przed nimi metodę 'createComposedCondition('nazwa_warunku')' oraz bezpośrednio po 'endComposedCondition('nazwa_warunku')'. Nazwa warunku w obu metodach musi być taka sama. Do wyników złożonego warunku odwołujemy się poprzez wywołane nazwy warunku jako właściwości tabeli. Oto dokładny przykład tworzenia i wywołania:

 $database->sd_usergroups->createComposedCondition('warunek1');
 $database->sd_usergroups->columns('name', 'usergroupid', 'commentaccess', 'categoryviewids');
 $database->sd_usergroups->sort('name desc', 'usergroupid acs');
 $database->sd_usergroups->select(array('usergroupid', '>', 5), array('name', '!=', 'admin'));
 print_r($database->sd_usergroups->warunek1);

Proste ? Mam nadzieje :). A co z właściwościami bazy, tabel, pól ?. No nic. Odwołujemy się do nich jak do właściwości :) Przykład:

$database->sd_usergroups->Rows;
$database->sd_usergroups->Columns;
$database->sd_usergroups->Version;
$database->sd_usergroups->Engine;
$database->sd_usergroups->Checksum;
$database->sd_usergroups->Comment;
...itd, itd...

Właściwości tabel bazują na zapytaniu SQL 'SHOW TABLE STATUS LIKE 'tabela' ', natomiast właściwości kolumn na zapytaniu 'DESCRIBE tabela';

4. Dodawanie wartości...

Pewnie zastanawiacie się jak mocno skomplikowane może być dodanie wartości... ano mocno :). Dodajemy wartości metodą 'add()' dla wybranej tabeli z parametrem, który jest tablicą powiązań 'nazwa_pola'=>'wartosc_dodawana'. Przykład:

$database->users->add(array('name'=>'admin2', 'password'=>md5('password'), 'dateadd'=>'now()'));

Metoda zwraca ilość dodanych wierszy do tabeli. Jeśli chcielibyśmy odczytać ostatio dodaną wartość pola auto_increment to wystaczy wywołać właściwość tabeli 'lastID'.

$database->users->lastID;

5. Modyfikacja wartości...

Modyfikacja wygląda podobnie jak dodawanie wartości i zwraca taką samą wartość. Jednak podobnie to nie znaczy tak samo, więc różnice są następujące:
- pierwszy parametr zostaje taki sam; tablica powiązanych wartości 'nazwapola'=>'wartosc';
- drugi parametr to warunek SQL zapisywany bez słowa kluczowego WHERE np.: "id = 3 AND username like 'admin%'"
- trzeci parametr (opcjonalny) - ustawimy na true jeżeli ma się wykonać REPLACE lub na false jeżeli UPDATE

$database->users->modify(array('username'=>'jan', password = 'tajnehaslo', 'modifyDate'=>'now()), 'id=2 AND username LIKE "admin%"'); 

6. Podsumowanie...

Mam nadzieje, że klasa czy zestaw cały przyda się komuś i będzie miał z niego naprawdę przydatne narzędzie. Udostepniam ten kod bezpłatnie z możliwością jego modyfikacji. Jednakże przy rozpowszechnianiu dobrze by było chociażby zostawić informacje kto jest autorem podstawy skryptu.

Co do pomysłów na przyszłość to przydałoby się przerobić klasę datasource tak aby nazwa klasy zmieniła się na DB2object czyli aby można było używać klasy z innymi bazami niż tylko MySQL. Pomyśleć należy również nad możliwością wykonywania złożonych zapytań SQL. Reszta pomysłów przyjdzie w czasie użytkowania... :) Wszelkie pomysły są mile widziane i przesyłać je należy na adres podany na górze strony.

@ wszelkie prawa zastrzeżone :: arkadiusz maliński :: grudzień 2006