quickstart-create-model.xml 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- Reviewed: no -->
  3. <sect1 id="learning.quickstart.create-model">
  4. <title>Create a Model and Database Table</title>
  5. <para>
  6. Before we get started, let's consider something: where will these classes live, and how will
  7. we find them? The default project we created instantiates an autoloader. We can attach other
  8. autoloaders to it so that it knows where to find different classes. Typically, we want our
  9. various MVC classes grouped under the same tree -- in this case,
  10. <filename>application/</filename> -- and most often using a common prefix.
  11. </para>
  12. <para>
  13. <classname>Zend_Controller_Front</classname> has a notion of "modules", which are individual
  14. mini-applications. Modules mimic the directory structure that the <command>zf</command>
  15. tool sets up under <filename>application/</filename>, and all classes inside them are
  16. assumed to begin with a common prefix, the module name. <filename>application/</filename>
  17. is itself a module -- the "default" or "application" module. As such, we'll want to setup
  18. autoloading for resources within this directory.
  19. </para>
  20. <para>
  21. <classname>Zend_Application_Module_Autoloader</classname> provides the functionality needed
  22. to map the various resources under a module to the appropriate directories, and provides a
  23. standard naming mechanism as well. An instance of the class is created by default during
  24. initialization of the bootstrap object; your application bootstrap will by default use the
  25. module prefix "Application". As such, our models, forms, and table classes will all begin
  26. with the class prefix "Application_".
  27. </para>
  28. <para>
  29. Now, let's consider what makes up a guestbook. Typically, they are simply a list of entries
  30. with a <emphasis>comment</emphasis>, <emphasis>timestamp</emphasis>, and, often,
  31. <emphasis>email address</emphasis>. Assuming we store them in a database, we may also want a
  32. <emphasis>unique identifier</emphasis> for each entry. We'll likely want to be able to save
  33. an entry, fetch individual entries, and retrieve all entries. As such, a simple guestbook
  34. model <acronym>API</acronym> might look something like this:
  35. </para>
  36. <programlisting language="php"><![CDATA[
  37. // application/models/Guestbook.php
  38. class Application_Model_Guestbook
  39. {
  40. protected $_comment;
  41. protected $_created;
  42. protected $_email;
  43. protected $_id;
  44. public function __set($name, $value);
  45. public function __get($name);
  46. public function setComment($text);
  47. public function getComment();
  48. public function setEmail($email);
  49. public function getEmail();
  50. public function setCreated($ts);
  51. public function getCreated();
  52. public function setId($id);
  53. public function getId();
  54. }
  55. class Application_Model_GuestbookMapper
  56. {
  57. public function save(Application_Model_Guestbook $guestbook);
  58. public function find($id);
  59. public function fetchAll();
  60. }
  61. ]]></programlisting>
  62. <para>
  63. <methodname>__get()</methodname> and <methodname>__set()</methodname> will provide a
  64. convenience mechanism for us to access the individual entry properties, and proxy to the
  65. other getters and setters. They also will help ensure that only properties we whitelist will
  66. be available in the object.
  67. </para>
  68. <para>
  69. <methodname>find()</methodname> and <methodname>fetchAll()</methodname> provide the ability
  70. to fetch a single entry or all entries, while <methodname>save()</methodname> takes care of
  71. saving an entry to the data store.
  72. </para>
  73. <para>
  74. Now from here, we can start thinking about setting up our database.
  75. </para>
  76. <para>
  77. First we need to initialize our <classname>Db</classname> resource. As with the
  78. <classname>Layout</classname> and <classname>View</classname> resource, we can provide
  79. configuration for the <classname>Db</classname> resource. We can do this with the
  80. <command>zf configure db-adapter</command> command:
  81. </para>
  82. <programlisting language="shell"><![CDATA[
  83. % zf configure db-adapter \
  84. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' \
  85. > production
  86. A db configuration for the production has been written to the application config file.
  87. % zf configure db-adapter \
  88. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-testing.db"' \
  89. > testing
  90. A db configuration for the production has been written to the application config file.
  91. % zf configure db-adapter \
  92. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-dev.db"' \
  93. > development
  94. A db configuration for the production has been written to the application config file.
  95. ]]></programlisting>
  96. <para>
  97. Now edit your <filename>application/configs/application.ini</filename> file, where you'll
  98. see the following lines were added in the appropriate sections.
  99. </para>
  100. <programlisting language="ini"><![CDATA[
  101. ; application/configs/application.ini
  102. [production]
  103. ; ...
  104. resources.db.adapter = "PDO_SQLITE"
  105. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
  106. [testing : production]
  107. ; ...
  108. resources.db.adapter = "PDO_SQLITE"
  109. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
  110. [development : production]
  111. ; ...
  112. resources.db.adapter = "PDO_SQLITE"
  113. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
  114. ]]></programlisting>
  115. <para>
  116. Your final configuration file should look like the following:
  117. </para>
  118. <programlisting language="ini"><![CDATA[
  119. ; application/configs/application.ini
  120. [production]
  121. phpSettings.display_startup_errors = 0
  122. phpSettings.display_errors = 0
  123. bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
  124. bootstrap.class = "Bootstrap"
  125. appnamespace = "Application"
  126. resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
  127. resources.frontController.params.displayExceptions = 0
  128. resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
  129. resources.view[] =
  130. resources.db.adapter = "PDO_SQLITE"
  131. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
  132. [staging : production]
  133. [testing : production]
  134. phpSettings.display_startup_errors = 1
  135. phpSettings.display_errors = 1
  136. resources.db.adapter = "PDO_SQLITE"
  137. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
  138. [development : production]
  139. phpSettings.display_startup_errors = 1
  140. phpSettings.display_errors = 1
  141. resources.db.adapter = "PDO_SQLITE"
  142. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
  143. ]]></programlisting>
  144. <para>
  145. Note that the database(s) will be stored in <filename>data/db/</filename>. Create those
  146. directories, and make them world-writeable. On unix-like systems, you can do that as
  147. follows:
  148. </para>
  149. <programlisting language="shell"><![CDATA[
  150. % mkdir -p data/db; chmod -R a+rwX data
  151. ]]></programlisting>
  152. <para>
  153. On Windows, you will need to create the directories in Explorer and set the permissions to
  154. allow anyone to write to the directory.
  155. </para>
  156. <para>
  157. At this point we have a connection to a database; in our case, its a connection to a Sqlite
  158. database located inside our <filename>application/data/</filename> directory. So, let's
  159. design a simple table that will hold our guestbook entries.
  160. </para>
  161. <programlisting language="sql"><![CDATA[
  162. -- scripts/schema.sqlite.sql
  163. --
  164. -- You will need load your database schema with this SQL.
  165. CREATE TABLE guestbook (
  166. id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  167. email VARCHAR(32) NOT NULL DEFAULT 'noemail@test.com',
  168. comment TEXT NULL,
  169. created DATETIME NOT NULL
  170. );
  171. CREATE INDEX "id" ON "guestbook" ("id");
  172. ]]></programlisting>
  173. <para>
  174. And, so that we can have some working data out of the box, lets create a few rows of
  175. information to make our application interesting.
  176. </para>
  177. <programlisting language="sql"><![CDATA[
  178. -- scripts/data.sqlite.sql
  179. --
  180. -- You can begin populating the database with the following SQL statements.
  181. INSERT INTO guestbook (email, comment, created) VALUES
  182. ('ralph.schindler@zend.com',
  183. 'Hello! Hope you enjoy this sample zf application!',
  184. DATETIME('NOW'));
  185. INSERT INTO guestbook (email, comment, created) VALUES
  186. ('foo@bar.com',
  187. 'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
  188. DATETIME('NOW'));
  189. ]]></programlisting>
  190. <para>
  191. Now that we have both the schema and some data defined. Lets get a script together that we
  192. can now execute to build this database. Naturally, this is not needed in production, but
  193. this script will help developers build out the database requirements locally so they can
  194. have the fully working application. Create the script as
  195. <filename>scripts/load.sqlite.php</filename> with the following contents:
  196. </para>
  197. <programlisting language="php"><![CDATA[
  198. // scripts/load.sqlite.php
  199. /**
  200. * Script for creating and loading database
  201. */
  202. // Initialize the application path and autoloading
  203. defined('APPLICATION_PATH')
  204. || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
  205. set_include_path(implode(PATH_SEPARATOR, array(
  206. APPLICATION_PATH . '/../library',
  207. get_include_path(),
  208. )));
  209. require_once 'Zend/Loader/Autoloader.php';
  210. Zend_Loader_Autoloader::getInstance();
  211. // Define some CLI options
  212. $getopt = new Zend_Console_Getopt(array(
  213. 'withdata|w' => 'Load database with sample data',
  214. 'env|e-s' => 'Application environment for which to create database (defaults to development)',
  215. 'help|h' => 'Help -- usage message',
  216. ));
  217. try {
  218. $getopt->parse();
  219. } catch (Zend_Console_Getopt_Exception $e) {
  220. // Bad options passed: report usage
  221. echo $e->getUsageMessage();
  222. return false;
  223. }
  224. // If help requested, report usage message
  225. if ($getopt->getOption('h')) {
  226. echo $getopt->getUsageMessage();
  227. return true;
  228. }
  229. // Initialize values based on presence or absence of CLI options
  230. $withData = $getopt->getOption('w');
  231. $env = $getopt->getOption('e');
  232. defined('APPLICATION_ENV')
  233. || define('APPLICATION_ENV', (null === $env) ? 'development' : $env);
  234. // Initialize Zend_Application
  235. $application = new Zend_Application(
  236. APPLICATION_ENV,
  237. APPLICATION_PATH . '/configs/application.ini'
  238. );
  239. // Initialize and retrieve DB resource
  240. $bootstrap = $application->getBootstrap();
  241. $bootstrap->bootstrap('db');
  242. $dbAdapter = $bootstrap->getResource('db');
  243. // let the user know whats going on (we are actually creating a
  244. // database here)
  245. if ('testing' != APPLICATION_ENV) {
  246. echo 'Writing Database Guestbook in (control-c to cancel): ' . PHP_EOL;
  247. for ($x = 5; $x > 0; $x--) {
  248. echo $x . "\r"; sleep(1);
  249. }
  250. }
  251. // Check to see if we have a database file already
  252. $options = $bootstrap->getOption('resources');
  253. $dbFile = $options['db']['params']['dbname'];
  254. if (file_exists($dbFile)) {
  255. unlink($dbFile);
  256. }
  257. // this block executes the actual statements that were loaded from
  258. // the schema file.
  259. try {
  260. $schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');
  261. // use the connection directly to load sql in batches
  262. $dbAdapter->getConnection()->exec($schemaSql);
  263. chmod($dbFile, 0666);
  264. if ('testing' != APPLICATION_ENV) {
  265. echo PHP_EOL;
  266. echo 'Database Created';
  267. echo PHP_EOL;
  268. }
  269. if ($withData) {
  270. $dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');
  271. // use the connection directly to load sql in batches
  272. $dbAdapter->getConnection()->exec($dataSql);
  273. if ('testing' != APPLICATION_ENV) {
  274. echo 'Data Loaded.';
  275. echo PHP_EOL;
  276. }
  277. }
  278. } catch (Exception $e) {
  279. echo 'AN ERROR HAS OCCURED:' . PHP_EOL;
  280. echo $e->getMessage() . PHP_EOL;
  281. return false;
  282. }
  283. // generally speaking, this script will be run from the command line
  284. return true;
  285. ]]></programlisting>
  286. <para>
  287. Now, let's execute this script. From a terminal or the DOS command line, do the following:
  288. </para>
  289. <programlisting language="shell"><![CDATA[
  290. % php scripts/load.sqlite.php --withdata
  291. ]]></programlisting>
  292. <para>
  293. You should see output like the following:
  294. </para>
  295. <programlisting language="text"><![CDATA[
  296. path/to/ZendFrameworkQuickstart/scripts$ php load.sqlite.php --withdata
  297. Writing Database Guestbook in (control-c to cancel):
  298. 1
  299. Database Created
  300. Data Loaded.
  301. ]]></programlisting>
  302. <para>
  303. Now we have a fully working database and table for our guestbook application. Our next few
  304. steps are to build out our application code. This includes building a data source (in our
  305. case, we will use <classname>Zend_Db_Table</classname>), and a data mapper to connect that
  306. data source to our domain model. Finally we'll also create the controller that will interact
  307. with this model to both display existing entries and process new entries.
  308. </para>
  309. <para>
  310. We'll use a <ulink url="http://martinfowler.com/eaaCatalog/tableDataGateway.html">Table Data
  311. Gateway</ulink> to connect to our data source; <classname>Zend_Db_Table</classname>
  312. provides this functionality. To get started, lets create a
  313. <classname>Zend_Db_Table</classname>-based table class. Just as we've done for layouts and
  314. the database adapter, we can use the <command>zf</command> tool to assist, using the command
  315. <command>create db-table</command>. This takes minimally two arguments, the name by which
  316. you want to refer to the class, and the database table it maps to.
  317. </para>
  318. <programlisting language="shell"><![CDATA[
  319. % zf create db-table Guestbook guestbook
  320. Creating a DbTable at application/models/DbTable/Guestbook.php
  321. Updating project profile 'zfproject.xml'
  322. ]]></programlisting>
  323. <para>
  324. Looking at your directory tree, you'll now see that a new directory,
  325. <filename>application/models/DbTable/</filename>, was created, with the file
  326. <filename>Guestbook.php</filename>. If you open that file, you'll see the following
  327. contents:
  328. </para>
  329. <programlisting language="php"><![CDATA[
  330. // application/models/DbTable/Guestbook.php
  331. /**
  332. * This is the DbTable class for the guestbook table.
  333. */
  334. class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
  335. {
  336. /** Table name */
  337. protected $_name = 'guestbook';
  338. }
  339. ]]></programlisting>
  340. <para>
  341. Note the class prefix: <classname>Application_Model_DbTable</classname>. The class prefix
  342. for our module, "Application", is the first segment, and then we have the component,
  343. "Model_DbTable"; the latter is mapped to the <filename>models/DbTable/</filename> directory
  344. of the module.
  345. </para>
  346. <para>
  347. All that is truly necessary when extending <classname>Zend_Db_Table</classname> is to
  348. provide a table name and optionally the primary key (if it is not "id").
  349. </para>
  350. <para>
  351. Now let's create a <ulink url="http://martinfowler.com/eaaCatalog/dataMapper.html">Data
  352. Mapper</ulink>. A <emphasis>Data Mapper</emphasis> maps a domain object to the database.
  353. In our case, it will map our model, <classname>Application_Model_Guestbook</classname>, to
  354. our data source, <classname>Application_Model_DbTable_Guestbook</classname>. A typical
  355. <acronym>API</acronym> for a data mapper is as follows:
  356. </para>
  357. <programlisting language="php"><![CDATA[
  358. // application/models/GuestbookMapper.php
  359. class Application_Model_GuestbookMapper
  360. {
  361. public function save($model);
  362. public function find($id, $model);
  363. public function fetchAll();
  364. }
  365. ]]></programlisting>
  366. <para>
  367. In addition to these methods, we'll add methods for setting and retrieving the Table Data
  368. Gateway. To create the initial class, use the <command>zf</command> CLI tool:
  369. </para>
  370. <programlisting language="shell"><![CDATA[
  371. % zf create model GuestbookMapper
  372. Creating a model at application/models/GuestbookMapper.php
  373. Updating project profile '.zfproject.xml'
  374. ]]></programlisting>
  375. <para>
  376. Now, edit the class <classname>Application_Model_GuestbookMapper</classname> found in
  377. <filename>application/models/GuestbookMapper.php</filename> to read as follows:
  378. </para>
  379. <programlisting language="php"><![CDATA[
  380. // application/models/GuestbookMapper.php
  381. class Application_Model_GuestbookMapper
  382. {
  383. protected $_dbTable;
  384. public function setDbTable($dbTable)
  385. {
  386. if (is_string($dbTable)) {
  387. $dbTable = new $dbTable();
  388. }
  389. if (!$dbTable instanceof Zend_Db_Table_Abstract) {
  390. throw new Exception('Invalid table data gateway provided');
  391. }
  392. $this->_dbTable = $dbTable;
  393. return $this;
  394. }
  395. public function getDbTable()
  396. {
  397. if (null === $this->_dbTable) {
  398. $this->setDbTable('Application_Model_DbTable_Guestbook');
  399. }
  400. return $this->_dbTable;
  401. }
  402. public function save(Application_Model_Guestbook $guestbook)
  403. {
  404. $data = array(
  405. 'email' => $guestbook->getEmail(),
  406. 'comment' => $guestbook->getComment(),
  407. 'created' => date('Y-m-d H:i:s'),
  408. );
  409. if (null === ($id = $guestbook->getId())) {
  410. unset($data['id']);
  411. $this->getDbTable()->insert($data);
  412. } else {
  413. $this->getDbTable()->update($data, array('id = ?' => $id));
  414. }
  415. }
  416. public function find($id, Application_Model_Guestbook $guestbook)
  417. {
  418. $result = $this->getDbTable()->find($id);
  419. if (0 == count($result)) {
  420. return;
  421. }
  422. $row = $result->current();
  423. $guestbook->setId($row->id)
  424. ->setEmail($row->email)
  425. ->setComment($row->comment)
  426. ->setCreated($row->created);
  427. }
  428. public function fetchAll()
  429. {
  430. $resultSet = $this->getDbTable()->fetchAll();
  431. $entries = array();
  432. foreach ($resultSet as $row) {
  433. $entry = new Application_Model_Guestbook();
  434. $entry->setId($row->id)
  435. ->setEmail($row->email)
  436. ->setComment($row->comment)
  437. ->setCreated($row->created);
  438. $entries[] = $entry;
  439. }
  440. return $entries;
  441. }
  442. }
  443. ]]></programlisting>
  444. <para>
  445. Now it's time to create our model class. We'll do so, once again, using the
  446. <command>zf create model</command> command:
  447. </para>
  448. <programlisting language="shell"><![CDATA[
  449. % zf create model Guestbook
  450. Creating a model at application/models/Guestbook.php
  451. Updating project profile '.zfproject.xml'
  452. ]]></programlisting>
  453. <para>
  454. We'll modify this empty <acronym>PHP</acronym> class to make it easy to populate the model
  455. by passing an array of data either to the constructor or a
  456. <methodname>setOptions()</methodname> method. The final model class, located in
  457. <filename>application/models/Guestbook.php</filename>, should look like this:
  458. </para>
  459. <programlisting language="php"><![CDATA[
  460. // application/models/Guestbook.php
  461. class Application_Model_Guestbook
  462. {
  463. protected $_comment;
  464. protected $_created;
  465. protected $_email;
  466. protected $_id;
  467. public function __construct(array $options = null)
  468. {
  469. if (is_array($options)) {
  470. $this->setOptions($options);
  471. }
  472. }
  473. public function __set($name, $value)
  474. {
  475. $method = 'set' . $name;
  476. if (('mapper' == $name) || !method_exists($this, $method)) {
  477. throw new Exception('Invalid guestbook property');
  478. }
  479. $this->$method($value);
  480. }
  481. public function __get($name)
  482. {
  483. $method = 'get' . $name;
  484. if (('mapper' == $name) || !method_exists($this, $method)) {
  485. throw new Exception('Invalid guestbook property');
  486. }
  487. return $this->$method();
  488. }
  489. public function setOptions(array $options)
  490. {
  491. $methods = get_class_methods($this);
  492. foreach ($options as $key => $value) {
  493. $method = 'set' . ucfirst($key);
  494. if (in_array($method, $methods)) {
  495. $this->$method($value);
  496. }
  497. }
  498. return $this;
  499. }
  500. public function setComment($text)
  501. {
  502. $this->_comment = (string) $text;
  503. return $this;
  504. }
  505. public function getComment()
  506. {
  507. return $this->_comment;
  508. }
  509. public function setEmail($email)
  510. {
  511. $this->_email = (string) $email;
  512. return $this;
  513. }
  514. public function getEmail()
  515. {
  516. return $this->_email;
  517. }
  518. public function setCreated($ts)
  519. {
  520. $this->_created = $ts;
  521. return $this;
  522. }
  523. public function getCreated()
  524. {
  525. return $this->_created;
  526. }
  527. public function setId($id)
  528. {
  529. $this->_id = (int) $id;
  530. return $this;
  531. }
  532. public function getId()
  533. {
  534. return $this->_id;
  535. }
  536. }
  537. ]]></programlisting>
  538. <para>
  539. Lastly, to connect these elements all together, lets create a guestbook controller that will
  540. both list the entries that are currently inside the database.
  541. </para>
  542. <para>
  543. To create a new controller, use the <command>zf create controller</command> command:
  544. </para>
  545. <programlisting language="shell"><![CDATA[
  546. % zf create controller Guestbook
  547. Creating a controller at
  548. application/controllers/GuestbookController.php
  549. Creating an index action method in controller Guestbook
  550. Creating a view script for the index action method at
  551. application/views/scripts/guestbook/index.phtml
  552. Creating a controller test file at
  553. tests/application/controllers/GuestbookControllerTest.php
  554. Updating project profile '.zfproject.xml'
  555. ]]></programlisting>
  556. <para>
  557. This will create a new controller, <classname>GuestbookController</classname>, in
  558. <filename>application/controllers/GuestbookController.php</filename>, with a single action
  559. method, <methodname>indexAction()</methodname>. It will also create a view script directory
  560. for the controller, <filename>application/views/scripts/guestbook/</filename>, with a view
  561. script for the index action.
  562. </para>
  563. <para>
  564. We'll use the "index" action as a landing page to view all guestbook entries.
  565. </para>
  566. <para>
  567. Now, let's flesh out the basic application logic. On a hit to
  568. <methodname>indexAction()</methodname>, we'll display all guestbook entries. This would look
  569. like the following:
  570. </para>
  571. <programlisting language="php"><![CDATA[
  572. // application/controllers/GuestbookController.php
  573. class GuestbookController extends Zend_Controller_Action
  574. {
  575. public function indexAction()
  576. {
  577. $guestbook = new Application_Model_GuestbookMapper();
  578. $this->view->entries = $guestbook->fetchAll();
  579. }
  580. }
  581. ]]></programlisting>
  582. <para>
  583. And, of course, we need a view script to go along with that. Edit
  584. <filename>application/views/scripts/guestbook/index.phtml</filename> to read as follows:
  585. </para>
  586. <programlisting language="php"><![CDATA[
  587. <!-- application/views/scripts/guestbook/index.phtml -->
  588. <p><a href="<?php echo $this->url(
  589. array(
  590. 'controller' => 'guestbook',
  591. 'action' => 'sign'
  592. ),
  593. 'default',
  594. true) ?>">Sign Our Guestbook</a></p>
  595. Guestbook Entries: <br />
  596. <dl>
  597. <?php foreach ($this->entries as $entry): ?>
  598. <dt><?php echo $this->escape($entry->email) ?></dt>
  599. <dd><?php echo $this->escape($entry->comment) ?></dd>
  600. <?php endforeach ?>
  601. </dl>
  602. ]]></programlisting>
  603. <note>
  604. <title>Checkpoint</title>
  605. <para>
  606. Now browse to "http://localhost/guestbook". You should see the following in your
  607. browser:
  608. </para>
  609. <para>
  610. <inlinegraphic width="525" scale="100" align="center" valign="middle"
  611. fileref="figures/learning.quickstart.create-model.png" format="PNG" />
  612. </para>
  613. </note>
  614. <note>
  615. <title>Using the data loader script</title>
  616. <para>
  617. The data loader script introduced in this section
  618. (<filename>scripts/load.sqlite.php</filename>) can be used to create the database for
  619. each environment you have defined, as well as to load it with sample data. Internally,
  620. it utilizes <classname>Zend_Console_Getopt</classname>, which allows it to provide a
  621. number of command line switches. If you pass the "-h" or "--help" switch, it will give
  622. you the available options:
  623. </para>
  624. <programlisting language="php"><![CDATA[
  625. Usage: load.sqlite.php [ options ]
  626. --withdata|-w Load database with sample data
  627. --env|-e [ ] Application environment for which to create database
  628. (defaults to development)
  629. --help|-h Help -- usage message)]]
  630. ]]></programlisting>
  631. <para>
  632. The "-e" switch allows you to specify the value to use for the constant
  633. <constant>APPLICATION_ENV</constant> -- which in turn allows you to create a SQLite
  634. database for each environment you define. Be sure to run the script for the environment
  635. you choose for your application when deploying.
  636. </para>
  637. </note>
  638. </sect1>