quickstart-create-model.xml 26 KB

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