Tutorial From Rob Allen's DevNotes
Application specific code
Before we set up our files, itʼs important to understand how Zend Framework expects the pages to be
organized.
Each page of the application is known as an action and actions are grouped into controllers.
For a URL of the format http://localhost/public/zf-tutorial/news/view, the controller is News and the action is view. This is to allow for grouping of related actions. For instance, a News controller might have actions of list, archived and view. Zend Frameworkʼs MVC system also supports modules for grouping controllers together, but this application isnʼt big enough to worry about them!
By default, Zend Frameworkʼs controller reserves a special action called index as a default action. This is for cases like http://localhost/zf-tutorial/public/news/ where the index action within the News controller will be executed. There is also a default controller name, which is also called index and so the URL http://localhost/zf-tutorial/public/ will cause the index action in the Index controller to be executed.
As this is a simple tutorial, we are not going to be bothered with “complicated” things like logging in! That can wait for a separate tutorial (or you can read about it in Zend Framework in Action!)
As we have four pages that all apply to albums, we will group them in a single controller as four actions. We shall use the default controller and the four actions will be:
Page Controller Action
Home page Index index
Add new album Index add
Edit album Index edit
Delete album Index delete
As a site gets more complicated, additional controllers are needed and you can even group controllers into modules if needed.
Setting up the Controller
We are now ready to set up our controller. In Zend Framework, the controller is a class that must be called
{Controller name}Controller. Note that {Controller name} must start with a capital letter. This class must be within a file called {Controller name}Controller.php within the application/controllers directory.
Each action is a public function within the controller class that must be named {action name}Action. In this case {action name} starts with a lower case letter and again must be completely lowercase.
Mixed case controller and action names are allowed, but have special rules that you must understand before you use them. Check the documentation first!
Our controller class is called IndexController which is defined in application/controllers/
IndexController.php and has been automatically created for us by Zend_Tool. It also contains the first action method, indexAction(). We just need to add our additional actions.
Adding additional controller actions is done using the zf command line toolʼs create action command.
Open up Terminal or Command Prompt and change directory to your zf-tutorial/ directory. Then typethese three commands:
zf create action add Index
zf create action edit Index
zf create action delete Index
These commands create three new methods: addAction, editAction and deleteAction in
IndexController and also create the appropriate view script files that weʼll need later. We now have all four actions that we want to use.
The URLs for each action are:
URL Action method
http://localhost/zf-tutorial/public/ IndexController::indexAction()
http://localhost/zf-tutorial/public/index/add IndexController::addAction()
http://localhost/zf-tutorial/public/index/edit IndexController::editAction()
http://localhost/zf-tutorial/public/index/delete IndexController::deleteAction()
You can test the three new actions and should see a message like this:
View script for controller index and script/action name add
Note: If you get a 404 error, then you have not configured Apache with the mod_rewrite module or have not
set up the AllowOverride correctly in your Apache config files so that the .htaccess file in the public/
folder is actually used.
The database
Now that we have the skeleton application with controller action functions and view files ready, it is time to
look at the model section of our application. Remember that the model is the part that deals with the
applicationʼs core purpose (the so-called “business rules”) and, in our case, deals with the database. We will make use of Zend Framework class Zend_Db_Table which is used to find, insert, update and delete rows from a database table.
Database configuration
To use Zend_Db_Table, we need to tell it which database to use along with a user name and password. As we would prefer not to hard-code this information into our application we will use a configuration file to hold this information. The Zend_Application component is shipped with a database configuration resource, so all we need to do is set up the appropriate information in the configs/application.ini file and it will do the rest.
Open application/configs/application.ini and add the following to the end of the
[production] section (i.e. above the [staging] section):
resources.db.adapter = PDO_MYSQL
resources.db.params.host = localhost
resources.db.params.username = rob
resources.db.params.password = 123456
resources.db.params.dbname = zf-tutorial
Obviously you should use your user name, password and database name, not mine! The database
connection will now be made for us automatically and Zend_Db_Tableʼs default adapter will be set. You can read about the other available resource plugins
here: http://framework.zend.com/manual/en/zend.application.available-resources.html.
Create the database table
As noted in the initial planning, we are going to be using a database to store our album data. Iʼm going to be using MySQL and so the SQL statement to create the table is:
CREATE TABLE albums (
id int(11) NOT NULL auto_increment,
artist varchar(100) NOT NULL,
title varchar(100) NOT NULL,
PRIMARY KEY (id)
);
Run this statement in a MySQL client such as phpMyAdmin or the standard MySQL command-line client.
Insert test data
We will also insert some rows into the table so that we can see the retrieval functionality of the home page.
Iʼm going to take the first few “Bestsellers” CDs from Amazon UK. Run the following statement in your
MySQL client:
INSERT INTO albums (artist, title)
VALUES
('Paolo Nutine', 'Sunny Side Up'),
('Florence + The Machine', 'Lungs'),
('Massive Attack', 'Heligoland'),
('Andre Rieu', 'Forever Vienna'),
('Sade', 'Soldier of Love');
We now have some data in a database and can write a very simple model for it
The Model
Zend Framework does not provide a Zend_Model class as the model is your business logic and itʼs up to you to decide how you want it to work. There are many components that you can use for this depending on your needs. One approach is to have model classes that represent each entity in your application and then use mapper objects that load and save entities to the database. This approach is documented in the Zend Framework QuickStart here:
http://framework.zend.com/manual/en/learning.quickstart.create-model.html.
For this tutorial, we are going to create a model that extends Zend_Db_Table and uses
Zend_Db_Table_Row. Zend Framework provides Zend_Db_Table which implements the Table Data
Gateway design pattern to allow for interfacing with data in a database table. Be aware though that the Table Data Gateway pattern can become limited in larger systems. There is also a temptation to put database access code into controller action methods as these are exposed by Zend_Db_Table.
Zend_Db_Table_Abstract is an abstract class, from which we derive our class that is specific to
managing albums. It doesnʼt matter what we call our class, but it makes sense to call it after the database
table. Our project has a default autoloader instantiated by Zend_Application which maps the resource classes within under a module to the directory where it is defined.
For the main application/ folders we use the prefix Application_.
The autoloader maps resources to directories using this mapping:
Prefix Directory
Form forms
Model models
Model_DbTable models/DbTable
Model_Mapper models/mappers
Plugin plugins
Service services
View_Filter views/filters
View_Helper views/helpers
As we are naming after the database table, albums and will use Zend_Db_Table our class will be called
Application_Model_DbTable_Albums which will be stored in applications/models/DbTable/
Albums.php.
To tell Zend_Db_Table the name of the table that it will manage, we have to set the protected property
$_name to the name of the table. Also, Zend_Db_Table assumes that your table has a primary key called id which is auto-incremented by the database. The name of this field can be changed too if required.
We can use the zf command line tool to do some of the work, so run the following command from the
command line:
zf create db-table Albums albums
The command line tool has now created the file Albums.php in the application/models/DbTable
folder. Inside this file is a class called Application_Model_DbTable_Albums within which is set the
name of the database table that this class communicates with.
We now need to add some functionality so edit application/models/DbTable/Albums.php and add the
methods getAlbum(), addAlbum(), updateAlbum() and deleteAlbum() and so that it now looks like this:
zf-tutorial/application/models/DbTable/Albums.php
<?php
class Application_Model_DbTable_Albums extends Zend_Db_Table_Abstract
{
protected $_name = 'albums';
public function getAlbum($id)
{
$id = (int)$id;
$row = $this->fetchRow('id = ' . $id);
if (!$row)
{
throw new Exception("Could not find row $id");
}
return $row->toArray();
}
public function addAlbum($artist, $title)
{
$data = array
(
'artist' => $artist,
'title' => $title,
);
$this->insert($data);
}
public function updateAlbum($id, $artist, $title)
{
$data = array
(
'artist' => $artist,
'title' => $title,
);
$this->update($data, 'id = '. (int)$id);
}
public function deleteAlbum($id)
{
$this->delete('id =' . (int)$id);
}
}
We create four helper methods that our application will use to interface to the database table. getAlbum()retrieves a single row as an array, addAlbum() creates a new row in the database, updateAlbum()updates an album row and deleteAlbum() removes the row completely. The code for each of these methods is self-explanatory. Whilst not needed in this tutorial, you can also tell Zend_Db_Table about related tables and it can fetch related data too.
We need to fill in the controllers with data from the model and get the view scripts to display it, however,
before we can do that, we need to understand how Zend Frameworkʼs view system works.
Layouts and views
Zend Frameworkʼs view component is called, somewhat unsurprisingly, Zend_View. The view component will allow us to separate the code that displays the page from the code in the action functions.
The basic usage of Zend_View is:
$view = new Zend_View();
$view->setScriptPath('/path/to/scripts');
echo $view->render('script.php');
It can very easily be seen that if we were to put this code directly into each of our action functions we will be repeating very boring “structural” code that is of no interest to the action. We would rather do the initialization of the view somewhere else and then access our already initialised view object within each action function.
Zend Framework provides an Action Helper for us called the ViewRenderer. This takes care of initialising a view property in the controller($this->view) for us to use and will also render a view script after the action has been dispatched.
For the rendering, the ViewRenderer sets up the Zend_View object to look in views/scripts/{controller
name} for the view scripts to be rendered and will (by default, at least) render the script that is named after the action with the extension phtml.
That is, the view script rendered is views/scripts/{controller name}/{action_name}.phtml and the rendered contents are appended to the Response objectʼs body.
The Response object is used to collate together all HTTP headers, body content and exceptions generated as a result of using the MVC system. The front controller then automatically sends the headers followed by the body content at the end of the dispatch.
This is all set up for us by Zend_Tool when we create the project and add controllers and actions using the
zf create controller and zf create action commands.
Common HTML code: Layouts
It also very quickly becomes obvious that there will be a lot of common HTML code in our views for the
header and footer sections at least and maybe a side bar or two also. This is a very common problem and
the Zend_Layout component is designed to solve this problem. Zend_Layout allows us to move all the common header, footer and other code to a layout view script which then includes the specific view code for the action being executed.
The default place to keep our layouts is application/layouts/ and there is a resource available for
Zend_Application that will configure Zend_Layout for us. We use Zend_Tool to create the layout
view script file and update application.ini appropriately. Again, from Terminal or the Command Prompt, type the following in your zf-tutorial directory.
zf enable layout
Zend_Tool has now created the folder application/layouts/scripts and placed a view script called layout.phtml into it. It has also updated application.ini and added the line
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/" to the
[production] section.
At the end of the dispatch cycle, after the controller action methods have finished, Zend_Layout will render our layout. Zend_Tool provides a very basic layout file that just displays the content of the actionʼs view script. We will augment this with the HTML required for this website. Open layouts.phtml and replace the code in there with this:
zf-tutorial/application/layouts/scripts/layout.phtml
<?php
$this->headMeta()->appendHttpEquiv('Content-Type', 'text/html;charset=utf-8');
$this->headTitle()->setSeparator(' - ');
$this->headTitle('Zend Framework Tutorial');
echo $this->doctype();
?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<?php echo $this->headMeta(); ?>
<?php echo $this->headTitle(); ?>
</head>
<body>
<div id="content">
<h1><?php echo $this->escape($this->title); ?></h1>
<?php echo $this->layout()->content; ?>
</div>
</body>
</html>
The layout file contains the “outer” HTML code which is all pretty standard. As it is a normal PHP file, we can use PHP within it, There is a variable, $this, available which is an instance of the view object that was created during bootstrapping. We can use this to retrieve data that has been assigned to the view and also to call methods. The methods (known as view helpers) return a string that we can then echo.
Firstly we configure some view helpers for the head section of the web page and then echo out the correct doctype. Within the <body>, we create a div with an <h1> containing the title.
To get the view script for the current action to display, we echo out the content placeholder using the layout() view helper: echo $this->layout()->content; which does the work for us. This means that the view scripts for the action are run before the layout view script.
We need to set the doctype for the webpage before we render any view scripts. As the action view scripts
are rendered earlier and may need to know which doctype is in force. This is especially true for Zend_Form.
To set the doctype we add another line to our application.ini, in the [production] section:
resources.view.doctype = "XHTML1_STRICT"
The doctype() view helper will now output the correct doctype and components like Zend_Form will
generate compatible HTML.
Styling
Even though this is “just” a tutorial, weʼll need a CSS file to make our application look a little bit presentable! This causes a minor problem in that we donʼt actually know how to reference the CSS file because the URL doesnʼt point to the correct root directory. Fortunately, a view helper called baseUrl() is available. This helper collects the information we require from the request object and provides us with the bit of the URL that we donʼt know.
We can now add the CSS file to the <head> section of the application/layouts/layout.phtml file and again we use a view helper, headLink():
zf-tutorial/application/layouts/layout.phtml
...
<head>
<?php echo $this->headMeta(); ?>
<?php echo $this->headTitle(); ?>
<?php echo $this->headLink()->prependStylesheet($this->baseUrl().'/css/site.css'); ?>
</head>
...
By using headLink()ʼs prependStylesheet() method, we allow for additional, more specific, CSS files to be added within the controller view scripts which will be rendered within the <head> section after
site.css. Finally, we need some CSS styles, so create a css directory within public/ and add site.css with this code:
zf-tutorial/public/css/site.css
body,html {
margin: 0 5px;
font-family: Verdana,sans-serif;
}
h1
{
font-size: 1.4em;
color: #008000;
}
a
{
color: #008000;
}
/* Table */
th{
text-align: left;
}
td, th {
padding-right: 5px;
}
Page 11 of 18
/* style form */
form dt {
width: 100px;
display: block;
float: left;
clear: left;
}
form dd {
margin-left: 0;
float: left;
}
form #submitbutton {
margin-left: 100px;
}
This should make it look slightly prettier, but as you can tell, Iʼm not a designer!
We can now clear out the four action scripts that were auto generated for us ready for filling up, so go ahead and empty the index.phtml, add.phtml, edit.phtml and delete.phtml files which, as youʼll no doubt remember, are in the application/views/scripts/index directory.
Listing albums
Now that we have set up configuration, database information and our view skeletons, we can get onto the
meat of the application and display some albums. This is done in the IndexController class and we start by listing the albums in a table within the indexAction() function:
zf-tutorial/application/controllers/IndexController.php
...
function indexAction()
{
$albums = new Application_Model_DbTable_Albums();
$this->view->albums = $albums->fetchAll();
}
...
We instantiate an instance of our table data gateway based model. The fetchAll() function returns a
Zend_Db_Table_Rowset which will allow us to iterate over the returned rows in the actionʼs view script file. We can now fill in the associated view script, index.phtml:
zf-tutorial/application/views/scripts/index/index.phtml
<?php
$this->title = "My Albums";
$this->headTitle($this->title);
?>
<p>
<a href="<?php echo $this->url(array('controller'=>'index', 'action'=>'add'));?>">Add new album</a>
</p>
<table>
<tr>
<th>Title</th>
<th>Artist</th>
<th> </th>
</tr>
<?php foreach($this->albums as $album) : ?>
<tr>
<td><?php echo $this->escape($album->title);?></td>
<td><?php echo $this->escape($album->artist);?></td>
<td>
<a href="<?php echo $this->url(array('controller'=>'index',
'action'=>'edit', 'id'=>$album->id));?>">Edit</a>
<a href="<?php echo $this->url(array('controller'=>'index',
'action'=>'delete', 'id'=>$album->id));?>">Delete</a>
</td>
</tr>
<?php endforeach; ?>
</table>
The first thing we do is to set the title for the page (used in the layout) and also set the title for the <head>
section using the headTitle() view helper which will display in the browerʼs title bar. We then create a link to add a new album. The url() view helper is provided by the framework and helpfully creates links
including the correct base URL. We simply pass in an array of the parameters we need and it will work out the rest as required.
We then create an html table to display each albumʼs title, artist and provide links to allow for editing and
deleting the record. A standard foreach: loop is used to iterate over the list of albums, and we use the
alternate form using a colon and endforeach; as it is easier to scan than to try and match up braces.
Again, the url() view helper is used to create the edit and delete links.
If you open http://localhost/zf-tutorial/public/ (or wherever you are following along from!) then you should now see a nice list of albums, something like this:
Adding new albums
We can now code up the functionality to add new albums. There are two bits to this part:
• Display a form for user to provide details
• Process the form submission and store to database
We use Zend_Form to do this. The Zend_Form component allows us to create a form and validate the
input. We create a new class Form_Album that extends from Zend_Form to define our form. As this an
application resource, the class is stored in the Album.php file within the forms directory. We start by using the zf command line script to create the correct file:
zf create form Album
This creates the file Album.php in application/forms and includes an init() method where we can set up the form and add the elements that we need. Edit application/forms/Album.php and remove the comment in the init() method and add the following:
zf-tutorial/application/forms/Album.php
<?php
class Application_Form_Album extends Zend_Form
{
public function init()
{
$this->setName('album');
$id = new Zend_Form_Element_Hidden('id');
$id->addFilter('Int');
$artist = new Zend_Form_Element_Text('artist');
$artist->setLabel('Artist')
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator('NotEmpty');
$title = new Zend_Form_Element_Text('title');
$title->setLabel('Title')
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator('NotEmpty');
$submit = new Zend_Form_Element_Submit('submit');
$submit->setAttrib('id', 'submitbutton');
$this->addElements(array($id, $artist, $title, $submit));
}
}
Within the init() method of Application_Form_Album, we create four form elements for the id, artist, title, and submit button. For each item we set various attributes, including the label to be displayed. For the id, we want to ensure that it is only an integer to prevent potential SQL injection issues. The Int filter will do this for us.
For the text elements, we add two filters, StripTags and StringTrim to remove unwanted HTML and
unnecessary white space. We also set them to be required and add a NotEmpty validator to ensure that the user actually enters the information we require. (the NotEmpty validator isnʼt technically required as it will be automatically added by the system as setRequired() has been set to true; it exists here as a
demonstration of how to add a validator.)
We now need to get the form to display and then process it on submission. This is done within the
IndexControllerʼs addAction():
zf-tutorial/application/controllers/IndexController.php
...
function addAction()
{
$form = new Application_Form_Album();
$form->submit->setLabel('Add');
$this->view->form = $form;
if ($this->getRequest()->isPost())
{
$formData = $this->getRequest()->getPost();
if ($form->isValid($formData))
{
$artist = $form->getValue('artist');
$title = $form->getValue('title');
$albums = new Application_Model_DbTable_Albums();
$albums->addAlbum($artist, $title);
$this->_helper->redirector('index');
}
Else
{
$form->populate($formData);
}
}
}
...
Let's examine it in a bit more detail:
$form = new Application_Form_Album();
$form->submit->setLabel('Add');
$this->view->form = $form;
We instantiate our Form_Album, set the label for the submit button to “Add” and then assign to the view for rendering.
if ($this->getRequest()->isPost()) {
$formData = $this->getRequest()->getPost();
if ($form->isValid($formData)) {
If the request objectʼs isPost() method is true, then the form has been submitted and so we retrieve theform data from the request using getPost() and check to see if it is valid using the isValid() member function.
$artist = $form->getValue('artist');
$title = $form->getValue('title');
$albums = new Application_Model_DbTable_Albums();
$albums->addAlbum($artist, $title);
If the form is valid, then we instantiate the Application_Model_DbTable_Albums model class and use addAlbum() method that we created earlier to create a new record in the database.
$this->_helper->redirector('index');
After we have saved the new album row, we redirect using the Redirector action helper to return to the index action (i.e we go back to the home page).
} else {
$form->populate($formData);
}
If the form data is not valid, then we populate the form with the data that the user filled in and redisplay.
We now need to render the form in the add.phtml view script:
zf-tutorial/application/views/scripts/index/add.phtml
<?php
$this->title = "Add new album";
$this->headTitle($this->title);
echo $this->form ;
?>
As you can see, rendering a form is very simple - we just echo it out, as the form knows how to display itself.
You should now be able to use the “Add new album” link on the home page of the application to add a new album record.
Editing an album
Editing an album is almost identical to adding one, so the code is very similar:
zf-tutorial/application/controllers/IndexController.php
...
function editAction()
{
$form = new Application_Form_Album();
$form->submit->setLabel('Save');
$this->view->form = $form;
if ($this->getRequest()->isPost())
{
$formData = $this->getRequest()->getPost();
if ($form->isValid($formData))
{
$id = (int)$form->getValue('id');
$artist = $form->getValue('artist');
$title = $form->getValue('title');
$albums = new Application_Model_DbTable_Albums();
$albums->updateAlbum($id, $artist, $title);
$this->_helper->redirector('index');
}
else
{
$form->populate($formData);
}
}
else
{
$id = $this->_getParam('id', 0);
if ($id > 0)
{
$albums = new Application_Model_DbTable_Albums();
$form->populate($albums->getAlbum($id));
}
}
}
...
Let'Note that this is done if the request is not a POST, as a POST implies we have filled out the form and want to process it. For the initial display of the form, we retrieve the id from request using the _getParam()method. We then use the model to retrieve the database row and populate the form with the row's datadirectly. (Now you know why the getAlbum() method in the model returned an array!)
After validating the form, we need to save the data back to the correct database row. This is done using ourmodel's updateAlbum() method:
$id = $form->getValue('id');
$artist = $form->getValue('artist');
$title = $form->getValue('title');
$albums = new Application_Model_DbTable_Albums();
$albums->updateAlbum($id, $artist, $title);
The view template is the same as add.phtml:
zf-tutorial/application/views/scripts/index/edit.phtml
<?php
$this->title = "Edit album";
$this->headTitle($this->title);
echo $this->form ;
?>
You should now be able to edit albums.
Deleting an album
To round out our application, we need to add deletion. We have a Delete link next to each album on our list page and the naïve approach would be to do a delete when itʼs clicked. This would be wrong. Remembering our HTTP spec, we recall that you shouldnʼt do an irreversible action using GET and should use POST instead.
We shall show a confirmation form when the user clicks delete and if they then click “yes”, we will do the
deletion. As the form is trivial, weʼll code it directly into our view (Zend_Form is, after all, optional!).
Letʼs start with the action code in IndexController::deleteAction():
zf-tutorial/application/controllers/IndexController.php
...
public function deleteAction()
{
if ($this->getRequest()->isPost())
{
$del = $this->getRequest()->getPost('del');
if ($del == 'Yes')
{
$id = $this->getRequest()->getPost('id');
$albums = new Application_Model_DbTable_Albums();
$albums->deleteAlbum($id);
}
$this->_helper->redirector('index');
}
else
{
$id = $this->_getParam('id', 0);
$albums = new Application_Model_DbTable_Albums();
$this->view->album = $albums->getAlbum($id);
}
}
As with add and edit, we use the Requestʼs isPost() method to determine if we should display the
confirmation form or if we should do a deletion. We use the Application_Model_DbTable_Albums
model to actually delete the row using the deleteAlbum() method. If the request is not a POST, then we look for an id parameter and retrieve the correct database record and assign to the view.
The view script is a simple form:
zf-tutorial/application/views/scripts/index/delete.phtml
<?php
$this->title = "Delete album";
$this->headTitle($this->title);
?>
<p>Are you sure that you want to delete
'<?php echo $this->escape($this->album['title']); ?>' by
'<?php echo $this->escape($this->album['artist']); ?>'?
</p>
<form action="<?php echo $this->url(array('action'=>'delete')); ?>" method="post">
<div>
<input type="hidden" name="id" value="<?php echo $this->album['id']; ?>" />
<input type="submit" name="del" value="Yes" />
<input type="submit" name="del" value="No" />
</div>
</form>
In this script, we display a confirmation message to the user and then a form with yes and no buttons. In theaction, we checked specifically for the “Yes” value when doing the deletion.
Thatʼs it - you now have a fully working application.
s look at the differences from adding an album. Firstly, when displaying the form to the user we need to retrieve the albumʼs artist and title from the database and populate the formʼs elements with it. This is at the bottom of the method:
$id = $this->_getParam('id', 0);
if ($id > 0) {
$albums = new Application_Model_DbTable_Albums();
$form->populate($albums->getAlbum($id));
}
watch satellite tv on pc
great blog , how are you doing now eeh?
great tutorial which i was looking for
i have problem when pointing my browser to /controller/action it gave me 404 not found error
may you help me with that error please
thank you in advance
Hi,
thanks for help for sample application. but i need to make sample theme layout in sample application like header, footer, content etc…..
please suggest me some links or ideas to do this.
Any help will be appriciable.
Thanks.
Jinesh
hi,
If you have any ideas or document, please forward it to below id.
[email protected]
Thanks.
Jinesh
Great, thanks, that saved me a fair bit of time. How many years have you spent working with Magento? You so are an internet specialist at it!
Thanks again, Ben.
nice tutorial…………… i learn a lot from this………….. but I m totally new to Zend………..so can u help me to understand how can we handle page redirection???????????
Thanx
Thank you for posting this help….From this post i start interest in Zend…Awesome work…
its very helpful for newcomer :Thanks auther