quickstart-create-model.xml 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- Reviewed: no -->
  3. <!-- EN-Revision: 23473 -->
  4. <sect1 id="learning.quickstart.create-model">
  5. <title>モデルとデータベーステーブルの作成</title>
  6. <para>
  7. 始める前にちょっと考えてみましょう。これらのクラスはどこにあって、それをどのように探すのでしょうか?
  8. わたしたちが作成したデフォルトのプロジェクトでは、一つのオートローダーがインスタンス化されます。
  9. そこへ、他のクラスを探せるよう別のオートローダーを付け加えることができます。
  10. MVC の様々なクラスはふつう一つのツリー -- ここでは <filename>application/</filename> --
  11. に集まっていて、ほとんどの場合には共通のプレフィックスを持っていてほしいものです。
  12. </para>
  13. <para>
  14. <classname>Zend_Controller_Front</classname> は、独立したミニアプリケーション、
  15. すなわち "モジュール" という考え方を採用しています。モジュールは <command>zf</command>
  16. ツールが <filename>application/</filename> 以下に設定するディレクトリ構造を模倣しており、
  17. その中の全てのクラスはモジュール名を共通のプレフィックスとして持っているものと見なされます。
  18. <filename>application/</filename> はそれ自体が一つのモジュール -- "default" または "application"
  19. モジュール -- です。以上を踏まえてこのディレクトリ下にあるリソースのオートロードを設定していきたいと思います。
  20. </para>
  21. <para>
  22. <classname>Zend_Application_Module_Autoloader</classname> は、あるモジュールの様々なリソースを
  23. 適切なディレクトリに対応付けるために必要となる機能を提供し、同時に、名前の付け方の規約も提供します。
  24. このクラスのインスタンスは、デフォルトではブートストラップ・オブジェクトの初期化時に作成され、
  25. アプリケーションのブートストラップでは "Application" というプレフィックスをデフォルトで使用します。
  26. そのため、モデル、フォーム、テーブル・クラスはどれも、プレフィックス "Application_" で始めます。
  27. </para>
  28. <para>
  29. では、ゲストブックを作っていくことにしましょう。一般的には<emphasis>コメント</emphasis>、
  30. <emphasis>タイムスタンプ</emphasis>、それからたまに<emphasis>メールアドレス</emphasis>を持つ単純なリストになります。
  31. それらをデータベースに保存するとしたら、各エントリーのユニークな識別子も欲しいかも知れません。
  32. エントリーを保存したり特定のエントリーを取ってきたり全エントリーを読み出したくなることでしょう。
  33. そうだとすると、簡単なゲストブックモデルの <acronym>API</acronym> はこのようになりそうです。
  34. </para>
  35. <programlisting language="php"><![CDATA[
  36. // application/models/Guestbook.php
  37. class Application_Model_Guestbook
  38. {
  39. protected $_comment;
  40. protected $_created;
  41. protected $_email;
  42. protected $_id;
  43. public function __set($name, $value);
  44. public function __get($name);
  45. public function setComment($text);
  46. public function getComment();
  47. public function setEmail($email);
  48. public function getEmail();
  49. public function setCreated($ts);
  50. public function getCreated();
  51. public function setId($id);
  52. public function getId();
  53. }
  54. class Application_Model_GuestbookMapper
  55. {
  56. public function save(Application_Model_Guestbook $guestbook);
  57. public function find($id);
  58. public function fetchAll();
  59. }
  60. ]]></programlisting>
  61. <para>
  62. <methodname>__get()</methodname> と <methodname>__set()</methodname> は、
  63. 各エントリーのプロパティにアクセスする便利な仕組みと、他のゲッター、セッターのプロキシ提供してくれます。
  64. また、オブジェクト中の許可したプロパティのみアクセス可能にするのにも役立ちます。
  65. </para>
  66. <para>
  67. <methodname>find()</methodname> と <methodname>fetchAll()</methodname> は単一のエントリー、
  68. 全てのエントリーをフェッチする機能を提供し、<methodname>save()</methodname> は
  69. 一つのエントリーをデータストアに保存する面倒を見ます。
  70. </para>
  71. <para>
  72. ここでようやく、データベース設定について考え始めることができます。
  73. </para>
  74. <para>
  75. まず <classname>Db</classname> リソースを初期化する必要があります。
  76. <classname>Layout</classname> と <classname>View</classname> リソースから <classname>Db</classname>
  77. リソースの設定を準備できます。これには <command>zf configure db-adapter</command> コマンドが使えます。
  78. </para>
  79. <programlisting language="shell"><![CDATA[
  80. % zf configure db-adapter \
  81. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' \
  82. > production
  83. A db configuration for the production has been written to the application config file.
  84. % zf configure db-adapter \
  85. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-testing.db"' \
  86. > testing
  87. A db configuration for the production has been written to the application config file.
  88. % zf configure db-adapter \
  89. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-dev.db"' \
  90. > development
  91. A db configuration for the production has been written to the application config file.
  92. ]]></programlisting>
  93. <para>
  94. ここで <filename>application/configs/application.ini</filename> ファイルの相当する部分に
  95. 以下の行が追加されているのが見付かるので、編集します。
  96. </para>
  97. <programlisting language="ini"><![CDATA[
  98. ; application/configs/application.ini
  99. [production]
  100. ; ...
  101. resources.db.adapter = "PDO_SQLITE"
  102. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
  103. [testing : production]
  104. ; ...
  105. resources.db.adapter = "PDO_SQLITE"
  106. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
  107. [development : production]
  108. ; ...
  109. resources.db.adapter = "PDO_SQLITE"
  110. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
  111. ]]></programlisting>
  112. <para>
  113. 設定ファイルが最終的に以下のようになるようにしてください。
  114. </para>
  115. <programlisting language="ini"><![CDATA[
  116. ; application/configs/application.ini
  117. [production]
  118. phpSettings.display_startup_errors = 0
  119. phpSettings.display_errors = 0
  120. bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
  121. bootstrap.class = "Bootstrap"
  122. appnamespace = "Application"
  123. resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
  124. resources.frontController.params.displayExceptions = 0
  125. resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
  126. resources.view[] =
  127. resources.db.adapter = "PDO_SQLITE"
  128. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
  129. [staging : production]
  130. [testing : production]
  131. phpSettings.display_startup_errors = 1
  132. phpSettings.display_errors = 1
  133. resources.db.adapter = "PDO_SQLITE"
  134. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
  135. [development : production]
  136. phpSettings.display_startup_errors = 1
  137. phpSettings.display_errors = 1
  138. resources.db.adapter = "PDO_SQLITE"
  139. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
  140. ]]></programlisting>
  141. <para>
  142. データベースは <filename>data/db/</filename> に保存されることに注意しましょう。
  143. ディレクトリを作って全ユーザーに書き込み権限を与えます。ユニックスライクなシステムでは、
  144. 次のようにすれば設定できます。
  145. </para>
  146. <programlisting language="shell"><![CDATA[
  147. % mkdir -p data/db; chmod -R a+rwX data
  148. ]]></programlisting>
  149. <para>
  150. Windows では、エクスプローラでディレクトリを作り、
  151. 全ユーザーがそのディレクトリに書き込めるようアクセス権を設定する必要があります。
  152. </para>
  153. <para>
  154. この段階でデータベース接続が行えます。今の例では <filename>application/data/</filename>
  155. ディレクトリ内にある Sqlite データベースへの接続です。では、ゲストブックのエントリーを入れる簡単なテーブルを設計しましょう。
  156. </para>
  157. <programlisting language="sql"><![CDATA[
  158. -- scripts/schema.sqlite.sql
  159. --
  160. -- この SQL からデータベーススキーマをロードする必要があります。
  161. CREATE TABLE guestbook (
  162. id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  163. email VARCHAR(32) NOT NULL DEFAULT 'noemail@test.com',
  164. comment TEXT NULL,
  165. created DATETIME NOT NULL
  166. );
  167. CREATE INDEX "id" ON "guestbook" ("id");
  168. ]]></programlisting>
  169. <para>
  170. それから、素晴らしい仕事ができるように、数行、アプリケーションを面白くするする情報を作りましょう。
  171. </para>
  172. <programlisting language="sql"><![CDATA[
  173. -- scripts/data.sqlite.sql
  174. --
  175. -- 以下の SQL 文でデータベースに生命を吹き込めます。
  176. INSERT INTO guestbook (email, comment, created) VALUES
  177. ('ralph.schindler@zend.com',
  178. 'Hello! Hope you enjoy this sample zf application!',
  179. DATETIME('NOW'));
  180. INSERT INTO guestbook (email, comment, created) VALUES
  181. ('foo@bar.com',
  182. 'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
  183. DATETIME('NOW'));
  184. ]]></programlisting>
  185. <para>
  186. これでスキーマができ、データもいくらか定義できました。それでは一緒にスクリプトを書いてこのデータベースの構築を実行しましょう。
  187. 普通は、プロダクション環境でこういったことは必要ありませんが、このスクリプトがあれば発者が必要なデータベースを手元で構築して、アプリケーションの作業に全力投球するのをたすけてくれるでしょう。
  188. 以下の内容で、<filename>scripts/load.sqlite.php</filename> としてスクリプトを作ってください。
  189. </para>
  190. <programlisting language="php"><![CDATA[
  191. // scripts/load.sqlite.php
  192. /**
  193. * データベースを作成して読み込むスクリプト
  194. */
  195. // アプリケーションパスとオートロードの初期化
  196. defined('APPLICATION_PATH')
  197. || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
  198. set_include_path(implode(PATH_SEPARATOR, array(
  199. APPLICATION_PATH . '/../library',
  200. get_include_path(),
  201. )));
  202. require_once 'Zend/Loader/Autoloader.php';
  203. Zend_Loader_Autoloader::getInstance();
  204. // CLI 用のオプション
  205. $getopt = new Zend_Console_Getopt(array(
  206. 'withdata|w' => 'Load database with sample data',
  207. 'env|e-s' => 'Application environment for which to create database (defaults to development)',
  208. 'help|h' => 'Help -- usage message',
  209. ));
  210. try {
  211. $getopt->parse();
  212. } catch (Zend_Console_Getopt_Exception $e) {
  213. // オプションが不正な場合に使用法を表示
  214. echo $e->getUsageMessage();
  215. return false;
  216. }
  217. // ヘルプが要求された場合に使用法を表示
  218. if ($getopt->getOption('h')) {
  219. echo $getopt->getUsageMessage();
  220. return true;
  221. }
  222. // CLI オプションの有無に応じて値を初期化
  223. $withData = $getopt->getOption('w');
  224. $env = $getopt->getOption('e');
  225. defined('APPLICATION_ENV')
  226. || define('APPLICATION_ENV', (null === $env) ? 'development' : $env);
  227. // Zend_Application の初期化
  228. $application = new Zend_Application(
  229. APPLICATION_ENV,
  230. APPLICATION_PATH . '/configs/application.ini'
  231. );
  232. // DB リソースの初期化と読み込み
  233. $bootstrap = $application->getBootstrap();
  234. $bootstrap->bootstrap('db');
  235. $dbAdapter = $bootstrap->getResource('db');
  236. // やっていることをユーザーにお知らせ
  237. // (実際にここでデータベースを作る)
  238. if ('testing' != APPLICATION_ENV) {
  239. echo 'Writing Database Guestbook in (control-c to cancel): ' . PHP_EOL;
  240. for ($x = 5; $x > 0; $x--) {
  241. echo $x . "\r"; sleep(1);
  242. }
  243. }
  244. // データベースファイルが既にないかチェック
  245. $options = $bootstrap->getOption('resources');
  246. $dbFile = $options['db']['params']['dbname'];
  247. if (file_exists($dbFile)) {
  248. unlink($dbFile);
  249. }
  250. // このブロックでスキーマファイルから読み込んだ実際のステートメントを実行
  251. try {
  252. $schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');
  253. // use the connection directly to load sql in batches
  254. $dbAdapter->getConnection()->exec($schemaSql);
  255. chmod($dbFile, 0666);
  256. if ('testing' != APPLICATION_ENV) {
  257. echo PHP_EOL;
  258. echo 'Database Created';
  259. echo PHP_EOL;
  260. }
  261. if ($withData) {
  262. $dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');
  263. // use the connection directly to load sql in batches
  264. $dbAdapter->getConnection()->exec($dataSql);
  265. if ('testing' != APPLICATION_ENV) {
  266. echo 'Data Loaded.';
  267. echo PHP_EOL;
  268. }
  269. }
  270. } catch (Exception $e) {
  271. echo 'AN ERROR HAS OCCURED:' . PHP_EOL;
  272. echo $e->getMessage() . PHP_EOL;
  273. return false;
  274. }
  275. // 大抵の場合、このスクリプトはコマンドラインから走らせて true を返す
  276. ]]></programlisting>
  277. <para>
  278. このスクリプトを実行しましょう。ターミナルか DOS のコマンドラインから以下を実行してください。
  279. </para>
  280. <programlisting language="shell"><![CDATA[
  281. % php scripts/load.sqlite.php --withdata
  282. ]]></programlisting>
  283. <para>
  284. 以下のような出力を目にすると思います。
  285. </para>
  286. <programlisting language="text"><![CDATA[
  287. path/to/ZendFrameworkQuickstart/scripts$ php load.sqlite.php --withdata
  288. Writing Database Guestbook in (control-c to cancel):
  289. 1
  290. Database Created
  291. Data Loaded.
  292. ]]></programlisting>
  293. <para>
  294. これでゲストブックアプリケーションのためにきちんと動くデータベースとテーブルができました。
  295. 次のステップはアプリケーションのコードを作成することです。
  296. これにはデータソース(ここでは <classname>Zend_Db_Table</classname> を使います)と、
  297. そのデータソースをドメインモデルに繋げる役目のデータマッパーを構築することが含まれます。
  298. 最後に、既存のエントリーの表示と新規エントリーの処理をモデルに結び付けるコントローラーも作ります。
  299. </para>
  300. <para>
  301. ここではデータソースへの接続に <ulink url="http://martinfowler.com/eaaCatalog/tableDataGateway.html">Table Data Gateway</ulink> を使います。
  302. <classname>Zend_Db_Table</classname> がこの機能を提供してくれます。
  303. 始めるにあたって <classname>Zend_Db_Table</classname> ベースのクラスを作りましょう。
  304. レイアウトとデータベースアダプターでやった時と同じように、<command>zf</command>
  305. ツールの力を借りることができます。<command>create db-table</command> コマンドを使うのです。
  306. これは最低で 2 つの引数をとります。参照させるクラスと、対応付けるデータベーステーブルの名前です。
  307. </para>
  308. <programlisting language="shell"><![CDATA[
  309. % zf create db-table Guestbook guestbook
  310. Creating a DbTable at application/models/DbTable/Guestbook.php
  311. Updating project profile 'zfproject.xml'
  312. ]]></programlisting>
  313. <para>
  314. Looking at your directory tree, you'll now see that a new directory,
  315. <filename>application/models/DbTable/</filename>, was created, with the file
  316. <filename>Guestbook.php</filename>. If you open that file, you'll see the following
  317. contents:
  318. </para>
  319. <programlisting language="php"><![CDATA[
  320. // application/models/DbTable/Guestbook.php
  321. /**
  322. * This is the DbTable class for the guestbook table.
  323. */
  324. class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
  325. {
  326. /** Table name */
  327. protected $_name = 'guestbook';
  328. }
  329. ]]></programlisting>
  330. <para>
  331. Note the class prefix: <classname>Application_Model_DbTable</classname>. The class prefix
  332. for our module, "Application", is the first segment, and then we have the component,
  333. "Model_DbTable"; the latter is mapped to the <filename>models/DbTable/</filename> directory
  334. of the module.
  335. </para>
  336. <para>
  337. All that is truly necessary when extending <classname>Zend_Db_Table</classname> is to
  338. provide a table name and optionally the primary key (if it is not "id").
  339. </para>
  340. <para>
  341. Now let's create a <ulink url="http://martinfowler.com/eaaCatalog/dataMapper.html">Data
  342. Mapper</ulink>. A <emphasis>Data Mapper</emphasis> maps a domain object to the database.
  343. In our case, it will map our model, <classname>Application_Model_Guestbook</classname>, to
  344. our data source, <classname>Application_Model_DbTable_Guestbook</classname>. A typical
  345. <acronym>API</acronym> for a data mapper is as follows:
  346. </para>
  347. <programlisting language="php"><![CDATA[
  348. // application/models/GuestbookMapper.php
  349. class Application_Model_GuestbookMapper
  350. {
  351. public function save($model);
  352. public function find($id, $model);
  353. public function fetchAll();
  354. }
  355. ]]></programlisting>
  356. <para>
  357. In addition to these methods, we'll add methods for setting and retrieving the Table Data
  358. Gateway. To create the initial class, use the <command>zf</command> CLI tool:
  359. </para>
  360. <programlisting language="shell"><![CDATA[
  361. % zf create model GuestbookMapper
  362. Creating a model at application/models/GuestbookMapper.php
  363. Updating project profile '.zfproject.xml'
  364. ]]></programlisting>
  365. <para>
  366. Now, edit the class <classname>Application_Model_GuestbookMapper</classname> found in
  367. <filename>application/models/GuestbookMapper.php</filename> to read as follows:
  368. </para>
  369. <programlisting language="php"><![CDATA[
  370. // application/models/GuestbookMapper.php
  371. class Application_Model_GuestbookMapper
  372. {
  373. protected $_dbTable;
  374. public function setDbTable($dbTable)
  375. {
  376. if (is_string($dbTable)) {
  377. $dbTable = new $dbTable();
  378. }
  379. if (!$dbTable instanceof Zend_Db_Table_Abstract) {
  380. throw new Exception('Invalid table data gateway provided');
  381. }
  382. $this->_dbTable = $dbTable;
  383. return $this;
  384. }
  385. public function getDbTable()
  386. {
  387. if (null === $this->_dbTable) {
  388. $this->setDbTable('Application_Model_DbTable_Guestbook');
  389. }
  390. return $this->_dbTable;
  391. }
  392. public function save(Application_Model_Guestbook $guestbook)
  393. {
  394. $data = array(
  395. 'email' => $guestbook->getEmail(),
  396. 'comment' => $guestbook->getComment(),
  397. 'created' => date('Y-m-d H:i:s'),
  398. );
  399. if (null === ($id = $guestbook->getId())) {
  400. unset($data['id']);
  401. $this->getDbTable()->insert($data);
  402. } else {
  403. $this->getDbTable()->update($data, array('id = ?' => $id));
  404. }
  405. }
  406. public function find($id, Application_Model_Guestbook $guestbook)
  407. {
  408. $result = $this->getDbTable()->find($id);
  409. if (0 == count($result)) {
  410. return;
  411. }
  412. $row = $result->current();
  413. $guestbook->setId($row->id)
  414. ->setEmail($row->email)
  415. ->setComment($row->comment)
  416. ->setCreated($row->created);
  417. }
  418. public function fetchAll()
  419. {
  420. $resultSet = $this->getDbTable()->fetchAll();
  421. $entries = array();
  422. foreach ($resultSet as $row) {
  423. $entry = new Application_Model_Guestbook();
  424. $entry->setId($row->id)
  425. ->setEmail($row->email)
  426. ->setComment($row->comment)
  427. ->setCreated($row->created);
  428. $entries[] = $entry;
  429. }
  430. return $entries;
  431. }
  432. }
  433. ]]></programlisting>
  434. <para>
  435. Now it's time to create our model class. We'll do so, once again, using the
  436. <command>zf create model</command> command:
  437. </para>
  438. <programlisting language="shell"><![CDATA[
  439. % zf create model Guestbook
  440. Creating a model at application/models/Guestbook.php
  441. Updating project profile '.zfproject.xml'
  442. ]]></programlisting>
  443. <para>
  444. We'll modify this empty <acronym>PHP</acronym> class to make it easy to populate the model
  445. by passing an array of data either to the constructor or a
  446. <methodname>setOptions()</methodname> method. The final model class, located in
  447. <filename>application/models/Guestbook.php</filename>, should look like this:
  448. </para>
  449. <programlisting language="php"><![CDATA[
  450. // application/models/Guestbook.php
  451. class Application_Model_Guestbook
  452. {
  453. protected $_comment;
  454. protected $_created;
  455. protected $_email;
  456. protected $_id;
  457. public function __construct(array $options = null)
  458. {
  459. if (is_array($options)) {
  460. $this->setOptions($options);
  461. }
  462. }
  463. public function __set($name, $value)
  464. {
  465. $method = 'set' . $name;
  466. if (('mapper' == $name) || !method_exists($this, $method)) {
  467. throw new Exception('Invalid guestbook property');
  468. }
  469. $this->$method($value);
  470. }
  471. public function __get($name)
  472. {
  473. $method = 'get' . $name;
  474. if (('mapper' == $name) || !method_exists($this, $method)) {
  475. throw new Exception('Invalid guestbook property');
  476. }
  477. return $this->$method();
  478. }
  479. public function setOptions(array $options)
  480. {
  481. $methods = get_class_methods($this);
  482. foreach ($options as $key => $value) {
  483. $method = 'set' . ucfirst($key);
  484. if (in_array($method, $methods)) {
  485. $this->$method($value);
  486. }
  487. }
  488. return $this;
  489. }
  490. public function setComment($text)
  491. {
  492. $this->_comment = (string) $text;
  493. return $this;
  494. }
  495. public function getComment()
  496. {
  497. return $this->_comment;
  498. }
  499. public function setEmail($email)
  500. {
  501. $this->_email = (string) $email;
  502. return $this;
  503. }
  504. public function getEmail()
  505. {
  506. return $this->_email;
  507. }
  508. public function setCreated($ts)
  509. {
  510. $this->_created = $ts;
  511. return $this;
  512. }
  513. public function getCreated()
  514. {
  515. return $this->_created;
  516. }
  517. public function setId($id)
  518. {
  519. $this->_id = (int) $id;
  520. return $this;
  521. }
  522. public function getId()
  523. {
  524. return $this->_id;
  525. }
  526. }
  527. ]]></programlisting>
  528. <para>
  529. Lastly, to connect these elements all together, lets create a guestbook controller that will
  530. both list the entries that are currently inside the database.
  531. </para>
  532. <para>
  533. To create a new controller, use the <command>zf create controller</command> command:
  534. </para>
  535. <programlisting language="shell"><![CDATA[
  536. % zf create controller Guestbook
  537. Creating a controller at
  538. application/controllers/GuestbookController.php
  539. Creating an index action method in controller Guestbook
  540. Creating a view script for the index action method at
  541. application/views/scripts/guestbook/index.phtml
  542. Creating a controller test file at
  543. tests/application/controllers/GuestbookControllerTest.php
  544. Updating project profile '.zfproject.xml'
  545. ]]></programlisting>
  546. <para>
  547. This will create a new controller, <classname>GuestbookController</classname>, in
  548. <filename>application/controllers/GuestbookController.php</filename>, with a single action
  549. method, <methodname>indexAction()</methodname>. It will also create a view script directory
  550. for the controller, <filename>application/views/scripts/guestbook/</filename>, with a view
  551. script for the index action.
  552. </para>
  553. <para>
  554. We'll use the "index" action as a landing page to view all guestbook entries.
  555. </para>
  556. <para>
  557. Now, let's flesh out the basic application logic. On a hit to
  558. <methodname>indexAction()</methodname>, we'll display all guestbook entries. This would look
  559. like the following:
  560. </para>
  561. <programlisting language="php"><![CDATA[
  562. // application/controllers/GuestbookController.php
  563. class GuestbookController extends Zend_Controller_Action
  564. {
  565. public function indexAction()
  566. {
  567. $guestbook = new Application_Model_GuestbookMapper();
  568. $this->view->entries = $guestbook->fetchAll();
  569. }
  570. }
  571. ]]></programlisting>
  572. <para>
  573. And, of course, we need a view script to go along with that. Edit
  574. <filename>application/views/scripts/guestbook/index.phtml</filename> to read as follows:
  575. </para>
  576. <programlisting language="php"><![CDATA[
  577. <!-- application/views/scripts/guestbook/index.phtml -->
  578. <p><a href="<?php echo $this->url(
  579. array(
  580. 'controller' => 'guestbook',
  581. 'action' => 'sign'
  582. ),
  583. 'default',
  584. true) ?>">Sign Our Guestbook</a></p>
  585. Guestbook Entries: <br />
  586. <dl>
  587. <?php foreach ($this->entries as $entry): ?>
  588. <dt><?php echo $this->escape($entry->email) ?></dt>
  589. <dd><?php echo $this->escape($entry->comment) ?></dd>
  590. <?php endforeach ?>
  591. </dl>
  592. ]]></programlisting>
  593. <note>
  594. <title>Checkpoint</title>
  595. <para>
  596. Now browse to "http://localhost/guestbook". You should see the following in your
  597. browser:
  598. </para>
  599. <para>
  600. <inlinegraphic width="525" scale="100" align="center" valign="middle"
  601. fileref="figures/learning.quickstart.create-model.png" format="PNG" />
  602. </para>
  603. </note>
  604. <note>
  605. <title>Using the data loader script</title>
  606. <para>
  607. The data loader script introduced in this section
  608. (<filename>scripts/load.sqlite.php</filename>) can be used to create the database for
  609. each environment you have defined, as well as to load it with sample data. Internally,
  610. it utilizes <classname>Zend_Console_Getopt</classname>, which allows it to provide a
  611. number of command line switches. If you pass the "-h" or "--help" switch, it will give
  612. you the available options:
  613. </para>
  614. <programlisting language="php"><![CDATA[
  615. Usage: load.sqlite.php [ options ]
  616. --withdata|-w Load database with sample data
  617. --env|-e [ ] Application environment for which to create database
  618. (defaults to development)
  619. --help|-h Help -- usage message)]]
  620. ]]></programlisting>
  621. <para>
  622. The "-e" switch allows you to specify the value to use for the constant
  623. <constant>APPLICATION_ENV</constant> -- which in turn allows you to create a SQLite
  624. database for each environment you define. Be sure to run the script for the environment
  625. you choose for your application when deploying.
  626. </para>
  627. </note>
  628. </sect1>