Zend Framework 1.10.4手册(ZF的快速启动四)



 在我们开始之前,让我们思考这样一些问题:这些类将放在什么地方,我们如何找到他们?我们创建的默认项目实例化一个自动加载器(autoloader)。我们可以把其他的自动加载器附加到它身上,这样它知道到哪里找到不同的类。典型的,我们想让我们大量的 MVC 类在同一个树状结构下分组--在本例中,是 application/--而且大部分情况使用一个通用前缀。

Zend_Controller_Front 有一个模块(modules)的理念,这些模块是独立的迷你应用程序。模块模仿 zf 工具在 application/ 下建立的目录结构,而且在它们(模块)内部的类被假设以一个通用前缀(模块的名字)开头。application/ 本身是一个模块--默认(default)或者应用(application)模块。这样,我们想为在这个目录内的资源创建自动加载。

Zend_Application_Module_Autoloader 提供了必要的功能来把一个模块下大量的资源映射到合适的目录,同时提供了一套标准的命名机制。类的一个实例将在 bootstrap 对象初始化的过程中被默认创建,你的应用程序的 bootstrap 将会默认的使用模块前缀 Application。这样,我们的模型,表单以及表格类将会以 Application 这个类前缀开头。

现在,让我们想一下什么组成了一个留言本。典型的,他们是一些简单的列表,包含有留言,时间,同时,经常的,电子邮件地址。假设我们把它们存储在一个数据库中,我们可能还想为每一个条目分配一个独一无二的标识符(unique identifier)。我们可能还希望可以保存每一个条目,捕获每一个条目,同时检索所有的条目。这样,一个简单的留言本模型 API 可能看起来是这样的:

 

  1. // application/models/Guestbook.php   
  2.   
  3. class Application_Model_Guestbook   
  4. {   
  5.     protected $_comment;   
  6.     protected $_created;   
  7.     protected $_email;   
  8.     protected $_id;   
  9.   
  10.     public function __set($name$value);   
  11.     public function __get($name);   
  12.   
  13.     public function setComment($text);   
  14.     public function getComment();   
  15.   
  16.     public function setEmail($email);   
  17.     public function getEmail();   
  18.   
  19.     public function setCreated($ts);   
  20.     public function getCreated();   
  21.   
  22.     public function setId($id);   
  23.     public function getId();   
  24. }   
  25.   
  26. class Application_Model_GuestbookMapper     
  27. {    
  28.     public function save(Application_Model_Guestbook $guestbook);    
  29.     public function find($id);     
  30.     public function fetchAll();     
  31. }  

 

__get() 和 set__() 将为我们访问独立的列表的属性提供一个方便的机制,同时代理其它的 getter 和 setter。他们同样将帮助确保只有列入我们白名单的属性才能被对象使用。

find() 和 fetch() 提供了捕获一个单独的条目或者全部条目的功能,而 save() 则负责把一个条目保存到数据库中。

从现在开始,我们可开始考虑建立我们的数据库。

首先,我们需要初始化我们的 Db 资源。如同 Layout 和 View 资源,我们可以为 Db 资源提供配置。我们可以使用 zf configure db-adapter 命令来完成:

      % zf configure db-adapter \
      > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' \
      > production
      A db configuration for the production has been written to the application config file.

      % zf configure db-adapter \
      > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-testing.db"' \
      > testing
      A db configuration for the production has been written to the application config file.

      % zf configure db-adapter \
      > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-dev.db"' \
      > development
      A db configuration for the production has been written to the application config file.

现在编辑你的 application/configs/application.ini 文件,在那你可以看到在对应的部分,添加了以下的内容:

      ; application/configs/application.ini

      [production]
      ; ...
      resources.db.adapter = "PDO_SQLITE"
      resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"

      [testing : production]
      ; ...
      resources.db.adapter = "PDO_SQLITE"
      resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"

      [development : production]
      ; ...
      resources.db.adapter = "PDO_SQLITE"
      resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"

最后你的配置文件看起来应该是这样的:

      ; application/configs/application.ini

      [production]
      phpSettings.display_startup_errors = 0
      phpSettings.display_errors = 0
      bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
      bootstrap.class = "Bootstrap"
      appnamespace = "Application"
      resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
      resources.frontController.params.displayExceptions = 0
      resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
      resources.view[] =
      resources.db.adapter = "PDO_SQLITE"
      resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"

      [staging : production]

      [testing : production]
      phpSettings.display_startup_errors = 1
      phpSettings.display_errors = 1
      resources.db.adapter = "PDO_SQLITE"
      resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"

      [development : production]
      phpSettings.display_startup_errors = 1
      phpSettings.display_errors = 1
      resources.db.adapter = "PDO_SQLITE"
      resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"

注意数据库将会保存在 data/db/ 中。创建那些目录,同时使它们可写。在 unix 系统中,你可以这样做:

% mkdir -p data/db; chmod -R a+rwX data

在 Windows,你将在文件浏览器中创建这些目录,并设置权限,让任何人都可以写入这个目录。

至此,我们有了一个到数据库的连接,在我们的例子中,这是一个到位于我们 application/data 目录中的一个 Sqlite 数据库的链接。所以,让我们设计一个简单的表格来保存我们的留言本条目。

 

  1. -- scripts/schema.sqlite.sql   
  2. --   
  3. -- You will need load your database schema with this SQL.   
  4.   
  5. CREATE TABLE guestbook (   
  6.     id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,   
  7.     email VARCHAR(32) NOT NULL DEFAULT '[email protected]',   
  8.     comment TEXT NULL,   
  9.     created DATETIME NOT NULL   
  10. );   
  11.   
  12. CREATE INDEX "id" ON "guestbook" ("id");  

 

同时,为了我们能有一些可以操作的数据,让我们创建一些信息来使我们的应用程序更有趣。

 

  1.   
  2. -- scripts/data.sqlite.sql   
  3. --   
  4. -- You can begin populating the database with the following SQL statements.   
  5.   
  6. INSERT INTO guestbook (email, comment, created) VALUES   
  7.     ('[email protected]',   
  8.     'Hello! Hope you enjoy this sample zf application!',   
  9.     DATETIME('NOW'));   
  10. INSERT INTO guestbook (email, comment, created) VALUES   
  11.     ('[email protected]',   
  12.     'Baz baz baz, baz baz Baz baz baz - baz baz baz.',   
  13.     DATETIME('NOW'));  

 

现在我们同时定义好了结构和一些数据。让我们创建一个脚本以便我们可以执行从而创建这个数据库。本来,这个在产品中不是必须的,但是这个脚本将帮助开发者创建本地数据库,以便他们拥有全套的工作应用程序。用以下的内容创建 scripts/load.sqlite.php 脚本:

 

  1. <?php   
  2.   
  3.   
  4. // Initialize the application path and autoloading   
  5. defined('APPLICATION_PATH')   
  6.     || define('APPLICATION_PATH'realpath(dirname(__FILE__) . '/../application'));   
  7. set_include_path(implode(PATH_SEPARATOR, array(   
  8.     APPLICATION_PATH . '/../library',   
  9.     get_include_path(),   
  10. )));   
  11. require_once 'Zend/Loader/Autoloader.php';   
  12. Zend_Loader_Autoloader::getInstance();   
  13.   
  14. // Define some CLI options   
  15. $getopt = new Zend_Console_Getopt(array(   
  16.     'withdata|w' => 'Load database with sample data',   
  17.     'env|e-s'    => 'Application environment for which to create database (defaults to development)',   
  18.     'help|h'     => 'Help -- usage message',   
  19. ));   
  20. try {   
  21.     $getopt->parse();   
  22. } catch (Zend_Console_Getopt_Exception $e) {   
  23.     // Bad options passed: report usage   
  24.     echo $e->getUsageMessage();   
  25.     return false;   
  26. }   
  27.   
  28. // If help requested, report usage message   
  29. if ($getopt->getOption('h')) {   
  30.     echo $getopt->getUsageMessage();   
  31.     return true;   
  32. }   
  33.   
  34. // Initialize values based on presence or absence of CLI options   
  35. $withData = $getopt->getOption('w');   
  36. $env      = $getopt->getOption('e');   
  37. defined('APPLICATION_ENV')   
  38.     || define('APPLICATION_ENV', (null === $env) ? 'development' : $env);   
  39.   
  40. // Initialize Zend_Application   
  41. $application = new Zend_Application(   
  42.     APPLICATION_ENV,   
  43.     APPLICATION_PATH . '/configs/application.ini'  
  44. );   
  45.   
  46. // Initialize and retrieve DB resource   
  47. $bootstrap = $application->getBootstrap();   
  48. $bootstrap->bootstrap('db');   
  49. $dbAdapter = $bootstrap->getResource('db');   
  50.   
  51. // let the user know whats going on (we are actually creating a   
  52. // database here)   
  53. if ('testing' != APPLICATION_ENV) {   
  54.     echo 'Writing Database Guestbook in (control-c to cancel): ' . PHP_EOL;   
  55.     for ($x = 5; $x > 0; $x--) {   
  56.         echo $x . "\r"; sleep(1);   
  57.     }   
  58. }   
  59.   
  60. // Check to see if we have a database file already   
  61. $options = $bootstrap->getOption('resources');   
  62. $dbFile  = $options['db']['params']['dbname'];   
  63. if (file_exists($dbFile)) {   
  64.     unlink($dbFile);   
  65. }   
  66.   
  67. // this block executes the actual statements that were loaded from   
  68. // the schema file.   
  69. try {   
  70.     $schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');   
  71.     // use the connection directly to load sql in batches   
  72.     $dbAdapter->getConnection()->exec($schemaSql);   
  73.     chmod($dbFile, 0666);   
  74.     if ('testing' != APPLICATION_ENV) {   
  75.         echo PHP_EOL;   
  76.         echo 'Database Created';   
  77.         echo PHP_EOL;   
  78.     }   
  79.   
  80.     if ($withData) {   
  81.         $dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');   
  82.         // use the connection directly to load sql in batches   
  83.         $dbAdapter->getConnection()->exec($dataSql);   
  84.         if ('testing' != APPLICATION_ENV) {   
  85.             echo 'Data Loaded.';   
  86.             echo PHP_EOL;   
  87.         }   
  88.     }   
  89.   
  90. } catch (Exception $e) {   
  91.     echo 'AN ERROR HAS OCCURED:' . PHP_EOL;   
  92.     echo $e->getMessage() . PHP_EOL;   
  93.     return false;   
  94. }   
  95.   
  96. // generally speaking, this script will be run from the command line   
  97. return true;  

 

现在我们的留言本应用程序有了一整套运转正常的数据库和表格。下面的几个步骤将创建我们的应用程序代码。包括创建一个数据源(在我们的例子中,我们将使用 Zend_Db_Table),和一个数据映射器来把数据源链接到我们的模型。最后我们还将创建控制器,来和这个模型互动,以便显示存在的条目,同时加入新的条目。

我们将使用一个 Table Data Gateway 来链接到我们的数据源;Zend_Db_Table 提供了这个功能。开始之前,让我们创建一个以 Zend_Db_Table 为基础的表格类。正如我们在 layout 和 database adapter 做的,我们可以使用 zf 工具来帮助我们,使用 create db-table 命令。它将接受至少两个参数,你想指向的类的名字,和它映射的数据库表格。

      % zf create db-table Guestbook guestbook
      Creating a DbTable at application/models/DbTable/Guestbook.php
      Updating project profile 'zfproject.xml'

看看你的目录树,你将会发现一个新目录, application/models/DbTable 被创建了,同时还有 Guestbook.php 文件。如果你打开那个文件,你会看到如下内容:

 

  1. // application/models/DbTable/Guestbook.php   
  2.   
  3.   
  4.   
  5. class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract   
  6. {   
  7.   
  8.     protected $_name = 'guestbook';   

注意类的前缀:Application_Model_DbTable。我们模块的类前缀,Application_,是第一个部分,然后是我们的组件,Model_DbTable;后面的部分是被映射到模块的 models/DbTable 目录。

当扩展 Zend_Db_Table 的时候,所需要提供的只是一个表格的名字,以及一个可选择的 primary key (如果它不是 id)。

现在让我们创建一个 Data Mapper。一个 Data Mapper 把一个对象映射到数据库。在我们的例子中,它将映射我们的模型,Application_Model_Guestbook,到我们的数据源,Application_Model_DbTable_Guestbook。一个典型的数据映射器(data mapper)的 API 将会是这样的:

 

  1. // application/models/GuestbookMapper.php   
  2.   
  3. class Application_Model_GuestbookMapper   
  4. {   
  5.     public function save($model);   
  6.     public function find($id$model);   
  7.     public function fetchAll();   
  8. }  

 

除了这些方法,我们将增加设置和检索 Table Data Gateway 的方法。为了创建最原始的类,使用 zf 客户工具:

      % zf create model GuestbookMapper
      Creating a model at application/models/GuestbookMapper.php
      Updating project profile '.zfproject.xml'

现在,编辑在 application/models/GuestbookMapper.php 文件中的 Application_Model_GuestbookMapper 类,将会看到以下内容:

 

  1. >?php   
  2.   
  3. class Application_Model_GuestbookMapper   
  4. {   
  5.     protected $_dbTable;   
  6.   
  7.     public function setDbTable($dbTable)   
  8.     {   
  9.         if (is_string($dbTable)) {   
  10.             $dbTable = new $dbTable();   
  11.         }   
  12.         if (!$dbTable instanceof Zend_Db_Table_Abstract) {   
  13.             throw new Exception('Invalid table data gateway provided');   
  14.         }   
  15.         $this->_dbTable = $dbTable;   
  16.         return $this;   
  17.     }   
  18.   
  19.     public function getDbTable()   
  20.     {   
  21.         if (null === $this->_dbTable) {   
  22.             $this->setDbTable('Application_Model_DbTable_Guestbook');   
  23.         }   
  24.         return $this->_dbTable;   
  25.     }   
  26.   
  27.     public function save(Application_Model_Guestbook $guestbook)   
  28.     {   
  29.         $data = array(   
  30.             'email' => $guestbook->getEmail(),   
  31.             'comment' => $guestbook->getComment(),   
  32.             'created' => date('Y-m-d H:i:s'),   
  33.         );   
  34.   
  35.         if (null === ($id = $guestbook->getId())) {   
  36.             unset($data['id']);   
  37.             $this->getDbTable()->insert($data);   
  38.         } else {   
  39.             $this->getDbTable()->update($dataarray('id = ?' => $id));   
  40.         }   
  41.     }   
  42.   
  43.     public function find($id, Application_Model_Guestbook $guestbook)   
  44.     {   
  45.         $result = $this->getDbTable()->find($id);   
  46.         if (0 == count($result)) {   
  47.             return;   
  48.         }   
  49.         $row = $result->current();   
  50.         $guestbook->setId($row->id)   
  51.                 ->setEmail($row->email)   
  52.                 ->setComment($row->comment)   
  53.                 ->setCreated($row->created);   
  54.     }   
  55.   
  56.     public function fetchAll()   
  57.     {   
  58.         $resultSet = $this->getDbTable()->fetchAll();   
  59.         $entries = array();   
  60.         foreach ($resultSet as $row) {   
  61.         $entry = new Application_Model_Guestbook();   
  62.             $entry->setId($row->id)   
  63.                 ->setEmail($row->email)   
  64.                 ->setComment($row->comment)   
  65.                 ->setCreated($row->created);   
  66.             $entries[] = $entry;   
  67.         }   
  68.         return $entries;   
  69.     }   
  70. }  

 

现在是时候创建我们的模型类了。我们可以,再次的,使用 zf create model 命令

      % zf create model Guestbook
      Creating a model at application/models/Guestbook.php
      Updating project profile '.zfproject.xml'

我们会修改这个空的 PHP 类,通过传递一个数据数组给构造函数或者一个 setOptions() 方法,来使它简单的填充这个模型。最后的模型类,在 application/models/Guestbook.php 文件中,看起来象这样:

 

  1. >?php   
  2.   
  3. class Application_Model_Guestbook   
  4. {   
  5.     protected $_comment;   
  6.     protected $_created;   
  7.     protected $_email;   
  8.     protected $_id;   
  9.   
  10.     public function __construct(array $options = null)   
  11.     {   
  12.         if (is_array($options)) {   
  13.             $this->setOptions($options);   
  14.         }   
  15.     }   
  16.   
  17.     public function __set($name$value)   
  18.     {   
  19.         $method = 'set' . $name;   
  20.         if (('mapper' == $name) || !method_exists($this$method)) {   
  21.             throw new Exception('Invalid guestbook property');   
  22.         }   
  23.         $this->$method($value);   
  24.     }   
  25.   
  26.     public function __get($name)   
  27.     {   
  28.         $method = 'get' . $name;   
  29.         if (('mapper' == $name) || !method_exists($this$method)) {   
  30.             throw new Exception('Invalid guestbook property');   
  31.         }   
  32.         return $this->$method();   
  33.     }   
  34.   
  35.     public function setOptions(array $options)   
  36.     {   
  37.         $methods = get_class_methods($this);   
  38.         foreach ($options as $key => $value) {   
  39.             $method = 'set' . ucfirst($key);   
  40.             if (in_array($method$methods)) {   
  41.                 $this->$method($value);   
  42.             }   
  43.         }   
  44.         return $this;   
  45.     }   
  46.   
  47.     public function setComment($text)   
  48.     {   
  49.         $this->_comment = (string) $text;   
  50.         return $this;   
  51.     }   
  52.   
  53.     public function getComment()   
  54.     {   
  55.         return $this->_comment;   
  56.     }   
  57.   
  58.     public function setEmail($email)   
  59.     {   
  60.         $this->_email = (string) $email;   
  61.         return $this;   
  62.     }   
  63.   
  64.     public function getEmail()   
  65.     {   
  66.         return $this->_email;   
  67.     }   
  68.   
  69.     public function setCreated($ts)   
  70.     {   
  71.         $this->_created = $ts;   
  72.         return $this;   
  73.     }   
  74.   
  75.     public function getCreated()   
  76.     {   
  77.         return $this->_created;   
  78.     }   
  79.   
  80.     public function setId($id)   
  81.     {   
  82.         $this->_id = (int) $id;   
  83.         return $this;   
  84.     }   
  85.   
  86.     public function getId()   
  87.     {   
  88.         return $this->_id;   
  89.     }   
  90. }  

 

最后,为了把这些元素链接起来,让我们创建一个 guestbook 控制器,它将列出数据库中现有的条目,同时可以添加新的条目进数据库。

为了创建一个新的控制器,使用 zf create controller 命令:

      % zf create controller Guestbook
      Creating a controller at
          application/controllers/GuestbookController.php
      Creating an index action method in controller Guestbook
      Creating a view script for the index action method at
          application/views/scripts/guestbook/index.phtml
      Creating a controller test file at
          tests/application/controllers/GuestbookControllerTest.php
      Updating project profile '.zfproject.xml'

这将创建一个新控制器,GuestbookController,在 application/controllers/GuestbookController.php 文件中,带有一个单独的行为方法,indexAction()。它同时为这个控制器创建一个视图脚本目录, application/views/scripts/guestbook/,内有与这个 index 行为相对应的视图脚本。

我们使用 index 行为作为一个登陆页面来浏览留言本条目。

现在,让我们更新基本的应用程序逻辑。对于一个 indexAction() 的点击,我们将显示全部的留言本条目。它看起来是这样的:

 

  1. // application/controllers/GuestbookController.php   
  2.   
  3. class GuestbookController extends Zend_Controller_Action   
  4. {    
  5.     public function indexAction()    
  6.     {    
  7.         $guestbook = new Application_Model_GuestbookMapper();    
  8.         $this->view->entries = $guestbook->fetchAll();    
  9.     }    
  10. }  

 

同时,当然,我们需要一个视图脚本。修改 application/views/scripts/guestbook/index.phtml,如下显示:

 

  1. <p>   
  2. <a href="<?php echo $this->url(   
  3. array(   
  4. 'controller' => 'guestbook',   
  5. 'action' => 'sign'  
  6. ),   
  7. 'default',   
  8. true) ?>">Sign Our Guestbook</a></p>   
  9.   
  10. Guestbook Entries: <br />   
  11. <dl>   
  12. <?php foreach ($this->entries as $entry): ?>   
  13. <dt><?php echo $this->escape($entry->email) ?></dt>   
  14. <dd><?php echo $this->escape($entry->comment) ?></dd>   
  15. <?php endforeach ?>   
  16. </dl>  

 

注意:检查

现在浏览 http://localhost/guestbook,在你的浏览器中你应该能看到如下内容:

Zend Framework 1.10.4手册(ZF的快速启动四)_第1张图片

你可能感兴趣的:(数据结构,sql,PHP,sqlite,Zend)