1.4 Zend Framework — Быстрый старт. Создание модели и таблицы базы данных

Zend, “Zend Framework Quick Start. Create a Model and Database Table”, public translation into Russian from English More about this translation.

Translate into another language.

Для начала, давайте рассмотрим: где находяться эти классы, и каким образом мы найдем их? По умолчанию в проекте, который мы создали, присутствует экземпляр автозагрузчика (autoloader). Мы можем подключать и другие автозагрузчики, таким образом, что бы он знал где искать разные классы. Обычно, мы хотим наши различные классы MVC группировать в одном и том же каталоге -- в нашем случае, application/ -- и чаще всего используем общий префикс.

Zend_Controller_Front имеет понятие "модули" ("modules"), которые являються отдельными мини-приложениями. Модули повторяют структуру каталогов, которую инструменты zf устанавливают в application/, и все классы находящиеся внутри, предполагается, что начинаются с общего префикса, имени модуля. application/ сам есть модуль -- модуль "default" или "application". По сути, мы устанавливаем автозагрузку для ресурсов на эту директории.

Zend_Application_Module_Autoloader обеспечивает функциональностью необходимой для сопоставления различных ресурсов модуля и соответствующих каталогов, а так же обеспечивает стандартный механизм именования. Экземпляр класса создаеться по умолчанию во время инициализации объекта загрузчика (bootstrap object); ваш загрузчик приложения будет по умолчанию использовать префикс модуля "Application". По сути, наши модули, формы, и классы таблиц все начинаются с префикса класса "Application_".

Теперь, давайте рассмотрим что представляет из себя гостевая книга. Как правило, это просто список записей с коментариями, меткой времени (timestamp), и, зачастую, email-адресом. Допустим мы будем хранить их в базе данных, нам так же необходим уникальный идендификатор для каждой записи. Нам, вероятней всего, будет необходимо иметь возможность сохранять запись, выбирать отдельные записи, и извлекать все записи. По сути, API модели простой гостевой книги может выглядеть примерно так:

01. // application/models/Guestbook.php

02.

03. class Application_Model_Guestbook

04. {

05. protected $_comment;

06. protected $_created;

07. protected $_email;

08. protected $_id;

09.

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() обеспечивает удобный механизм для доступа к отдельным свойствам записей, и посредник (proxy) для других геттеров (getters) и сеттеров (setters). Они так же помогут гарантировать что только свойства из рекомендованого списка (whitelist) будут доступны в объекте.

find() и fetchAll() обеспечивают возможность извлекать одну запись и все записи, в то время как save() заботиться о сохранении записи в хранилище данных.

Теперь с этого места, мы можем начинать думать о настройке нашей базы данных.

Во-первых мы должны инициализировать наш ресурс БД. В равной степенни с ресурсом Layout и View, мы можем обеспечить конфигурирование ресурса БД. Мы можем сделать это с помощью команды zf configure db-adapter:

01. % zf configure db-adapter \

02. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' \

03. > production

04. A db configuration for the production has been written to the application config file.

05.

06. % zf configure db-adapter \

07. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-testing.db"' \

08. > testing

09. A db configuration for the production has been written to the application config file.

10.

11. % zf configure db-adapter \

12. > 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-dev.db"' \

13. > development

14. A db configuration for the production has been written to the application config file.

Теперь отредактируйте ваш файл application/configs/application.ini, где вы увидите следующие строки добавленые в соответствующие секции.

01. ; application/configs/application.ini

02.

03. [production]

04. ; ...

05. resources.db.adapter = "PDO_SQLITE"

06. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"

07.

08. [testing : production]

09. ; ...

10. resources.db.adapter = "PDO_SQLITE"

11. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"

12.

13. [development : production]

14. ; ...

15. resources.db.adapter = "PDO_SQLITE"

16. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"

Ваш конечный файл конфигурации должен выглядеть следующим образом:

01. ; application/configs/application.ini

02.

03. [production]

04. phpSettings.display_startup_errors = 0

05. phpSettings.display_errors = 0

06. bootstrap.path = APPLICATION_PATH "/Bootstrap.php"

07. bootstrap.class = "Bootstrap"

08. appnamespace = "Application"

09. resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

10. resources.frontController.params.displayExceptions = 0

11. resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"

12. resources.view[] =

13. resources.db.adapter = "PDO_SQLITE"

14. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"

15.

16. [staging : production]

17.

18. [testing : production]

19. phpSettings.display_startup_errors = 1

20. phpSettings.display_errors = 1

21. resources.db.adapter = "PDO_SQLITE"

22. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"

23.

24. [development : production]

25. phpSettings.display_startup_errors = 1

26. phpSettings.display_errors = 1

27. resources.db.adapter = "PDO_SQLITE"

28. resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"

Заметьте, что база(ы) данных будет храниться в data/db/. Создайте эти каталоги, и сделайте их доступными для записи. На unix-подобных системах, вы можете сделать это следующим образом:

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

На Windows, вы должны создать эти каталоги в Explorer’е и установить доступ позволяющий всем записывать в каталог.

На данный момент у нас есть подключение к базе данных; в нашем варианте, это подключение к базе данных Sqlite расположенной в каталоге application/data/. Таким образом, давайте спроектируем простую таблицу, в которой будут храниться наши записи гостевой книги.

01. -- scripts/schema.sqlite.sql

02. --

03. -- Загрузите структуру базы данных с помощью этого SQL.

04.

05. CREATE TABLE guestbook (

06. id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,

07. email VARCHAR(32) NOT NULL DEFAULT '[email protected]',

08. comment TEXT NULL,

09. created DATETIME NOT NULL

10. );

11.

12. CREATE INDEX "id" ON "guestbook" ("id");

И, для того что бы мы могли иметь некоторые рабочие данные из коробки, давайте создадим несколько строк с данными, что бы сделать наше приложение интересным.

01. -- scripts/data.sqlite.sql

02. --

03. -- Можете начать заполнять базу данных со следующего SQL запроса.

04.

05. INSERT INTO guestbook (email, comment, created) VALUES

07. 'Hello! Hope you enjoy this sample zf application!',

08. DATETIME('NOW'));

09. INSERT INTO guestbook (email, comment, created) VALUES

11. 'Baz baz baz, baz baz Baz baz baz - baz baz baz.',

12. DATETIME('NOW'));

Теперь у нас есть и структура и некоторые определенные данные. Давайте получим скрипт, который мы можем сейчас выполнить для построения этой базы данных. Конечно это не требуется в production версии, но этот скрипт поможет разработчикам создать требуемую базу данных локально, так у них будет полностью работающее приложение. Создайте скрипт scripts/load.sqlite.php следующего содержания:

01. // scripts/load.sqlite.php

02.

03. /**

04. * Скрипт для создания и загрузки базы данных

05. */

06.

07. // Initialize the application path and autoloading

08. defined('APPLICATION_PATH')

09. || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

10. set_include_path(implode(PATH_SEPARATOR, array(

11. APPLICATION_PATH . '/../library',

12. get_include_path(),

13. )));

14. require_once 'Zend/Loader/Autoloader.php';

15. Zend_Loader_Autoloader::getInstance();

16.

17. // Define some CLI options

18. $getopt = new Zend_Console_Getopt(array(

19. 'withdata|w' => 'Load database with sample data',

20. 'env|e-s' => 'Application environment for which to create database (defaults to development)',

21. 'help|h' => 'Help -- usage message',

22. ));

23. try {

24. $getopt->parse();

25. } catch (Zend_Console_Getopt_Exception $e) {

26. // Bad options passed: report usage

27. echo $e->getUsageMessage();

28. return false;

29. }

30.

31. // If help requested, report usage message

32. if ($getopt->getOption('h')) {

33. echo $getopt->getUsageMessage();

34. return true;

35. }

36.

37. // Initialize values based on presence or absence of CLI options

38. $withData = $getopt->getOption('w');

39. $env = $getopt->getOption('e');

40. defined('APPLICATION_ENV')

41. || define('APPLICATION_ENV', (null === $env) ? 'development' : $env);

42.

43. // Initialize Zend_Application

44. $application = new Zend_Application(

45. APPLICATION_ENV,

46. APPLICATION_PATH . '/configs/application.ini'

47. );

48.

49. // Initialize and retrieve DB resource

50. $bootstrap = $application->getBootstrap();

51. $bootstrap->bootstrap('db');

52. $dbAdapter = $bootstrap->getResource('db');

53.

54. // let the user know whats going on (we are actually creating a

55. // database here)

56. if ('testing' != APPLICATION_ENV) {

57. echo 'Writing Database Guestbook in (control-c to cancel): ' . PHP_EOL;

58. for ($x = 5; $x > 0; $x--) {

59. echo $x . "\r"; sleep(1);

60. }

61. }

62.

63. // Check to see if we have a database file already

64. $options = $bootstrap->getOption('resources');

65. $dbFile = $options['db']['params']['dbname'];

66. if (file_exists($dbFile)) {

67. unlink($dbFile);

68. }

69.

70. // this block executes the actual statements that were loaded from

71. // the schema file.

72. try {

73. $schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');

74. // use the connection directly to load sql in batches

75. $dbAdapter->getConnection()->exec($schemaSql);

76. chmod($dbFile, 0666);

77.

78. if ('testing' != APPLICATION_ENV) {

79. echo PHP_EOL;

80. echo 'Database Created';

81. echo PHP_EOL;

82. }

83.

84. if ($withData) {

85. $dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');

86. // use the connection directly to load sql in batches

87. $dbAdapter->getConnection()->exec($dataSql);

88. if ('testing' != APPLICATION_ENV) {

89. echo 'Data Loaded.';

90. echo PHP_EOL;

91. }

92. }

93.

94. } catch (Exception $e) {

95. echo 'AN ERROR HAS OCCURED:' . PHP_EOL;

96. echo $e->getMessage() . PHP_EOL;

97. return false;

98. }

99.

100. // generally speaking, this script will be run from the command line

101. return true;

Теперь давайте выполним этот скрипт. Из терминала или командной строки DOS, выполните следующее:

01. % php scripts/load.sqlite.php --withdata

В результате вы увидите примерно следующее:

01. path/to/ZendFrameworkQuickstart/scripts$ php load.sqlite.php --withdata

02. Writing Database Guestbook in (control-c to cancel):

03. 1

04. Database Created

05. Data Loaded.

Теперь у нас есть полностью работающая база данных и таблица для нашего приложения гостевой книги. Наши следующие несколько шагов это создание нашего кода приложения. Это включает построение источника данных (data source) (в нашем случае, мы используем Zend_Db_Table), и data mapper для подключения источника данных (data source) к нашей области данных модели. В конце мы также создадим контроллер который будет взаимодействовать с этой моделью и для вывода существующих записей и для обработки новых записей.

Мы используем » Table Data Gateway для соединения с источником данных (data source); Zend_Db_Table предоставляет такую функциональность. Для начала, давайте создадим класс таблицы основанный на Zend_Db_Table. Так же, как для макета (layouts) и адаптера базы данных (database adapter), мы можем использовать zf tool для помощи, используя команду create db-table. Эта команда принимает минимум два аргумента, имя которое вы хотите дать классу, и таблица базы данных соответствующая ему.

01. % zf create db-table Guestbook guestbook

02. Creating a DbTable at application/models/DbTable/Guestbook.php

03. Updating project profile 'zfproject.xml'

Посмотрите на дерево каталогов, вы увидите новый каталог, application/models/DbTable/, и созданный файл Guestbook.php. Если вы откроете этот файл, то увидите следующее содержимое:

01. // application/models/DbTable/Guestbook.php

02.

03. /**

04. * Это класс DbTable для таблицы guestbook.

*/

06. class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract

07. {

08. /** Имя таблицы */

09. protected $_name = 'guestbook';

10. }

Обратите внимание на префикс класса: Application_Model_DbTable. Префикс класса для нашего модуля, "Application", в первой части, далее у нас компонент, "Model_DbTable"; последний соответствует директории модуля models/DbTable/.

Все что действительно необходимо когда расширяется Zend_Db_Table, это предоставить имя таблицы и возможно имя первичного ключа (если это не "id").

Теперь давайте создадим » Data Mapper. Data Mapper устанавливает соответствие между облатью данных объекта и базой данных. В нашем случае, это структура нашей модели, Application_Model_Guestbook, и наш источник данных, Application_Model_DbTable_Guestbook. Как правило API для data mapper выглядят следующим образом:

01. // application/models/GuestbookMapper.php

02.

03. class Application_Model_GuestbookMapper

04. {

05. public function save($model);

06. public function find($id, $model);

07. public function fetchAll();

08. }

В дополнение к этим методам, добавим еще методы для установки и извлечения шлюза к данным таблицы (Table Data Gateway). Создайте исходный класс, используя инструменты zf CLI:

01. % zf create model GuestbookMapper

02. Creating a model at application/models/GuestbookMapper.php

03. Updating project profile '.zfproject.xml'

Теперь отредактируем класс Application_Model_GuestbookMapper в application/models/GuestbookMapper.php следующим образом:

01. // application/models/GuestbookMapper.php

02.

03. class Application_Model_GuestbookMapper

04. {

05. protected $_dbTable;

06.

07. public function setDbTable($dbTable)

08. {

09. 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($data, array('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:

01. % zf create model Guestbook

02. Creating a model at application/models/Guestbook.php

03. Updating project profile '.zfproject.xml'

Мы изменим этот пустой PHP класс что бы сделать его легким для наполнения модели при передаче массива данных либо в конструктор, либо в метод setOptions(). Готовый класс модели, расположенный в application/models/Guestbook.php, должен выглядеть следующим образом:

01. // application/models/Guestbook.php

02.

03. class Application_Model_Guestbook

04. {

05. protected $_comment;

06. protected $_created;

07. protected $_email;

08. protected $_id;

09.

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:

01. % zf create controller Guestbook

02. Creating a controller at

03. application/controllers/GuestbookController.php

04. Creating an index action method in controller Guestbook

05. Creating a view script for the index action method at

06. application/views/scripts/guestbook/index.phtml

07. Creating a controller test file at

08. tests/application/controllers/GuestbookControllerTest.php

09. Updating project profile '.zfproject.xml'

Это создаст новый контроллер, GuestbookController, в application/controllers/GuestbookController.php, с единственным действием (action), метод indexAction(). Это, к тому же, создаст каталог для view-скриптов контроллера, application/views/scripts/guestbook/, с view-скриптом для действия (action) index.

Мы используем действие "index" как целевую страницу для показа всех записей гостевой книги.

Теперь давайте расширять основную логику приложения. При попадании на indexAction(), мы выводим все записи гостевой книги. Это должно выглядеть следующим образом:

01. // application/controllers/GuestbookController.php

02.

03. class GuestbookController extends Zend_Controller_Action

04. {

05. public function indexAction()

06. {

07. $guestbook = new Application_Model_GuestbookMapper();

08. $this->view->entries = $guestbook->fetchAll();

09. }

10. }

И конечно, мы должны привести в соответствие наш view-скрипт. Отредактируйте application/views/scripts/guestbook/index.phtml следующим образом:

01. <!-- application/views/scripts/guestbook/index.phtml -->

02.

03. <p><a href="<?php echo $this->url(

04. array(

05. 'controller' => 'guestbook',

06. 'action' => 'sign'

07. ),

08. 'default',

09. true) ?>">Sign Our Guestbook</a></p>

10.

11. Guestbook Entries: <br />

12. <dl>

13. <?php foreach ($this->entries as $entry): ?>

14. <dt><?php echo $this->escape($entry->email) ?></dt>

15. <dd><?php echo $this->escape($entry->comment) ?></dd>

16. <?php endforeach ?>

17. </dl>

Замечание: Контрольная точка

Теперь перейдите на "http://localhost/guestbook". В браузере вы должны увидеть следующее:

learning.quickstart.create-model.png

Замечание: Использование скрипта загрузчика данных

Скрипт загрузчика данных предложенный в этой части (scripts/load.sqlite.php) может быть использован для создания базы данных для каждой среды (environment) которые вы определите, а так же наполнение тестовыми данных. Внутри, он использует Zend_Console_Getopt, который позволяет управлять набором опций командной строки. Если вы передадите "-h" или "--help", он выдаст вам доступные параметры:

01. Usage: load.sqlite.php [ options ]

02. --withdata|-w Load database with sample data

03. --env|-e [ ] Application environment for which to create database

04. (defaults to development)

05. --help|-h Help -- usage message)]]

Ключ "-e" позволяет вам определить значение используемое для константы APPLICATION_ENV -- который позволяет создать различные базы данных SQLite для каждой среды определенный вами. Не забудьте запустить скрипт для среды, которую вы выберите, для вашего приложения при развёртывании.

Pages: ← previous Ctrl next
1 2 3 4 5

Original (English): Zend Framework Quick Start. Create a Model and Database Table

Translation: © antdmi, Владимир, whitebug .

translatedby.com crowd

Like this translation? Share it or bookmark!