Korzystając z Symfony bardzo spodobała mi się praca z Propelem i Doctrine (bardziej do gustu przypadło mi jednak Doctrine). Jako że domyślny silnik bazodanowy Zenda pozostawia wiele do życzenia, postanowiłem go zamienić na Doctrine. Osoby, które jeszcze nie spotkały się nigdy wcześniej z Doctrine zapraszam na stronę projektu - znajdziecie tam wszystkie niezbędne informacje.
Integracja Doctrine z Zendem nie należy do trudnych, a rozpocząć jÄ… należy od pobrania biblioteki Doctrine , i umieszczeniu zawartoÅ›ci katalog “lib” (plik Doctrine.php i katalog z bibliotekÄ…) w “lib” naszej struktury aplikacji.
Niezbędne będą drobne modyfikacji struktury naszej aplikacji - umiejscowienie bibliotek, schmatów i wygenerowanych modeli jest dowolne, jednak moja struktura jest zasugerowana w niewielkim stopniu podobną w Symfony.
Szkielet aplikacji po małych modyfikacjach:
index.php
application/
assistant/
plugin/
models/
generated/
modules/
default/
controllers/
models/
views/
admin/
controllers/
models/
views/
library/
Zend/
Core/
Doctrine/
data/
sql/
migrations/
fixtures/
config/
public/
images/
js/
css/
cache/
templates_c
smarty_cache
Dodałem kilka nowych katalogów:
- config - tutaj przeniesiemy główny plik konfiguracyjny aplikacji: config.ini. W tym miejcu umieścimy również plik schema.yml na podstawie którego będziemy budowali modele aplikacji.
- data - pliki dla doctrine, np wygenerowany plik sql bazy.
- application/models i application/models/generated - wygenerowane modele aplikacji.
W pierwszej kolejności ustawimy niezbędne ścieżki w pliku index.php:
<?php set_include_path( '.' . PATH_SEPARATOR . './library/' . PATH_SEPARATOR . './application/assistant/' . PATH_SEPARATOR . './application/modules/' . PATH_SEPARATOR . './application/models/' . PATH_SEPARATOR . './application/models/generated' . get_include_path() ); ?>
Należy usunąć linijkę w której rejestrujemy Plugin_ModelDirectory - nie będzie nam On już potrzebny, podobnie jak katalogi models w poszczególnych modułach (były niezbędne dla Zend_db_Table). W jego miejscy zarejestrujemy nowy plugin: Plugin_Doctrine, który będzie odpowiadał ze nawiązanie połączenia. Plik Doctrine.php należy umieścić w katalogu: application/assistant/plugin/:
<?php
require_once 'Zend/Controller/Plugin/Abstract.php';
class Plugin_Doctrine extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $req)
{
$db = self::connect( Zend_Registry::get('config') );
if ($data->charset) {
$db->setCharset($data->charset);
}
Zend_Registry::set('db', $db);
return $this;
}
public static function connect($config){
$data = $config->database;
$dsn = sprintf(
'%s://%s:%s@%s/%s',
strtolower($data->type),
$data->username,
$data->password,
$data->host,
$data->dbname
);
$db = Doctrine_Manager::connection($dsn);
return $db;
}
}
?>
Celowo umieściłem samą akcję nawiązania połączenia w metodzie statycznej, by móc ją później wykorzystać w pliku: doctrine-cli.php. Możemy w tym momencie przenieść config.ini do katalogu config, zmienić dla niego ścieżkę dostępu i nanieść małe poprawki w konfiguracji bazy danych pliku config.ini:
Rejestracja pluginu + poprawka ścieżki dostępu dla konfiguracji:
<?php
$config = new Zend_Config_Ini('config/config.ini', null);
$front->registerPlugin(new Plugin_Doctrine());
?>
Sekcja bazy danych pliku konfiguracyjnego:
[database] name = "db" type = "mysql" dbname = "dbname host = "localhost" username = "user" password = "pass" charset = "utf8"
Następnie zajmiemy się ustawieniami skryptu doctrine-cli.php, który należy umieścić w głównym katalogu aplikacji:
<?php
set_include_path(
'.' . PATH_SEPARATOR .
'./library/' . PATH_SEPARATOR .
'./application/assistant/' . PATH_SEPARATOR .
'./application/models/' . PATH_SEPARATOR .
'./application/models/generated/' . PATH_SEPARATOR . get_include_path()
);
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();
$config = array(
'data_fixtures_path' => './data/fixtures/',
'migrations_path' => './data/migrations/',
'sql_path' => './data/sql/',
'yaml_schema_path' => './config/',
'models_path' => './application/models/'
);
$connection = Plugin_Doctrine::connect( new Zend_Config_Ini('./config/config.ini', null) );
$cli = new Doctrine_Cli($config);
if (isset($_GET['cmd'])) {
$_SERVER['argv'] = array('doctrine-cli.php', $_GET['cmd']);
}
$cli->run($_SERVER['argv']);
?>
Skrypt ten będziemy wywoływali z poziomu linii komend systemu operacyjnego, znajdując się w głównym katalogu aplikacji. Odpowiada on za generowanie klas modelu. Dodatkowo jednak może tworzyć strukturę bazy danych, eksportować/importować dane z/do bazy. Klasa Doctrine_Cli jako parametr przyjmuje tablice parametrów - ścieżek, niezbędnych do generowanie odpowiednich plików.
By wyświetlić dostępne komendy skryptu należy po prostu wpisać doctrine-cli.
Przykładowe polecenia:
- doctrine-cli generate-models-yaml - generuje modele na podstawie pliku schema.yml
- doctrine-cli generate-sql - tworzy sql na podstawie wygenerowanych wcześniej modeli
- doctrine-cli create-tables - wykonuje zapytania sql - tworzy tabele bazy danych
Strukturę tabeli zaleca się tworzyć w pliku schema.yml, jednak nie jest to konieczne. Równie dobrze możemy utworzyć strukturę bazy za pomocą dowolnego kreatora, a następnie wywołać doctrine-cli.php generate-yaml-db, by skrypt wygenerował nam strukturę bazy do pliku schema.yml.
Więcej na ten temat napiszę następnym razem. Postaram się również przedstawić prosty, praktyczny przykład wykorzystania Doctrine i Zenda.
“podobnie jak katalogi models w poszczególnych moduÅ‚ach (byÅ‚y niezbÄ™dne dla Zend_db_Table) ” - no i jaki sens ma moduÅ‚ który ma widoki kontroler a nie ma ma modelu ?
Nie nie stoi na przeszkodzie byś tak ustawił Doctrine by genenrował Ci modele w różnych modułach - możesz to sobie wrzucić w dowolne miejsce - chodzi jednak o to, by było to jak najbardziej elastyczne rozwiązanie. Wg mojego rozwiązania wszystkie moduły korzystają ze wspólnych modeli, które znajdują się w katalogu models. Nie bardzo widzę sens w umieszczaniu np dwoch modeli w jednym module, pozostalych w drugim. Możnaby umieszcać w danym module tylko modele z których korzysta, ale co wtedy z modelami wykorzystywanymi przez różne moduły?
mi siÄ™ wydaje że każdy moduÅ‚ ma być możliwie niezależnÄ… jednostkÄ…/strukturÄ…. A jeżeli jakiÅ› moduÅ‚ chce skorzystać z możliwoÅ›ci innego to albo za jego poÅ›rednictwem, albo zrobic sobie metodÄ™ getModel(’modelClass’, ‘moduleName’) i tyle. Ale faktycznie wszystko zależy od wÅ‚asnych upodobaÅ„
A możesz jeszcze pokazać plik application.ini ??
Chodzi Ci chyba o config.ini ?
Artykuł bardzo ciekawy i przydatny aczkolwiek jedynie do starczej wersji biblioteki. Podany przez ciebie sposób nie działa na bibliotece ZF > 1.8, dlatego też po kilku próbach i paru godzinkach boju udało mi się zintegrować Doctrine z najnowszym Zend Framework 1.9.3 - http://holewa.pl/dawid/2009/09/zend-framework-v-1-9-3-i-doctrine-1-1-4/.
W swoim wpisie nawiązałem do twojego bloga więc liczę, że nie będziesz miał nic przeciwko.
Gratuluję bloga i czekam na kolejne równie wartościowe artykuły.