同时还有中文Zend Php Framework
Zend Framework 中文版手册在线浏览
The Zend Framework has been unveiled! Although it is still in the early stages of development, this tutorial highlights some of the best of what's available now and guides you through the process of building a simple application.
Zend has chosen to release the framework and involve the community early. In the same spirit, this tutorial is written to showcase the framework as it exists today. Because this tutorial is published online, I'll update it as the framework evolves, so that it remains relevant as long as possible.
Requirements
The Zend Framework requires PHP 5. In order to take full advantage of the code presented in this tutorial, you also need the Apache web server, because the sample application (a news management system) uses
mod_rewrite
.
The code from this tutorial is available for free download, so you can try it out for yourself. You can download it from the Brain Bulb web site at http://brainbulb.com/zend-framework-tutorial.tar.gz.
Downloading the Framework
Before you can get started with this tutorial, you need to download the preview release of the framework. You can do this manually by visiting http://framework.zend.com/download with a browser and choosing the
tar.gz
or
zip
download, or you can use the command line:
$ wget http://framework.zend.com/download/tgz
$ tar -xvzf ZendFramework-0.1.2.tar.gz
Note:
Zend has plans to offer its own PEAR channel to help simplify the download process.
Once you have the preview release, locate the
library
directory and place it somewhere convenient. In this tutorial, I rename
library
to
lib
to provide a clean and simple directory structure:
app/
views/
controllers/
www/
.htaccess
index.php
lib/
The
www
directory is the document root,
controllers
and
views
are empty directories you'll use later, and the
lib
directory is from the preview release download.
Getting Started
The first component I want to show you is
Zend_Controller
. In many ways, it provides the foundation of the application you're developing, and it's also part of what makes the Zend Framework more than just a collection of components. Before you can use it, however, you need to direct all incoming requests to a single PHP script. This tutorial uses
mod_rewrite
for this purpose.
Using
mod_rewrite
is an art in itself, but luckily, this particular task is very simple. If you're unfamiliar with
mod_rewrite
or configuring Apache in general, create a
.htaccess
file in the document root and add the following directives:
RewriteEngine on
RewriteRule !/.(js|ico|gif|jpg|png|css)$ index.php
Note:
One of the TODO items for
Zend_Controller
is to remove the
mod_rewrite
dependency. In order to provide an example that works with the preview release, this tutorial uses
mod_rewrite
.
If you add these directives to
httpd.conf
directly, you must restart the web server. Otherwise, if you use a
.htaccess
file, you should be good to go. You can quickly test this by placing some identifiable text in
index.php
and making a request for an arbitrary path such as
/foo/bar
. For example, if your host is
example.org
, request the URL http://example.org/foo/bar.
You also want
include_path
to include the path to the framework library. You can do this in
php.ini
, or you can just put the following directive in your
.htaccess
file:
php_value include_path "/path/to/lib"
Zend
The
Zend
class contains a collection of static methods that are universally useful. This is the only class you must include manually:
<?php
include
'Zend.php'
;
?>
Once you've included
Zend.php
, you have access to all of the methods from the
Zend
class. Loading other classes is simplified with the
loadClass()
method. For example, to load the
Zend_Controller_Front
class:
<?php
include
'Zend.php'
;
Zend
::
loadClass
(
'Zend_Controller_Front'
);
?>
The
loadclass()
method is
include_path
aware, and it also understands the organization and directory structure of the framework. I use it to load all other classes.
Zend_Controller
Using the controller is pretty intuitive. In fact, I'm writing this tutorial without the luxury of documentation!
Note:
Documentation is now available at http://framework.zend.com/manual/zend.controller.html.
I begin with
Zend_Controller_Front
, a front controller. In order to begin understanding how it works, place the following code in your
index.php
file:
<?php
include
'Zend.php'
;
Zend
::
loadClass
(
'Zend_Controller_Front'
);
$controller
=
Zend_Controller_Front
::
getInstance
();
$controller
->
setControllerDirectory
(
'/path/to/controllers'
);
$controller
->
dispatch
();
?>
If you prefer object chaining, this can instead be written as:
<?php
include
'Zend.php'
;
Zend
::
loadClass
(
'Zend_Controller_Front'
);
$controller
=
Zend_Controller_Front
::
getInstance
()
->
setControllerDirectory
(
'/path/to/controllers'
)
->
dispatch
();
?>
Now when you make a request for
/foo/bar
, you get an error. That's good! It lets you know something is happening. The major complaint is that
IndexController.php
is not found.
Before you create this file, it's helpful to understand how the framework expects you to organize things. The framework breaks a request down into parts, and in the case of a request for
/foo/bar
,
foo
is the controller, and
bar
is the action. The default value for each is
index
.
When
foo
is the controller, the framework looks for a file called
FooController.php
in the
controllers
directory. Because this does not exist, the framework falls back to
IndexController.php
. Not finding either, it reports the error.
To continue, create
IndexController.php
in the
controllers
directory (which you set with
setControllerDirectory()
):
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
class
IndexController
extends
Zend_Controller_Action
{
public function
indexAction
()
{
echo
'IndexController::indexAction()'
;
}
}
?>
The
IndexController
class handles requests for which the controller is
index
or for which the indicated controller does not exist, as just explained. The
indexAction()
method handles requests for which the action is
index
. Remember that
index
is the default value for both the controller and the action. If you try a request for
/
,
/index
, or
/index/index
, the
indexAction()
method is executed. (Trailing slashes do not alter this behavior.) A request for any other resource is going to result in an error.
There is another useful method to add to
IndexController
before continuing. The
noRouteAction()
method is called whenever a request is made for a controller that doesn't exist. For example, a request for
/foo/bar
executes
noRouteAction()
if
FooController.php
does not exist. However, a request for
/index/foo
still results in an error, because
foo
is the action, not the controller.
Add
noRouteAction()
to
IndexController.php
:
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
class
IndexController
extends
Zend_Controller_Action
{
public function
indexAction
()
{
echo
'IndexController::indexAction()'
;
}
public function
noRouteAction
()
{
$this
->
_redirect
(
'/'
);
}
}
?>
This example uses
$this->_redirect('/')
to illustrate a possible action to take in
noRouteAction()
. This causes requests for nonexistent controllers to be redirected to the root document (front page).
Now create
FooController.php
:
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
class
FooController
extends
Zend_Controller_Action
{
public function
indexAction
()
{
echo
'FooController::indexAction()'
;
}
public function
barAction
()
{
echo
'FooController::barAction()'
;
}
}
?>
If you again request
/foo/bar
, you should see that
barAction()
is being executed, because
bar
is the action. Not only can you already support friendly URLs, but you can also do so in a very organized way with just a few lines of code. Cool!
You can also create a
__call()
method to handle requests for undefined actions such as
/foo/baz
:
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
class
FooController
extends
Zend_Controller_Action
{
public function
indexAction
()
{
echo
'FooController::indexAction()'
;
}
public function
barAction
()
{
echo
'FooController::barAction()'
;
}
public function
__call
(
$action
,
$arguments
)
{
echo
'FooController:__call()'
;
}
}
?>
Now that you can elegantly handle incoming requests with just a few lines of code, you are ready to continue.
Zend_View
Zend_View
is a class that helps you organize your view logic. It is template-system agnostic, and for the sake of simplicity, I don't use a template system in this tutorial. You're free to use one if you prefer.
Keep in mind that all incoming requests are now handled by the front controller. Therefore, the framework of the application already exists, and further additions must conform to it. In order to demonstrate a very basic use of
Zend_View
, change the code in
IndexController.php
as follows:
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
Zend
::
loadClass
(
'Zend_View'
);
class
IndexController
extends
Zend_Controller_Action
{
public function
indexAction
()
{
$view
= new
Zend_View
();
$view
->
setScriptPath
(
'/path/to/views'
);
echo
$view
->
render
(
'example.php'
);
}
public function
noRouteAction
()
{
$this
->
_redirect
(
'/'
);
}
}
?>
Create a file called
example.php
in the
views
directory:
<html>
<head>
<title>This Is an Example</title>
</head>
<body>
<p>This is an example.</p>
</body>
</html>
Now, when you request your web site's root resource, you should see the contents of
example.php
. This isn't very useful yet, but keep in mind that you're working toward a very structured and organized way to develop web applications.
In order to make the use of
Zend_View
a bit clearer, modify your template (
example.php
) to include some data:
<html>
<head>
<title>
<?php
echo
$this
->
escape
(
$this
->
title
);
?>
</title>
</head>
<body>
<?php
echo
$this
->
escape
(
$this
->
body
);
?>
</body>
</html>
Two additional features have been added. The
$this->escape()
method must be used on all output. Even if you create the output yourself, which is going to be the case in this example, escaping all output is a very good habit that can help you prevent cross-site scripting (XSS) vulnerabilities by default.
The
$this->title
and
$this->body
properties exist to demonstrate dynamic data. These should be defined in the controller, so modify
IndexController.php
to assign them:
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
Zend
::
loadClass
(
'Zend_View'
);
class
IndexController
extends
Zend_Controller_Action
{
public function
indexAction
()
{
$view
= new
Zend_View
();
$view
->
setScriptPath
(
'/path/to/views'
);
$view
->
title
=
'Dynamic Title'
;
$view
->
body
=
'This is a dynamic body.'
;
echo
$view
->
render
(
'example.php'
);
}
public function
noRouteAction
()
{
$this
->
_redirect
(
'/'
);
}
}
?>
Now you should see these values being used by the template when you again visit your web site's root directory. The reason you use
$this
in the template is that it is executed within the scope of the
Zend_View
instance.
Keep in mind that
example.php
is just an ordinary PHP script, so you can do anything you want. Just try to be disciplined enough to limit your use of templates to only what is required to display data. Your controller (or a module to which the controller dispatches) should handle all of your business logic.
I want to make one final note about
Zend_View
before continuing. Instantiating the
$view
object within each method of the controller requires a lot of extra typing, and our primary goal is to make it easier to quickly develop web applications. It's also a hassle to call
setScriptPath()
in each case if all of the templates reside in a single directory.
Luckily, the
Zend
class includes a registry that helps you eliminate this overhead. You can store your
$view
object in the registry by using the
register()
method:
<?php
Zend
::
register
(
'view'
,
$view
);
?>
To retrieve it, use the
registry()
method:
<?php
$view
=
Zend
::
registry
(
'view'
);
?>
From this point forward, this tutorial uses the registry.
Zend_InputFilter
The last component this tutorial covers is
Zend_InputFilter
. This class provides a simple but rigid approach to input filtering. You instantiate it by passing an array of data to be filtered:
<?php
$filterPost
= new
Zend_InputFilter
(
$_POST
);
?>
This sets the array (
$_POST
) to
NULL
, so direct access is no longer possible.
Zend_InputFilter
instead provides a small, focused collection of methods that filter data according to specific criteria. For example, if you want the alphabetic characters of
$_POST['name'
], you can use the
getAlpha()
method:
<?php
/* $_POST['name'] = 'John123Doe'; */
$filterPost
= new
Zend_InputFilter
(
$_POST
);
/* $_POST = NULL; */
$alphaName
=
$filterPost
->
getAlpha
(
'name'
);
/* $alphaName = 'JohnDoe'; */
?>
The argument you pass each filtering method is the key that corresponds to the array element to be filtered. The object (
$filterPost
in this example) is a protected cage that contains the tainted data, making access to that data more controlled and consistent. Therefore, you should always use
Zend_InputFilter
when you need to access input.
Note:
Zend_Filter
provides static filtering methods that follow the same conventions as the
Zend_InputFilter
methods.
Building a News Management System
Although the preview release contains many more components (and even more are being developed), the components already discussed provide all you need to build a simple application. In the process, you should gain a clearer understanding of the framework's basic structure and design.
Everyone develops applications a bit differently, and the Zend Framework tries to embrace diversity as much as possible. Similarly, this tutorial is subject to my preferences, so please adjust these to suite your own tastes.
When I begin developing an application, I start with the interface. This doesn't mean I spend hours with markup, stylesheets, and images, but I do approach the problem from the perspective of a user. As such, I see an application as a collection of pages, where each page is a unique URL. This news management system consists of the following URLs:
/
/add/news
/add/comment
/admin
/admin/approve
/view/{id}
You want to immediately begin thinking of these URLs in terms of controllers. The
IndexController
lists the news, the
AddController
handles adding news and comments, the
AdminController
handles administrative actions such as approving news, and the
ViewController
handles viewing a specific news entry and its corresponding comments.
Begin by removing
FooController.php
if it still exists, and modify
IndexController.php
to add the appropriate actions and some comments as placeholders for the business logic:
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
class
IndexController
extends
Zend_Controller_Action
{
public function
indexAction
()
{
/* List the news. */
}
public function
noRouteAction
()
{
$this
->
_redirect
(
'/'
);
}
}
?>
Next, create
AddController.php
:
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
class
AddController
extends
Zend_Controller_Action
{
function
indexAction
()
{
$this
->
_redirect
(
'/'
);
}
function
commentAction
()
{
/* Add a comment. */
}
function
newsAction
()
{
/* Add news. */
}
function
__call
(
$action
,
$arguments
)
{
$this
->
_redirect
(
'/'
);
}
}
?>
Note that the
indexAction()
method of
AddController
should never be called. This only happens when the requested path is
/add
. Because a user might explore the URLs manually, this is likely, so you can redirect the user to the front page, display an error, or take whatever action you feel is appropriate.
Next, create
AdminController.php
:
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
class
AdminController
extends
Zend_Controller_Action
{
function
indexAction
()
{
/* Display admin interface. */
}
function
approveAction
()
{
/* Approve news. */
}
function
__call
(
$action
,
$arguments
)
{
$this
->
_redirect
(
'/'
);
}
}
?>
Finally, create
ViewController.php
:
<?php
Zend
::
loadClass
(
'Zend_Controller_Action'
);
class
ViewController
extends
Zend_Controller_Action
{
function
indexAction
()
{
$this
->
_redirect
(
'/'
);
}
function
__call
(
$id
,
$arguments
)
{
/* Display news and comments for $id. */
}
}
?>
As with
AddController
, the
index()
method should never be called, so you can take whatever action you feel is appropriate.
ViewController
is a bit different than the others, because you don't know what the valid actions are. In order to support URLs like
/view/23
, you must support dynamic actions with
__call()
.
Interacting with the Database
Because the database components of the Zend Framework are still relatively unstable, and because I want this demo to be easy to work with, I use a simple class that uses SQLite for storing and retrieving news entries and comments:
<?php
class
Database
{
private
$_db
;
public function
__construct
(
$filename
)
{
$this
->
_db
= new
SQLiteDatabase
(
$filename
);
}
public function
addComment
(
$name
,
$comment
,
$newsId
)
{
$name
=
sqlite_escape_string
(
$name
);
$comment
=
sqlite_escape_string
(
$comment
);
$newsId
=
sqlite_escape_string
(
$newsId
);
$sql
=
"INSERT
INTO comments (name, comment, newsId)
VALUES ('$name', '$comment', '$newsId')"
;
return
$this
->
_db
->
query
(
$sql
);
}
public function
addNews
(
$title
,
$content
)
{
$title
=
sqlite_escape_string
(
$title
);
$content
=
sqlite_escape_string
(
$content
);
$sql
=
"INSERT
INTO news (title, content)
VALUES ('$title', '$content')"
;
return
$this
->
_db
->
query
(
$sql
);
}
public function
approveNews
(
$ids
)
{
foreach (
$ids
as
$id
) {
$id
=
sqlite_escape_string
(
$id
);
$sql
=
"UPDATE news
SET approval = 'T'
WHERE id = '$id'"
;
if (!
$this
->
_db
->
query
(
$sql
)) {
return
FALSE
;
}
}
return
TRUE
;
}
public function
getComments
(
$newsId
)
{
$newsId
=
sqlite_escape_string
(
$newsId
);
$sql
=
"SELECT name, comment
FROM comments
WHERE newsId = '$newsId'"
;
if (
$result
=
$this
->
_db
->
query
(
$sql
)) {
return
$result
->
fetchAll
();
}
return
FALSE
;
}
public function
getNews
(
$id
=
'ALL'
)
{
$id
=
sqlite_escape_string
(
$id
);
switch (
$id
) {
case
'ALL'
:
$sql
=
"SELECT id,
title
FROM news
WHERE approval = 'T'"
;
break;
case
'NEW'
:
$sql
=
"SELECT *
FROM news
WHERE approval != 'T'"
;
break;
default:
$sql
=
"SELECT *
FROM news
WHERE id = '$id'"
;
break;
}
if (
$result
=
$this
->
_db
->
query
(
$sql
)) {
if (
$result
->
numRows
() !=
1
) {
return
$result
->
fetchAll
();
} else {
return
$result
->
fetch
();
}
}
return
FALSE
;
}
}
?>
(You're free to replace this class with your own solution. This is only included to provide a complete example and is not meant to suggest an implementation.)
The constructor of this class expects the full path and filename of the SQLite database, something you must create:
<?php
$db
= new
SQLiteDatabase
(
'/path/to/db.sqlite'
);
$db
->
query
(
"CREATE TABLE news (
id INTEGER PRIMARY KEY,
title VARCHAR(255),
content TEXT,
approval CHAR(1) DEFAULT 'F'
)"
);
$db
->
query
(
"CREATE TABLE comments (
id INTEGER PRIMARY KEY,
name VARCHAR(255),
comment TEXT,
newsId INTEGER
)"
);
?>
You only need to do this once, then you can just pass the full path and filename to the constructor of the
Database
class:
<?php
$db
= new
Database
(
'/path/to/db.sqlite'
);
?>
Putting It All Together
To put this all together, create
Database.php
in the
lib
directory, and
loadClass()
will be able to find it. Your
index.php
file should now instantiate
$view
and
$db
and store them in the registry. You can also create a function called
__autoload()
to automatically handle loading all the classes you need:
<?php
include
'Zend.php'
;
function
__autoload
(
$class
)
{
Zend
::
loadClass
(
$class
);
}
$db
= new
Database
(
'/path/to/db.sqlite'
);
Zend
::
register
(
'db'
,
$db
);
$view
= new
Zend_View
;
$view
->
setScriptPath
(
'/path/to/views'
);
Zend
::
register
(
'view'
,
$view
);
$controller
=
Zend_Controller_Front
::
getInstance
()
->
setControllerDirectory
(
'/path/to/controllers'
)
->
dispatch
();
?>
Next, create some simple templates in the
views
directory. The
index.php
file can be used for displaying the index view:
<html>
<head>
<title>News</title>
</head>
<body>
<h1>News</h1>
<?php
foreach (
$this
->
news
as
$entry
) {
?>
<p>
<a href="/view/
<?php
echo
$this
->
escape
(
$entry
[
'id'
]);
?>
">
<?php
echo
$this
->
escape
(
$entry
[
'title'
]);
?>
</a>
</p>
<?php
}
?>
<h1>Add News</h1>
<form action="/add/news" method="POST">
<p>Title:<br /><input type="text" name="title" /></p>
<p>Content:<br /><textarea name="content"></textarea></p>
<p><input type="submit" value="Add News" /></p>
</form>
</body>
</html>
The
view.php
template can be used for displaying a specific news entry:
<html>
<head>
<title>
<?php
echo
$this
->
escape
(
$this
->
news
[
'title'
]);
?>
</title>
</head>
<body>
<h1>
<?php
echo
$this
->
escape
(
$this
->
news
[
'title'
]);
?>
</h1>
<p>
<?php
echo
$this
->
escape
(
$this
->
news
[
'content'
]);
?>
</p>
<h1>Comments</h1>
<?php
foreach (
$this
->
comments
as
$comment
) {
?>
<p>
<?php
echo
$this
->
escape
(
$comment
[
'name'
]);
?>
writes:
</p>
<blockquote>
<?php
echo
$this
->
escape
(
$comment
[
'comment'
]);
?>
</blockquote>
<?php
}
?>
<h1>Add a Comment</h1>
<form action="/add/comment" method="POST">
<input type="hidden" name="newsId"
value="
<?php
echo
$this
->
escape
(
$this
->
id
);
?>
" />
<p>Name:<br /><input type="text" name="name" /></p>
<p>Comment:<br /><textarea name="comment"></textarea></p>
<p><input type="submit" value="Add Comment" /></p>
</form>
</body>
</html>
Finally, the
admin.php
template can be used to approve news entries:
<html>
<head>
<title>News Admin</title>
</head>
<body>
<form action="/admin/approve" method="POST">
<?php
foreach (
$this
->
news
as
$entry
) {
?>
<p>
<input type="checkbox" name="ids[]"
value="
<?php
echo
$this
->
escape
(
$entry
[
'id'
]);
?>
" />
<?php
echo
$this
->
escape
(
$entry
[
'title'
]);
?>
<?php
echo
$this
->
escape
(
$entry
[
'content'
]);
?>
</p>
<?php
}
?>
<p>
Password:<br /><input type="password" name="password" />
</p>
<p><input type="submit" value="Approve" /></p>
</form>
</body>
</html>
Note:
To keep things simple, this form accepts a password as an access control mechanism.
With the templates in place, you just need to replace the comment placeholders in the controllers with a few lines of code. For example,
IndexController.php
becomes the following:
<?php
class
IndexController
extends
Zend_Controller_Action
{
public function
indexAction
()
{
/* List the news. */
$db
=
Zend
::
registry
(
'db'
);
$view
=
Zend
::
registry
(
'view'
);
$view
->
news
=
$db
->
getNews
();
echo
$view
->
render
(
'index.php'
);
}
public function
noRouteAction
()
{
$this
->
_redirect
(
'/'
);
}
}
?>
With everything organized, the entire business logic for the front page of this application is reduced to four lines of code.
AddController.php
is a bit more involved, so it requires more code:
<?php
class
AddController
extends
Zend_Controller_Action
{
function
indexAction
()
{
$this
->
_redirect
(
'/'
);
}
function
commentAction
()
{
/* Add a comment. */
$filterPost
= new
Zend_InputFilter
(
$_POST
);
$db
=
Zend
::
registry
(
'db'
);
$name
=
$filterPost
->
getAlpha
(
'name'
);
$comment
=
$filterPost
->
noTags
(
'comment'
);
$newsId
=
$filterPost
->
getDigits
(
'newsId'
);
$db
->
addComment
(
$name
,
$comment
,
$newsId
);
$this
->
_redirect
(
"/view/$newsId"
);
}
function
newsAction
()
{
/* Add news. */
$filterPost
= new
Zend_InputFilter
(
$_POST
);
$db
=
Zend
::
registry
(
'db'
);
$title
=
$filterPost
->
noTags
(
'title'
);
$content
=
$filterPost
->
noTags
(
'content'
);
$db
->
addNews
(
$title
,
$content
);
$this
->
_redirect
(
'/'
);
}
function
__call
(
$action
,
$arguments
)
{
$this
->
_redirect
(
'/'
);
}
}
?>
Because the user is redirected after submitting a form, no view is necessary in this controller.
In
AdminController.php
, you handle two actions, displaying the admin interface and approving news:
<?php
class
AdminController
extends
Zend_Controller_Action
{
function
indexAction
()
{
/* Display admin interface. */
$db
=
Zend
::
registry
(
'db'
);
$view
=
Zend
::
registry
(
'view'
);
$view
->
news
=
$db
->
getNews
(
'NEW'
);
echo
$view
->
render
(
'admin.php'
);
}
function
approveAction
()
{
/* Approve news. */
$filterPost
= new
Zend_InputFilter
(
$_POST
);
$db
=
Zend
::
registry
(
'db'
);
if (
$filterPost
->
getRaw
(
'password'
) ==
'mypass'
) {
$db
->
approveNews
(
$filterPost
->
getRaw
(
'ids'
));
$this
->
_redirect
(
'/'
);
} else {
echo
'The password is incorrect.'
;
}
}
function
__call
(
$action
,
$arguments
)
{
$this
->
_redirect
(
'/'
);
}
}
?>
Finally,
ViewController.php
:
<?php
class
ViewController
extends
Zend_Controller_Action
{
function
indexAction
()
{
$this
->
_redirect
(
'/'
);
}
function
__call
(
$id
,
$arguments
)
{
/* Display news and comments for $id. */
$id
=
Zend_Filter
::
getDigits
(
$id
);
$db
=
Zend
::
registry
(
'db'
);
$view
=
Zend
::
registry
(
'view'
);
$view
->
news
=
$db
->
getNews
(
$id
);
$view
->
comments
=
$db
->
getComments
(
$id
);
$view
->
id
=
$id
;
echo
$view
->
render
(
'view.php'
);
}
}
?>
This provides a fully-functional, albeit very simplistic, application for sharing news and posting comments. The best part is that adding more features is easy due to the elegant design, and as the Zend Framework continues to mature, things should only get better.
More Information
This tutorial barely scratches the surface, but there are already a few additional resources available. In addition to the manual at http://framework.zend.com/manual/, Rob Allen has provided some details about his experiences with the Zend Framework at http://akrabat.com/zend-framework/, and Richard Thomas has provided some useful notes at http://www.cyberlot.net/zendframenotes. If you have some commentary of your own, please visit the new Zend Framework forum at http://www.phparch.com/discuss/index.php/f/289//.
Closing Note
It's easy to judge a preview release harshly, and I encountered a few frustrations of my own while writing this tutorial. Overall, I think the Zend Framework shows a lot of promise, and everyone involved is working hard to continue to improve it.
Note:
Comments? Thoughts? Questions? Check out our new Zend Framework forum at http://www.phparch.com/discuss/index.php/f/289//.
About the author—
Chris Shiflett is the principal of Brain Bulb, a consulting firm that specializes in PHP development and security. Chris' blog is at http://shiflett.org/.