
Ostatnio zainteresowałem się możliwością zastosowania Doctrine'a w jednym z moich projektów. Znalazłem wiele informacji na ten temat w internecie, niestety w większości zdezaktualizowanych. Okazało się że z wersji na wersję twórcy Doctrine coraz bardziej ułatwiają życie koderom piszącym w ZF. Aktualny przepis znalazłem na stronie ZendCasts. Podczas prób okazało się, że można to wszystko zrobić jeszcze prościej niż proponuje autor, zatem w tym wpisie podam własny przepis, przetestowany z Doctrine 1.2.1 i Zend-em 1.10 beta (1.9 też powinien działać).
Do stworzenia nowego projektu wykorzystam Zend_Tool - w obecnej wersji nie ma jeszcze zbyt rozbudowanych możliwości, jednak doskonale nadaje się do zbudowania podstawowej struktury naszej aplikacji.
Wystarczy jedno polecenie:
mateusz:~/public_html> zf create project zfdoctrine Creating project at /home/mateusz/public_html/zfdoctrine
Jeśli Zend_Tool jest poprawnie skonfigurowany to otrzymamy katalog zfdoctrine z działającym projektem. Następnym krokiem jest uzupełnienie podkatalogu library - kopiujemy lub linukujemy do niego Zenda i Doctrine (wystarczy folder /lib/Doctrine z pobranej paczki, no i oczywiście zawarte w nim pliki - lib/vendor i lib/Doctrine.php można pominąć).
Otwieramy plik zfdoctrine/application/configs/application.ini, dodajemy kilka linijek do sekcji [production] aby uzyskać następujący rezultat:
[production] phpSettings.display_startup_errors = 0 phpSettings.display_errors = 0 includePaths.library = APPLICATION_PATH "/../library" bootstrap.path = APPLICATION_PATH "/Bootstrap.php" bootstrap.class = "Bootstrap" appnamespace = "Application" resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" resources.frontController.moduleDirectory = APPLICATION_PATH "/modules" resources.frontController.params.displayExceptions = 0 resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/" resources.modules[] = autoloaderNamespaces[] = "Doctrine" doctrine.dsn = "mysql://UŻYTKOWNIK:HASŁO@localhost/NAZWA_BAZY" doctrine.data_fixtures_path = APPLICATION_PATH "/../doctrine/data/fixtures" doctrine.models_path = APPLICATION_PATH "/models" doctrine.migrations_path = APPLICATION_PATH "/../doctrine/migrations" doctrine.sql_path = APPLICATION_PATH "/../doctrine/data/sql" doctrine.yaml_schema_path = APPLICATION_PATH "/../doctrine/schema" doctrine.generate_models_options.pearStyle = true doctrine.generate_models_options.generateTableClasses = true doctrine.generate_models_options.generateBaseClasses = true doctrine.generate_models_options.baseClassPrefix = "Base_" doctrine.generate_models_options.baseClassesDirectory = doctrine.generate_models_options.classPrefixFiles = false doctrine.generate_models_options.classPrefix = "Application_Model_" [staging : production] [testing : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 [development : production] phpSettings.display_startup_errors = 1 phpSettings.display_errors = 1 resources.frontController.params.displayExceptions = 1
Tworzymy podkatalogi dla doctrine, zgodnie z powyższymi ustawieniami:
zfdoctrine/doctrine/data
zfdoctrine/doctrine/data/fixtures
zfdoctrine/doctrine/data/sql
zfdoctrine/doctrine/migrations
zfdoctrine/doctrine/schema
Edytujemy plik application/Bootstrap.php, dodając metodę _initDoctrine:
<?php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
public function _initDoctrine()
{
$doctrineConfig = $this->getOption('doctrine');
$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine_Core::ATTR_AUTO_ACCESSOR_OVERRIDE, true);
$conn = Doctrine_Manager::connection($doctrineConfig['dsn'],'doctrine');
$conn->setAttribute(Doctrine_Core::ATTR_USE_NATIVE_ENUM, true);
return $conn;
}
}
Jeśli zrobić porównanie do bootstrapu opisanego w screencascie, można zauważyć że mój jest dużo prostszy. To dlatego że moje modele będą miały nazwy w zalecanej przez twórców ZF konwencji (na przykład Application_Model_User). Przez to nie muszę zawracać sobie głowy autoloaderem Doctrine - Zend_Loader w zupełności wystarczy.
Ostatnia rzecz do zrobienia to konsolowy interfejs Doctrine. Proponuję umieścić skrypt w folderze /zfdoctrine/scripts, w pliku doctrine-cli.php:
<?php
define('APPLICATION_ENV', 'development');
define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
require_once 'Zend/Application.php';
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH . '/configs/application.ini'
);
$loader = Zend_Loader_Autoloader::getInstance();
$loader->pushAutoloader(array('Doctrine_Core', 'autoload'));
$application->getBootstrap()->bootstrap('doctrine');
$cli = new Doctrine_Cli($application->getOption('doctrine'));
$cli->run($_SERVER['argv']);
Z jakiegoś powodu w tym skrypcie trzeba wykorzystać autoloadera Doctrine. To nic - liczy się fakt że nie będzie zawadzał w samej aplikacji.
I to już wszystko. Nasz projekt jest gotowy do współpracy z Doctrine. Możemy teraz przetestować jego działanie działanie, budując przykładowy model.
W pliku zfdoctrine/doctrine/schema/schema.yml zdefiniujmy klasę User:
connection: doctrine
options:
collate: utf8_unicode_ci
charset: utf8
User:
tableName: users
columns:
id:
type: integer
fixed: false
unsigned: true
primary: true
autoincrement: true
name:
type: string(50)
notnull: true
password:
type: string(64)
notnull: true
email:
type: string(70)
notnull: true
Spróbujmy go zbudować przy pomocy linii poleceń:
mateusz:~/public_html/zfdoctrine/scripts# php5 ./doctrine-cli build-all-reload
Zostaniemy zapytani czy na pewno chcemy usunąć bazę danych (jeśli już istnieje). Naciskamy "Y". Jeżeli wszystko zrobiliśmy dobrze to skrypt uraczy nas następującymi komunikatami:
build-all-reload - Successfully dropped database for connection named 'doctrine' build-all-reload - Generated models successfully from YAML schema build-all-reload - Successfully created database for connection named 'doctrine' build-all-reload - Created tables successfully build-all-reload - Data was successfully loaded
Wreszcie, czas skorzystać z naszego modelu. W pliku IndexController.php, w akcji index wpisujemy kod:
$user = new Application_Model_User();
$user->email = 'aaa@bbb.pl';
$user->name = 'test';
$user->password = sha1('pass');
$user->save();
Otwieramy aplikację w przeglądarce a następnie sprawdzamy bazę danych - powinna zawierać zdefiniowanego wyżej użytkownika.