Create a Model and Database Table
Before we get started, let's consider something: where will these classes live, and how will we find them? The default project we created instantiates an autoloader. We can attach other autoloaders to it so that it knows where to find different classes. Typically, we want our various MVC classes grouped under the same tree -- in this case,
application/ -- and most often using a common prefix.
Zend_Controller_Front has a notion of "modules", which are individual mini-applications. Modules mimic the directory structure that the
zf tool sets up under
application/, and all classes inside them are assumed to begin with a common prefix, the module name.
application/ is itself a module -- the "default" module. As such, let's setup autoloading for resources within this directory, giving them a prefix of "Default". We can do this by creating another bootstrap resource.
Zend_Application_Module_Autoloader provides the functionality needed to map the various resources under a module to the appropriate directories, and provides a standard naming mechanism as well. In our bootstrap resource, we'll instantiate this, and be done. The method looks like this:
_initAutoload()
{
$autoloader = Zend_Application_Module_Autoloader((
=> ,
=> dirname(__FILE__),
));
$autoloader;
}
The final bootstrap class will look as follows:
Bootstrap Zend_Application_Bootstrap_Bootstrap
{
_initAutoload()
{
$autoloader = Zend_Application_Module_Autoloader((
=> ,
=> dirname(__FILE__),
));
$autoloader;
}
_initDoctype()
{
$this->bootstrap();
$view = $this->getResource();
$view->doctype();
}
}
Now, let's consider what makes up a guestbook. Typically, they are simply a list of entries with a
comment,
timestamp, and, often,
email address. Assuming we store them in a database, we may also want a
unique identifier for each entry. We'll likely want to be able to save an entry, fetch individual entries, and retrieve all entries. As such, a simple guestbook model API might look something like this:
Default_Model_Guestbook
{
$_comment;
$_created;
$_email;
$_id;
__set($name, $value);
__get($name);
setComment($text);
getComment();
setEmail($email);
getEmail();
setCreated($ts);
getCreated();
setId($id);
getId();
save();
find($id);
fetchAll();
}
__get() and
__set() will provide a convenience mechanism for us to access the individual entry properties, and proxy to the other getters and setters. They also will help ensure that only properties we whitelist will be available in the object.
find() and
fetchAll() provide the ability to fetch a single entry or all entries.
Now from here, we can start thinking about setting up our database.
First we need to initialize our
Db resource. As with the
Layout and
View resource, we can provide configuration for the
Db resource. In your
application/configs/application.ini file, add the following lines in the appropriate sections.
; application/configs/application.ini
; Add these lines to the appropriate sections:
[production]
resources.db.adapter =
resources.db.params.dbname = APPLICATION_PATH
[testing : production]
resources.db.params.dbname = APPLICATION_PATH
[development : production]
resources.db.params.dbname = APPLICATION_PATH
Your final configuration file should look like the following:
; application/configs/application.ini
[production]
phpSettings.display_startup_errors =
phpSettings.display_errors =
bootstrap.path = APPLICATION_PATH
bootstrap. =
resources.frontController.controllerDirectory = APPLICATION_PATH
resources.layout.layoutPath = APPLICATION_PATH
resources.view[] =
resources.db.adapter =
resources.db.params.dbname = APPLICATION_PATH
[staging : production]
[testing : production]
phpSettings.display_startup_errors =
phpSettings.display_errors =
resources.db.params.dbname = APPLICATION_PATH
[development : production]
phpSettings.display_startup_errors =
phpSettings.display_errors =
resources.db.params.dbname = APPLICATION_PATH
Note that the database(s) will be stored in
data/db/. Create those directories, and make them world-writeable. On unix-like systems, you can do that as follows:
% mkdir -p data/db; chmod -R a+rwX data
On Windows, you will need to create the directories in Explorer and set the permissions to allow anyone to write to the directory.
At this point we have a connection to a database; in our case, its a connection to a Sqlite database located inside our
application/data/ directory. So, let's design a simple table that will hold our guestbook entries.
-- scripts/schema.sqlite.sql
--
-- You will need load your database schema with SQL.
CREATE TABLE guestbook (
id INTEGER NOT PRIMARY KEY AUTOINCREMENT,
email VARCHAR() NOT ,
comment TEXT ,
created DATETIME NOT
);
CREATE INDEX ON ();
And, so that we can have some working data out of the box, lets create a few rows of information to make our application interesting.
-- scripts/data.sqlite.sql
--
-- You can begin populating the database with the following SQL statements.
INSERT INTO guestbook (email, comment, created) VALUES
(,
,
DATETIME());
INSERT INTO guestbook (email, comment, created) VALUES
(,
,
DATETIME());
Now that we have both the schema and some data defined. Lets get a script together that we can now execute to build this database. Naturally, this is not needed in production, but this script will help developers build out the database requirements locally so they can have the fully working application. Create the script as
scripts/load.sqlite.php with the following contents:
<?php
defined()
|| define(, realpath(dirname(__FILE__) . ));
;
Zend_Loader_Autoloader::getInstance();
$getopt = Zend_Console_Getopt((
=> ,
=> ,
=> ,
));
{
$getopt->parse();
} (Zend_Console_Getopt_Exception $e) {
$e->getUsageMessage();
false;
}
($getopt->getOption()) {
$getopt->getUsageMessage();
true;
}
$withData = $getopt->getOption();
$env = $getopt->getOption();
defined()
|| define(, ( === $env) ? : $env);
$application = Zend_Application(
APPLICATION_ENV,
APPLICATION_PATH .
);
$bootstrap = $application->getBootstrap();
$bootstrap->bootstrap();
$dbAdapter = $bootstrap->getResource();
( != APPLICATION_ENV) {
. PHP_EOL;
($x = ; $x > ; $x--) {
$x . ; sleep();
}
}
$options = $bootstrap->getOption();
$dbFile = $options[][][];
(file_exists($dbFile)) {
unlink($dbFile);
}
{
$schemaSql = file_get_contents(dirname(__FILE__) . );
$dbAdapter->getConnection()->exec($schemaSql);
( != APPLICATION_ENV) {
PHP_EOL;
;
PHP_EOL;
}
($withData) {
$dataSql = file_get_contents(dirname(__FILE__) . );
$dbAdapter->getConnection()->exec($dataSql);
( != APPLICATION_ENV) {
;
PHP_EOL;
}
}
} ( $e) {
. PHP_EOL;
$e->getMessage() . PHP_EOL;
false;
}
true;
Now, let's execute this script. From a terminal or the DOS command line, do the following:
% php scripts/load.sqlite.php
You should see output like the following:
path/to/ZendFrameworkQuickstart/scripts$ php load.sqlite.php --withdata Writing Database Guestbook in (control-c to cancel): 1 Database Created Data Loaded.
Now we have a fully working database and table for our guestbook application. Our next few steps are to build out our application code. This includes building a data source (in our case, we will use
Zend_Db_Table), and a data mapper to connect that data source to our domain model. Finally we'll also create the controller that will interact with this model to both display existing entries and process new entries.
We'll use a
Table Data Gateway to connect to our data source;
Zend_Db_Table provides this functionality. To get started, lets create a
Zend_Db_Table-based table class. First, create the directory
application/models/DbTable/. Then create and edit a file
Guestbook.php within it, and add the following contents:
<?php
Default_Model_DbTable_Guestbook Zend_Db_Table_Abstract
{
$_name = ;
}
Note the class prefix:
Default_Model_DbTable. The class prefix "Default" from our autoloader is the first segment, and then we have the component, "Model_DbTable"; the latter is mapped to the
models/DbTable/ directory of the module.
All that is truly necessary when extending
Zend_Db_Table is to provide a table name and optionally the primary key (if it is not "id").
Now let's create a
Data Mapper. A
Data Mapper maps a domain object to the database. In our case, it will map our model,
Default_Model_Guestbook, to our data source,
Default_Model_DbTable_Guestbook. A typical API for a data mapper is as follows:
Default_Model_GuestbookMapper
{
save($model);
find($id, $model);
fetchAll();
}
In addition to these methods, we'll add methods for setting and retrieving the Table Data Gateway. The final class, located in
application/models/GuestbookMapper.php, looks like this:
Default_Model_GuestbookMapper
{
$_dbTable;
setDbTable($dbTable)
{
(is_string($dbTable)) {
$dbTable = $dbTable();
}
(!$dbTable instanceof Zend_Db_Table_Abstract) {
();
}
$this->_dbTable = $dbTable;
$this;
}
getDbTable()
{
( === $this->_dbTable) {
$this->setDbTable();
}
$this->_dbTable;
}
save(Default_Model_Guestbook $guestbook)
{
$data = (
=> $guestbook->getEmail(),
=> $guestbook->getComment(),
=> date(),
);
( === ($id = $guestbook->getId())) {
($data[]);
$this->getDbTable()->insert($data);
} {
$this->getDbTable()->update($data, ( => $id));
}
}
find($id, Default_Model_Guestbook $guestbook)
{
$result = $this->getDbTable()->find($id);
( == count($result)) {
;
}
$row = $result->current();
$guestbook->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created);
}
fetchAll()
{
$resultSet = $this->getDbTable()->fetchAll();
$entries = ();
($resultSet $row) {
$entry = Default_Model_Guestbook();
$entry->setId($row->id)
->setEmail($row->email)
->setComment($row->comment)
->setCreated($row->created)
->setMapper($this);
$entries[] = $entry;
}
$entries;
}
}
Now it's time to update our model class slightly, to accomodate the data mapper. Just like the data mapper contains a reference to the data source, the model contains a reference to the data mapper. Additionally, we'll make it easy to populate the model by passing an array of data either to the constructor or a
setOptions() method. The final model class, located in
application/models/Guestbook.php, looks like this:
Default_Model_Guestbook
{
$_comment;
$_created;
$_email;
$_id;
$_mapper;
__construct( $options = )
{
(is_array($options)) {
$this->setOptions($options);
}
}
__set($name, $value)
{
$method = . $name;
(( == $name) || !method_exists($this, $method)) {
();
}
$this->$method($value);
}
__get($name)
{
$method = . $name;
(( == $name) || !method_exists($this, $method)) {
();
}
$this->$method();
}
setOptions( $options)
{
$methods = get_class_methods($this);
($options $key => $value) {
$method = . ucfirst($key);
(in_array($method, $methods)) {
$this->$method($value);
}
}
$this;
}
setComment($text)
{
$this->_comment = (string) $text;
$this;
}
getComment()
{
$this->_comment;
}
setEmail($email)
{
$this->_email = (string) $email;
$this;
}
getEmail()
{
$this->_email;
}
setCreated($ts)
{
$this->_created = $ts;
$this;
}
getCreated()
{
$this->_created;
}
setId($id)
{
$this->_id = (int) $id;
$this;
}
getId()
{
$this->_id;
}
setMapper($mapper)
{
$this->_mapper = $mapper;
$this;
}
getMapper()
{
( === $this->_mapper) {
$this->setMapper( Default_Model_GuestbookMapper());
}
$this->_mapper;
}
save()
{
$this->getMapper()->save($this);
}
find($id)
{
$this->getMapper()->find($id, $this);
$this;
}
fetchAll()
{
$this->getMapper()->fetchAll();
}
}
Lastly, to connect these elements all together, lets create a guestbook controller that will both list the entries that are currently inside the database.
To create a new controller, open a terminal or DOS console, navigate to your project directory, and enter the following:
% zf.sh create controller guestbook
C:> zf.bat create controller guestbook
This will create a new controller,
GuestbookController, in
application/controllers/GuestbookController.php, with a single action method,
indexAction(). It will also create a view script directory for the controller,
application/views/scripts/guestbook/, with a view script for the index action.
We'll use the "index" action as a landing page to view all guestbook entries.
Now, let's flesh out the basic application logic. On a hit to
indexAction, we'll display all guestbook entries. This would look like the following:
GuestbookController Zend_Controller_Action
{
indexAction()
{
$guestbook = Default_Model_Guestbook();
$this->view->entries = $guestbook->fetchAll();
}
}
And, of course, we need a view script to go along with that. Edit
application/views/scripts/guestbook/index.phtml to read as follows:
<!-- application/views/scripts/guestbook/index.phtml -->
<p><a href=>Sign Our Guestbook</a></p>
Guestbook Entries: <br />
<dl>
<?php ($this->entries $entry): ?>
<dt><?php $this->escape($entry->email) ?></dt>
<dd><?php $this->escape($entry->comment) ?></dd>
<?php ?>
</dl>
Using the data loader script
The data loader script introduced in this section ("scripts/load.sqlite.php") can be used to create the database for each environment you have defined, as well as to load it with sample data. Internally, it utilizes
Zend_Console_Getopt
, which allows it to provide a number of command line switches. If you pass the "-h" or "--help" switch, it will give you the available options:
Usage: load.sqlite.php [ options ]
--withdata|-w Load database with sample data
--env|-e [ ] Application environment for which to create database
(defaults to development)
--help|-h Help -- usage message)]]
APPLICATION_ENV
-- which in turn allows you to create a SQLite database for each environment you define. Be sure to run the script for the environment you choose for your application when deploying.
0
收藏
转载于:https://blog.51cto.com/ud1121/188842