quickstart-create-model.xml 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- EN-Revision: 20876 -->
  3. <!-- Reviewed: no -->
  4. <sect1 id="learning.quickstart.create-model">
  5. <title>Ein Modell und eine Datenbank Tabelle erstellen</title>
  6. <para>
  7. Bevor wir anfangen nehmen wie etwas an: Wo werden diese Klassen leben, und wie werden wir
  8. Sie finden? Das Standardprojekt welches wir erstellt haben instanziert einen Autoloader. Wir
  9. können Ihm andere Autoloader anhängen damit er weiss wo andere Klassen zu finden sind.
  10. Typischerweise wollen wir das unsere verschiedenen MVC Klassen im selben Baum gruppiert sind
  11. -- in diesem Fall <filename>application/</filename> -- und meistens einen gemeinsamen Präfix
  12. verwenden.
  13. </para>
  14. <para>
  15. <classname>Zend_Controller_Front</classname> hat den Begriff von "Modulen", welche
  16. individuelle Mini-Anwendungen sind. Module mimen die Verzeichnisstruktur welche das
  17. <command>zf</command> Tool unter <filename>application/</filename> einrichtet, und von allen
  18. Klassen in Ihm wird angenommen das Sie mit einen gemeinsamen Präfix beginnen, dem Namen des
  19. Moduls. <filename>application/</filename> selbst ist ein Modul -- das "default" oder
  20. "application" Modul. Als solches richten wir das Autoloading für Ressourcen in diesem
  21. Verzeichnis ein.
  22. </para>
  23. <para>
  24. <classname>Zend_Application_Module_Autoloader</classname> bietet die Funktionalität welche
  25. benötigt wird um die verschiedenen Ressourcen unter einem Modul mit den richtigen
  26. Verzeichnissen zu verbinden, und auch einen standardmäßigen Namensmechanismus. Standardmäßig
  27. wird eine Instanz der Klasse wärend der Initialisierung des Bootstrap Objekts erstellt;
  28. unser Application Bootstrap verwendet standardmäßig das Modulpräfix "Application". Daher
  29. beginnen alle unsere Modelle, Formulare, und Tabellenklassen mit dem Klassenpräfix
  30. "Application_".
  31. </para>
  32. <para>
  33. Nehmen wir jetzt also an was ein Guestbook ausmacht. Typischerweise sind Sie einfach eine
  34. Liste ein Einträgen mit einem <emphasis>Kommentar</emphasis> (comment), einem
  35. <emphasis>Zeitpunkt</emphasis> (timestamp) und oft einer <emphasis>Email Adresse</emphasis>.
  36. Angenommen wir speichern diese in einer Datenbank, dann wollen wir auch einen
  37. <emphasis>eindeutigen Identifikator</emphasis> für jeden Eintrag. Wir wollen in der Lage
  38. sein einen Eintrag zu speichern, individuelle Einträge zu holen, und alle Einträge zu
  39. empfangen. Als solches könnte das Modell einer einfachen Guestbook API wie folgt aussehen:
  40. </para>
  41. <programlisting language="php"><![CDATA[
  42. // application/models/Guestbook.php
  43. class Application_Model_Guestbook
  44. {
  45. protected $_comment;
  46. protected $_created;
  47. protected $_email;
  48. protected $_id;
  49. public function __set($name, $value);
  50. public function __get($name);
  51. public function setComment($text);
  52. public function getComment();
  53. public function setEmail($email);
  54. public function getEmail();
  55. public function setCreated($ts);
  56. public function getCreated();
  57. public function setId($id);
  58. public function getId();
  59. }
  60. class Application_Model_GuestbookMapper
  61. {
  62. public function save(Application_Model_Guestbook $guestbook);
  63. public function find($id);
  64. public function fetchAll();
  65. }
  66. ]]></programlisting>
  67. <para>
  68. <methodname>__get()</methodname> und <methodname>__set()</methodname> bieten uns bequeme
  69. Mechanismen an um auf individuelle Eigenschaften von Einträgen zuzugreifen und auf andere
  70. Getter und Setter zu verweisen. Sie stellen auch sicher das nur Eigenschaften im Objekt
  71. vorhanden sind die wir freigegeben haben.
  72. </para>
  73. <para>
  74. <methodname>find()</methodname> und <methodname>fetchAll()</methodname> bieten die Fähigkeit
  75. einen einzelnen Eintrag oder alle Einträge zu holen, wärend <methodname>save()</methodname>
  76. das Speichern der Einträge im Datenspeicher übernimmt.
  77. </para>
  78. <para>
  79. Von hier an können wir über die Einrichtung unserer Datenbank nachdenken.
  80. </para>
  81. <para>
  82. Zuerst muss unsere <classname>Db</classname> Ressource initialisiert werden. Wie bei der
  83. <classname>Layout</classname> und <classname>View</classname> kann die Konfiguration für die
  84. <classname>Db</classname> Ressource angegeben werden. Dies kann mit dem Befehl
  85. <command>zf configure db-adapter</command> getan werden:
  86. </para>
  87. <programlisting language="shell"><![CDATA[
  88. % zf configure db-adapter \
  89. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' \
  90. > production
  91. A db configuration for the production has been written to the application config file.
  92. % zf configure db-adapter \
  93. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-testing.db"' \
  94. > testing
  95. A db configuration for the production has been written to the application config file.
  96. % zf configure db-adapter \
  97. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-dev.db"' \
  98. > development
  99. A db configuration for the production has been written to the application config file.
  100. ]]></programlisting>
  101. <para>
  102. Jetzt muss die Datei <filename>application/configs/application.ini</filename> bearbeitet
  103. werden, und man kann sehen das die folgenden Zeilen in den betreffenden Abschnitten
  104. hinzugefügt wurden.
  105. </para>
  106. <programlisting language="ini"><![CDATA[
  107. ; application/configs/application.ini
  108. [production]
  109. ; ...
  110. resources.db.adapter = "PDO_SQLITE"
  111. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
  112. [testing : production]
  113. ; ...
  114. resources.db.adapter = "PDO_SQLITE"
  115. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
  116. [development : production]
  117. ; ...
  118. resources.db.adapter = "PDO_SQLITE"
  119. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
  120. ]]></programlisting>
  121. <para>
  122. Die endgültige Konfigurationsdatei sollte wie folgt aussehen:
  123. </para>
  124. <programlisting language="ini"><![CDATA[
  125. ; application/configs/application.ini
  126. [production]
  127. phpSettings.display_startup_errors = 0
  128. phpSettings.display_errors = 0
  129. bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
  130. bootstrap.class = "Bootstrap"
  131. appnamespace = "Application"
  132. resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
  133. resources.frontController.params.displayExceptions = 0
  134. resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
  135. resources.view[] =
  136. resources.db.adapter = "PDO_SQLITE"
  137. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
  138. [staging : production]
  139. [testing : production]
  140. phpSettings.display_startup_errors = 1
  141. phpSettings.display_errors = 1
  142. resources.db.adapter = "PDO_SQLITE"
  143. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
  144. [development : production]
  145. phpSettings.display_startup_errors = 1
  146. phpSettings.display_errors = 1
  147. resources.db.adapter = "PDO_SQLITE"
  148. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
  149. ]]></programlisting>
  150. <para>
  151. Es ist zu beachten das die Datenbank(en) unter <filename>data/db/</filename> gespeichert
  152. wird. Diese Verzeichnisse sind zu erstellen und weltweit-schreibbar zu machen. Auf
  153. Unix-artigen Systemen kann man das wie folgt durchführen:
  154. </para>
  155. <programlisting language="shell"><![CDATA[
  156. % mkdir -p data/db; chmod -R a+rwX data
  157. ]]></programlisting>
  158. <para>
  159. Unter Windows muss man die Verzeichnisse im Explorer erstellen und die Zugriffsrechte so zu
  160. setzen das jeder in das Verzeichnis schreiben darf.
  161. </para>
  162. <para>
  163. Ab diesem Punkt haben wir eine Verbindung zu einer Datenbank; in unserem Fall ist es eine
  164. verbindung zu einer Sqlite Datenbank die in unserem <filename>application/data/</filename>
  165. Verzeichnis ist. Designen wir also eine einfache Tabelle die unsere Guestbook Einträge
  166. enthalten wird.
  167. </para>
  168. <programlisting language="sql"><![CDATA[
  169. -- scripts/schema.sqlite.sql
  170. --
  171. -- Man muss das Datenbank Schema mit diesem SQL laden.
  172. CREATE TABLE guestbook (
  173. id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  174. email VARCHAR(32) NOT NULL DEFAULT 'noemail@test.com',
  175. comment TEXT NULL,
  176. created DATETIME NOT NULL
  177. );
  178. CREATE INDEX "id" ON "guestbook" ("id");
  179. ]]></programlisting>
  180. <para>
  181. Und damit wir gleich einige Arbeitsdaten haben, erstellen wir ein paar Zeilen an Information
  182. um unsere Anwendung interessant zu machen.
  183. </para>
  184. <programlisting language="sql"><![CDATA[
  185. -- scripts/data.sqlite.sql
  186. --
  187. -- Man kann damit beginnen die Datenbank zu befüllen indem die folgenden SQL
  188. -- Anweisungen ausgeführt werden.
  189. INSERT INTO guestbook (email, comment, created) VALUES
  190. ('ralph.schindler@zend.com',
  191. 'Hallo! Hoffentlich geniesst Ihr dieses Beispiel einer ZF Anwendung!
  192. DATETIME('NOW'));
  193. INSERT INTO guestbook (email, comment, created) VALUES
  194. ('foo@bar.com',
  195. 'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
  196. DATETIME('NOW'));
  197. ]]></programlisting>
  198. <para>
  199. Jetzt haben wir sowohl das Schema als auch einige Daten definiert. Schreiben wir also ein
  200. Skript das wir jetzt ausführen können um diese Datenbank zu erstellen. Natürlich wird das
  201. nicht in der Produktion benötigt, aber dieses Skriupt hilft Entwicklern die Notwendigkeiten
  202. der Datenbank lokal zu erstellen damit Sie eine voll funktionsfähige Anwendung haben. Das
  203. Skript ist als <filename>scripts/load.sqlite.php</filename> mit dem folgenden Inhalt zu
  204. erstellen:
  205. </para>
  206. <programlisting language="php"><![CDATA[
  207. // scripts/load.sqlite.php
  208. /**
  209. * Skript für das erstellen und Laden der Datenbank
  210. */
  211. // Initialisiert den Pfad und das Autoloading der Anwendung
  212. defined('APPLICATION_PATH')
  213. || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
  214. set_include_path(implode(PATH_SEPARATOR, array(
  215. APPLICATION_PATH . '/../library',
  216. get_include_path(),
  217. )));
  218. require_once 'Zend/Loader/Autoloader.php';
  219. Zend_Loader_Autoloader::getInstance();
  220. // Definiert einige CLI Optionen
  221. $getopt = new Zend_Console_Getopt(array(
  222. 'withdata|w' => 'Datenbank mit einigen Daten laden',
  223. 'env|e-s' => "Anwendungsumgebung für welche die Datenbank "
  224. . "erstellt wird (Standard ist Development)",
  225. 'help|h' => 'Hilfe -- Verwendung',
  226. ));
  227. try {
  228. $getopt->parse();
  229. } catch (Zend_Console_Getopt_Exception $e) {
  230. // Schlechte Option übergeben: Verwendung ausgeben
  231. echo $e->getUsageMessage();
  232. return false;
  233. }
  234. // Wenn Hilfe angefragt wurde, Verwendung ausgeben
  235. if ($getopt->getOption('h')) {
  236. echo $getopt->getUsageMessage();
  237. return true;
  238. }
  239. // Werte basierend auf Ihrer Anwesenheit oder Abwesenheit von CLI Optionen initialisieren
  240. $withData = $getopt->getOption('w');
  241. $env = $getopt->getOption('e');
  242. defined('APPLICATION_ENV')
  243. || define('APPLICATION_ENV', (null === $env) ? 'development' : $env);
  244. // Zend_Application initialisieren
  245. $application = new Zend_Application(
  246. APPLICATION_ENV,
  247. APPLICATION_PATH . '/configs/application.ini'
  248. );
  249. // Die DB Ressource initialisieren und empfangen
  250. $bootstrap = $application->getBootstrap();
  251. $bootstrap->bootstrap('db');
  252. $dbAdapter = $bootstrap->getResource('db');
  253. // Den Benutzer informieren was abgeht
  254. // (wir erstellen hier aktuell eine Datenbank)
  255. if ('testing' != APPLICATION_ENV) {
  256. echo 'Schreiben in die Guestbook Datenbank (control-c um abzubrechen): ' . PHP_EOL;
  257. for ($x = 5; $x > 0; $x--) {
  258. echo $x . "\r"; sleep(1);
  259. }
  260. }
  261. // Prüfen um zu sehen ob wie bereits eine Datenbankdatei haben
  262. $options = $bootstrap->getOption('resources');
  263. $dbFile = $options['db']['params']['dbname'];
  264. if (file_exists($dbFile)) {
  265. unlink($dbFile);
  266. }
  267. // Dieser Block führt die aktuellen Statements aus welche von der Schemadatei
  268. // geladen werden.
  269. try {
  270. $schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');
  271. // Die Verbindung direkt verwenden um SQL im Block zu laden
  272. $dbAdapter->getConnection()->exec($schemaSql);
  273. chmod($dbFile, 0666);
  274. if ('testing' != APPLICATION_ENV) {
  275. echo PHP_EOL;
  276. echo 'Datenbank erstellt';
  277. echo PHP_EOL;
  278. }
  279. if ($withData) {
  280. $dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');
  281. // Die Verbindung direkt verwenden um SQL in Blöcken zu laden
  282. $dbAdapter->getConnection()->exec($dataSql);
  283. if ('testing' != APPLICATION_ENV) {
  284. echo 'Daten geladen.';
  285. echo PHP_EOL;
  286. }
  287. }
  288. } catch (Exception $e) {
  289. echo 'EIN FEHLER IST AUFGETRETEN:' . PHP_EOL;
  290. echo $e->getMessage() . PHP_EOL;
  291. return false;
  292. }
  293. // Generell gesprochen wird dieses Skript von der Kommandozeile aus aufgerufen
  294. return true;
  295. ]]></programlisting>
  296. <para>
  297. Jetzt führen wir dieses Skript aus. Von einem Terminal oder der DOS Kommandozeile ist das
  298. folgende zu tun:
  299. </para>
  300. <programlisting language="shell"><![CDATA[
  301. % php scripts/load.sqlite.php --withdata
  302. ]]></programlisting>
  303. <para>
  304. Man sollte eine ähnliche Ausgabe wie folgt sehen:
  305. </para>
  306. <programlisting language="text"><![CDATA[
  307. path/to/ZendFrameworkQuickstart/scripts$ php load.sqlite.php --withdata
  308. Schreiben in die Guestbook Datenbank (control-c um abzubrechen):
  309. 1
  310. Datenbank erstellt
  311. Daten geladen.
  312. ]]></programlisting>
  313. <para>
  314. Jetzt haben wir eine voll funktionsfähige Datenbank und eine Tabelle für unsere Guestbook
  315. Anwendung. Unsere nächsten paar Schritte sind die Ausarbeitung unseres Anwendungscodes. Das
  316. inkludiert das Bauen einer Datenquelle (in unserem Fall verwenden wir
  317. <classname>Zend_Db_Table</classname>), und einen Daten Mapper um diese Datenquelle mit
  318. unserem Domain Modell zu verbinden. Letztendlich erstellen wir den Controller der mit diesem
  319. Modell interagiert damit sowohl existierende Einträge angezeigt als auch neue Einträge
  320. bearbeitet werden.
  321. </para>
  322. <para>
  323. Wir verwenden ein <ulink
  324. url="http://martinfowler.com/eaaCatalog/tableDataGateway.html">Table Data
  325. Gateway</ulink> um uns mit unserer Datenquelle zu verbinden;
  326. <classname>Zend_Db_Table</classname> bietet diese Funktionalität. Um anzufangen erstellen
  327. wir eine <classname>Zend_Db_Table</classname>-basierende Tabellenklasse. Wie wir es für
  328. Layouts und den Datenbank Adapter getan haben, können wir das <command>zf</command> Tool
  329. verwenden um uns zu assistieren indem der Befehl <command>create db-table</command>
  330. verwendet wird. Dieser nimmt mindestens zwei Argumente, den Namen mit dem man auf die Klasse
  331. referenzieren will, und die Datenbanktabelle auf die Sie zeigt.
  332. </para>
  333. <programlisting language="shell"><![CDATA[
  334. % zf create db-table Guestbook guestbook
  335. Creating a DbTable at application/models/DbTable/Guestbook.php
  336. Updating project profile 'zfproject.xml'
  337. ]]></programlisting>
  338. <para>
  339. Wenn man in der Verzeichnisbaum sieht, dann wird man jetzt sehen das ein neues Verzeichnis
  340. <filename>application/models/DbTable/</filename> zusammen mit der Datei
  341. <filename>Guestbook.php</filename> erstellt wurde. Wenn man die Datei öffnet wird man den
  342. folgenden Inhalt sehen:
  343. </para>
  344. <programlisting language="php"><![CDATA[
  345. // application/models/DbTable/Guestbook.php
  346. /**
  347. * Das ist die DbTable Klasse für die Guestbook Tabelle.
  348. */
  349. class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
  350. {
  351. /** Tabellenname */
  352. protected $_name = 'guestbook';
  353. }
  354. ]]></programlisting>
  355. <para>
  356. Der Klassenpräfix ist zu beachten: <classname>Application_Model_DbTable</classname>. Der
  357. Klassenpräfix für unser Modul "Application" ist das erste Segment, und dann haben wir die
  358. Komponente "Model_DbTable"; die letztere verweist auf das Verzeichnis
  359. <filename>models/DbTable/</filename> des Moduls.
  360. </para>
  361. <para>
  362. Alles das ist wirklich notwendig wenn <classname>Zend_Db_Table</classname> erweitert wird
  363. um einen Tabellennamen anzubieten und optional den primären Schlüssel (wenn es nicht die
  364. "id" ist).
  365. </para>
  366. <para>
  367. Jetzt erstellen wir einen <ulink
  368. url="http://martinfowler.com/eaaCatalog/dataMapper.html">Daten Mapper</ulink>. Ein
  369. <emphasis>Daten Mapper</emphasis> bildet ein Domain Objekt in der Datenbank ab. In unserem
  370. Fall bildet es unser Modell <classname>Application_Model_Guestbook</classname> auf unsere
  371. Datenquelle, <classname>Application_Model_DbTable_Guestbook</classname>, ab. Eine typische
  372. API für einen Daten Mapper ist wie folgt:
  373. </para>
  374. <programlisting language="php"><![CDATA[
  375. // application/models/GuestbookMapper.php
  376. class Application_Model_GuestbookMapper
  377. {
  378. public function save($model);
  379. public function find($id, $model);
  380. public function fetchAll();
  381. }
  382. ]]></programlisting>
  383. <para>
  384. Zusätzlich zu diesen Methoden, fügen wir Methoden für das Setzen und Holen des Table Data
  385. Gateways hinzu. Um die initiale Klasse zu erstellen kann das <command>zf</command> CLI
  386. Tool verwendet werden:
  387. </para>
  388. <programlisting language="shell"><![CDATA[
  389. % zf create model GuestbookMapper
  390. Creating a model at application/models/GuestbookMapper.php
  391. Updating project profile '.zfproject.xml'
  392. ]]></programlisting>
  393. <para>
  394. Jetzt muss die Klasse <classname>Application_Model_GuestbookMapper</classname> welche in
  395. <filename>application/models/GuestbookMapper.php</filename> gefunden werden kann so
  396. geändert werden dass Sie wie folgt zu lesen ist:
  397. </para>
  398. <programlisting language="php"><![CDATA[
  399. // application/models/GuestbookMapper.php
  400. class Application_Model_GuestbookMapper
  401. {
  402. protected $_dbTable;
  403. public function setDbTable($dbTable)
  404. {
  405. if (is_string($dbTable)) {
  406. $dbTable = new $dbTable();
  407. }
  408. if (!$dbTable instanceof Zend_Db_Table_Abstract) {
  409. throw new Exception('Ungültiges Table Data Gateway angegeben');
  410. }
  411. $this->_dbTable = $dbTable;
  412. return $this;
  413. }
  414. public function getDbTable()
  415. {
  416. if (null === $this->_dbTable) {
  417. $this->setDbTable('Application_Model_DbTable_Guestbook');
  418. }
  419. return $this->_dbTable;
  420. }
  421. public function save(Application_Model_Guestbook $guestbook)
  422. {
  423. $data = array(
  424. 'email' => $guestbook->getEmail(),
  425. 'comment' => $guestbook->getComment(),
  426. 'created' => date('Y-m-d H:i:s'),
  427. );
  428. if (null === ($id = $guestbook->getId())) {
  429. unset($data['id']);
  430. $this->getDbTable()->insert($data);
  431. } else {
  432. $this->getDbTable()->update($data, array('id = ?' => $id));
  433. }
  434. }
  435. public function find($id, Application_Model_Guestbook $guestbook)
  436. {
  437. $result = $this->getDbTable()->find($id);
  438. if (0 == count($result)) {
  439. return;
  440. }
  441. $row = $result->current();
  442. $guestbook->setId($row->id)
  443. ->setEmail($row->email)
  444. ->setComment($row->comment)
  445. ->setCreated($row->created);
  446. }
  447. public function fetchAll()
  448. {
  449. $resultSet = $this->getDbTable()->fetchAll();
  450. $entries = array();
  451. foreach ($resultSet as $row) {
  452. $entry = new Application_Model_Guestbook();
  453. $entry->setId($row->id)
  454. ->setEmail($row->email)
  455. ->setComment($row->comment)
  456. ->setCreated($row->created)
  457. ->setMapper($this);
  458. $entries[] = $entry;
  459. }
  460. return $entries;
  461. }
  462. }
  463. ]]></programlisting>
  464. <para>
  465. Jetzt ist es Zeit unsere Modellklasse zu erstellen. Wir machen dies indem wieder das
  466. Kommando <command>zf create model</command> verwendet wird:
  467. </para>
  468. <programlisting language="shell"><![CDATA[
  469. % zf create model Guestbook
  470. Creating a model at application/models/Guestbook.php
  471. Updating project profile '.zfproject.xml'
  472. ]]></programlisting>
  473. <para>
  474. Wir verändern diese leere PHP Klasse um es einfach zu machen das Modell
  475. bekanntzugeben indem ein Array an Daten entweder an den Constructor oder an die
  476. <methodname>setOptions()</methodname> Methode übergeben wird. Das endgültige Modell, welches
  477. in <filename>application/models/Guestbook.php</filename> ist, sollte wie folgt aussehen:
  478. </para>
  479. <programlisting language="php"><![CDATA[
  480. // application/models/Guestbook.php
  481. class Application_Model_Guestbook
  482. {
  483. protected $_comment;
  484. protected $_created;
  485. protected $_email;
  486. protected $_id;
  487. public function __construct(array $options = null)
  488. {
  489. if (is_array($options)) {
  490. $this->setOptions($options);
  491. }
  492. }
  493. public function __set($name, $value)
  494. {
  495. $method = 'set' . $name;
  496. if (('mapper' == $name) || !method_exists($this, $method)) {
  497. throw new Exception('Ungültige Guestbook Eigenschaft');
  498. }
  499. $this->$method($value);
  500. }
  501. public function __get($name)
  502. {
  503. $method = 'get' . $name;
  504. if (('mapper' == $name) || !method_exists($this, $method)) {
  505. throw new Exception('Ungültige Guestbook Eigenschaft');
  506. }
  507. return $this->$method();
  508. }
  509. public function setOptions(array $options)
  510. {
  511. $methods = get_class_methods($this);
  512. foreach ($options as $key => $value) {
  513. $method = 'set' . ucfirst($key);
  514. if (in_array($method, $methods)) {
  515. $this->$method($value);
  516. }
  517. }
  518. return $this;
  519. }
  520. public function setComment($text)
  521. {
  522. $this->_comment = (string) $text;
  523. return $this;
  524. }
  525. public function getComment()
  526. {
  527. return $this->_comment;
  528. }
  529. public function setEmail($email)
  530. {
  531. $this->_email = (string) $email;
  532. return $this;
  533. }
  534. public function getEmail()
  535. {
  536. return $this->_email;
  537. }
  538. public function setCreated($ts)
  539. {
  540. $this->_created = $ts;
  541. return $this;
  542. }
  543. public function getCreated()
  544. {
  545. return $this->_created;
  546. }
  547. public function setId($id)
  548. {
  549. $this->_id = (int) $id;
  550. return $this;
  551. }
  552. public function getId()
  553. {
  554. return $this->_id;
  555. }
  556. }
  557. ]]></programlisting>
  558. <para>
  559. Letztendlich, um diese Elemente alle zusammen zu verbinden, erstellen wir einen Guestbook
  560. Controller der die Einträge auflistet welche aktuell in der Datenbank sind.
  561. </para>
  562. <para>
  563. Um einen neuen Controller zu erstellen muss das Kommando
  564. <command>zf create controller</command> verwendet werden:
  565. </para>
  566. <programlisting language="shell"><![CDATA[
  567. % zf create controller Guestbook
  568. Creating a controller at
  569. application/controllers/GuestbookController.php
  570. Creating an index action method in controller Guestbook
  571. Creating a view script for the index action method at
  572. application/views/scripts/guestbook/index.phtml
  573. Creating a controller test file at
  574. tests/application/controllers/GuestbookControllerTest.php
  575. Updating project profile '.zfproject.xml'
  576. ]]></programlisting>
  577. <para>
  578. Das erstellt einen neuen Controller, <classname>GuestbookController</classname>, in
  579. <filename>application/controllers/GuestbookController.php</filename> mit einer einzelnen
  580. Aktions Methode, <methodname>indexAction()</methodname>. Er erstellt auch ein View Skript
  581. Verzeichnis für den Controller, <filename>application/views/scripts/guestbook/</filename>,
  582. mit einem View Skript für die Index Aktion.
  583. </para>
  584. <para>
  585. Wir verwenden die "index" Aktion als Landeseite um alle Guestbook Einträge anzusehen.
  586. </para>
  587. <para>
  588. Jetzt betrachten wir die grundsätzliche Anwendungslogik. Bei einem Treffer auf
  589. <methodname>indexAction()</methodname> zeigen wir alle Guestbook Einträge an. Das würde wie
  590. folgt aussehen:
  591. </para>
  592. <programlisting language="php"><![CDATA[
  593. // application/controllers/GuestbookController.php
  594. class GuestbookController extends Zend_Controller_Action
  595. {
  596. public function indexAction()
  597. {
  598. $guestbook = new Application_Model_GuestbookMapper();
  599. $this->view->entries = $guestbook->fetchAll();
  600. }
  601. }
  602. ]]></programlisting>
  603. <para>
  604. Und natürlich benötigen wir ein View Skript um damit weiterzumachen.
  605. <filename>application/views/scripts/guestbook/index.phtml</filename> ist zu bearbeiten damit
  606. Sie wie folgt aussieht:
  607. </para>
  608. <programlisting language="php"><![CDATA[
  609. <!-- application/views/scripts/guestbook/index.phtml -->
  610. <p><a href="<?php echo $this->url(
  611. array(
  612. 'controller' => 'guestbook',
  613. 'action' => 'sign'
  614. ),
  615. 'default',
  616. true) ?>">Im Guestbook eintragen</a></p>
  617. Guestbook Einträge: <br />
  618. <dl>
  619. <?php foreach ($this->entries as $entry): ?>
  620. <dt><?php echo $this->escape($entry->email) ?></dt>
  621. <dd><?php echo $this->escape($entry->comment) ?></dd>
  622. <?php endforeach ?>
  623. </dl>
  624. ]]></programlisting>
  625. <note>
  626. <title>Checkpoint</title>
  627. <para>
  628. Jetzt gehen wir auf "http://localhost/guestbook". Man sollte das folgende im Browser
  629. sehen:
  630. </para>
  631. <para>
  632. <inlinegraphic width="525" scale="100" align="center" valign="middle"
  633. fileref="figures/learning.quickstart.create-model.png" format="PNG" />
  634. </para>
  635. </note>
  636. <note>
  637. <title>Das Datenlade Skript verwenden</title>
  638. <para>
  639. Das Datenlade Skript welches in diesem Kapitel beschrieben wird
  640. (<filename>scripts/load.sqlite.php</filename>) kann verwendet werden um die Datenbank,
  641. für jede Umgebung die man definiert hat, zu erstellen sowie Sie mit Beispieldaten zu
  642. laden. Intern verwendet es <classname>Zend_Console_Getopt</classname>, was es erlaubt
  643. eine Anzahl von Kommandozeilen Schalter anzubieten. Wenn man den "-h" oder "--help"
  644. Schalter übergibt, werden die folgenden Optionen angegeben:
  645. </para>
  646. <programlisting language="php"><![CDATA[
  647. Usage: load.sqlite.php [ options ]
  648. --withdata|-w Datenbank mit einigen Daten laden
  649. --env|-e [ ] Anwendungsumgebung für welche die Datenbank erstellt wird
  650. (Standard ist Development)
  651. --help|-h Hilfe -- Verwendung)]]
  652. ]]></programlisting>
  653. <para>
  654. Der "-e" Schalter erlaubt es den Wert zu spezifizieren der für die Konstante
  655. <constant>APPLICATION_ENV</constant> verwendet wird -- welcher es erlaubt eine SQLite
  656. Datenbank für jede Umgebung zu erstellen die man definiert. Man sollte sicherstellen
  657. dass das Skript für die Umgebung gestartet wird welche man für die eigene Anwendung
  658. ausgewählt hat wenn man in Betrieb geht.
  659. </para>
  660. </note>
  661. </sect1>