Co by nie pisać o Zend_Db, można z niego sporo wycisnąć. Jedną z takich wyciśniętych funkcjonalności są relacje. Wystarczy zdefiniować w klasach modelu zależne klasy i możemy cieszyć się relacjami, zamiast kombinować z joinami. Z początku relacje mogą być niejasne, jednak jak już je poznacie, nie będziecie mogli się bez nich obejść.
Wszystko zaczyna się w bazie. Przykładowe tabele to:
- users – lista użytkowników
- user_params – dodatkowe parametry użytkownika
- roles – role, np admin
- user_role – relacja między użytkownikami i rolami
CREATE TABLE users
(
id serial NOT NULL,
"login" character varying(50),
"password" character varying(32),
CONSTRAINT users_pkey PRIMARY KEY (id)
)
CREATE TABLE user_params
(
id serial NOT NULL,
iduser integer,
param_name character varying(250),
param_value text,
CONSTRAINT user_params_pkey PRIMARY KEY (id),
CONSTRAINT user_params_iduser_fkey FOREIGN KEY (iduser)
REFERENCES users (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
CREATE TABLE roles
(
id serial NOT NULL,
"name" character varying(150),
CONSTRAINT roles_pkey PRIMARY KEY (id)
)
CREATE TABLE user_role
(
iduser integer NOT NULL,
idrole integer NOT NULL,
CONSTRAINT user_role_pkey PRIMARY KEY (iduser, idrole),
CONSTRAINT user_role_idrole_fkey FOREIGN KEY (idrole)
REFERENCES roles (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT user_role_iduser_fkey FOREIGN KEY (iduser)
REFERENCES users (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
Następnie musimy stworzyć odpowiadające im klasy modeli (każda klasa powinna znaleźć się w osobnym pliku).
class Application_Model_DbTable_Users extends Zend_Db_Table_Abstract
{
protected $_name = 'users';
protected $_dependentTables = array(
'Application_Model_DbTable_UserParams',
'Application_Model_DbTable_UserRole'
);
}
class Application_Model_DbTable_UserParams extends Zend_Db_Table_Abstract
{
protected $_name = 'user_params';
protected $_referenceMap = array(
'User' => array(
'columns' => array('iduser'),
'refTableClass' => 'Application_Model_DbTable_Users',
'refColumns' => array('id')
)
);
}
class Application_Model_DbTable_Roles extends Zend_Db_Table_Abstract
{
protected $_name = 'roles';
protected $_dependentTables = array(
'Application_Model_DbTable_UserRole'
);
}
class Application_Model_DbTable_UserRole extends Zend_Db_Table_Abstract
{
protected $_name = 'user_role';
protected $_referenceMap = array(
'User' => array(
'columns' => array('iduser'),
'refTableClass' => 'Application_Model_DbTable_Users',
'refColumns' => array('id')
),
'Role' => array(
'columns' => array('idrole'),
'refTableClass' => 'Application_Model_DbTable_Roles',
'refColumns' => array('id')
)
);
}
Jak to działa? W klasie “rodzica”, należy określić jaka tabela jest od tego rodzica zależna. Innymi słowy należy wskazać, w której klasie znajduje się klucz główny bieżącej klasy.
Zastosowanie relacji jest banalne i sprowadza się do wywołania jednej metody oraz wskazania, do której tabeli się odwołujemy. Jeśli chcielibyśmy pobrać wszystkie możliwe informacje, wystarczy, że napisze coś takiego:
$modelUser = new Application_Model_DbTable_Users();
// dane o uzytkowniku
$user = $modelUser->find(1)->current();
// parametry uzytkownika. jako parametr podajemy nazwe klasy, z ktorej pobieramy dane
$userParams = $user->findDependentRowset(
'Application_Model_DbTable_UserParams'
);
// role uzytkownika. pierwszym parametrem jest tabela docelowa, drugim - tabela posrednia
$userRoles = $user->findManyToManyRowset(
'Application_Model_DbTable_Roles',
'Application_Model_DbTable_UserRole'
);
Relacje oferują jeszcze jedną ciekawą funkcjonalność. Możliwość pobrania danych z tabeli na podstawie relacji. Czyli mamy dany wiersz, np z tabeli user_params i na jego podstawie możemy pobrać dane powiązanego z nim użytkownika z tabeli users. Wygląda to następująco.
$modelUserParams = new Application_Model_DbTable_UserParams();
$userParam = $modelUserParams->find(1)->current();
$user = $userParam->findParentRow('Application_Model_DbTable_Users');
Do opisanych powyżej funkcjonalności dochodzi jeszcze jedna. W każdym z przypadków możemy do metody dodać obiekt Zend_Db_Table_Select, którym mamy możliwość ograniczania wyników.
Nie są to jedyne możliwości oferowane przez relacje w Zend_Db. Mamy możliwość skorzystania z “magii”, czyli z metod automatycznie tłumaczonych na odpowiednie klasy oraz reguł (jeśli w jednej tabeli jest kilka kluczy obcych z innej tabeli).