KEMBAR78
Os PHP Zend Google pt1 PDF | PDF | Xhtml | Html
0% found this document useful (0 votes)
168 views27 pages

Os PHP Zend Google pt1 PDF

In this three-part tutorial series, we will build an application with Zend Framework V1. That uses Google Apps. In Part 1, we explore the various features of the Zend Framework, outlining the many new features in V1. That we will take advantage of to build an example Web site. In Part 2, see how to integrate the various Google applications into our site, including Google Calendar, Google Docs and spreadsheets, Picasa, and YouTube.

Uploaded by

Anders Ruberg
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
168 views27 pages

Os PHP Zend Google pt1 PDF

In this three-part tutorial series, we will build an application with Zend Framework V1. That uses Google Apps. In Part 1, we explore the various features of the Zend Framework, outlining the many new features in V1. That we will take advantage of to build an example Web site. In Part 2, see how to integrate the various Google applications into our site, including Google Calendar, Google Docs and spreadsheets, Picasa, and YouTube.

Uploaded by

Anders Ruberg
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 27

Create a productivity package with the Zend

Framework V1.5 and Google Apps, Part 1: Getting


started with Zend Framework V1.5
New features that make building a Web application easier than
ever

Skill Level: Intermediate

John Mertic (jmertic@gmail.com)


Software Engineer
SugarCRM

24 Jun 2008

Google Apps provides amazing productivity tools. From sharable calendars,


collaborative documents and spreadsheets to even a database, they have reinvented
what one can do in the Web browser. Zend Framework V1.5 provides an API to
connect to these services to extend what these tools offer. In this three-part "Create a
productivity package with the Zend Framework V1.5 and Google Apps" tutorial
series, we will build an application with Zend Framework V1.5 that uses Google
Apps. Here in Part 1, we explore the various features of the Zend Framework,
outlining the many new features in V1.5 that we will take advantage of to build an
example Web site.

Section 1. Before you start


This series is intended for PHP developers looking to take advantage of the many
features of the Zend Framework and integrate with various Google applications.

About this series

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 1 of 27
developerWorks® ibm.com/developerWorks

In this series, we will build an application using new Zend Framework V1.5 features
that make use of some powerful Google applications:

• In Part 1, learn how to create a Web site using the Zend Framework. In
particular, many new features with advanced Web-site layout will be
introduced.
• In Part 2, extend the basic site and add functionality. Learn the many
features of the Zend_Form component, including the new Ajax features.
Also learn about Google Base with the Zend_Gdata component and
integrate it with the site.
• In Part 3, see how to integrate the various Google applications into our
site, including Google Calendar, Google Docs and spreadsheets, Picasa,
and YouTube.

About this tutorial


Zend Framework V1.5 introduced a raft of features for handling layout of Web
pages. In this tutorial, you'll learn how to create a Web site using the Zend
Framework. You'll learn how to take advantage of the additional control V1.5 gives
you over processing layouts, such as two-step processing, in order to create the
different sections of the site with different requirements, while still taking advantage
of the maintainability these features offer. Topics covered:

• Zend Framework primer


• Working with layouts
• Customizing layout processing
• DRY code
• Adding new features and requirements to the site

Prerequisites
PHP programming knowledge is required to follow along, and some experience with
Web application development is preferred, but not necessary.

System requirements
You need these tools to follow along:

Web server

Getting started with Zend Framework V1.5


Page 2 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

Any operating system and any Web server can be used. Feel free to use
Apache V2.X or IBM's HTTP Server. Download from Apache.org or from IBM.

PHP
PHP V5.1.4 or later is required for this tutorial.

Zend Framework
V1.5 can be downloaded from Zend Technologies.

Section 2. Zend Framework primer


Before diving into coding, begin by setting up the base of the Web site. In this
section, you'll see how to properly set up a Zend Framework Web site, from the
directory structure to getting the default files in place. Then you'll take a look at the
base of the Web site and see how to put the pieces into place using the
Zend_Controller and Zend_View components.

Starting a new Web site


The Zend Framework is similar to other frameworks for PHP. It provides many tools
for building a secure, scalable site and a wealth of libraries for interacting with
various databases and Web services. You can pick and choose the components you
wish to use without the excess baggage of using all the bundled components. This is
helpful for those working with legacy sites that want to leverage using the framework
without rewriting major portions of their applications.

When starting a new Web site, the Zend_Controller component is designed to


help us lay out the site using the Model-View-Controller (MVC) design pattern. MVC
is a growing standard in Web development, designed to help you keep code well
organized and easier to maintain. To learn more about the MVC design pattern,
check out the article listed in Resources.

The application code in this tutorial has been separated into its own directory, with
subdirectories for controllers, models, and views, as shown in Listing 1. For this
tutorial, we recommend using the same structure.

Listing 1. File system layout for a Zend Framework site

application/
controllers/
IndexController.php

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 3 of 27
developerWorks® ibm.com/developerWorks

models/
views/
scripts/
index/
index.phtml
helpers/
filters/
layouts/
html/
.htaccess
index.php
library/
Zend/
MySite/

Downloading the example code (see Downloads), will create the structure shown in
Listing 1. The library folder is where we'll add any reusable code the sample
application may use, such as code from a third party. If you followed the System
requirements, you will have the Zend Framework ZIP file handy. Export the
library/Zend folder from the framework ZIP file into the Zend directory from Listing 1.

You will want the document root of your Web site to be the HTML directory in Listing
1. This protects your PHP code from being directly accessible from the outside world
and is good security practice.

If you are using the Apache Web server, edit the .htaccess file shown in Listing 1 to
add the contents of Listing 2.

Listing 2. .htaccess file

RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

If you're using a different Web server, refer to the Zend_Controller_Router


documentation (see Resources) for examples of rewrite rules for other Web servers.

Edit the index.php and add the contents in Listing 3. The file is the bootstrap file,
which handles all incoming requests and directs them to the appropriate controller
and action.

Listing 3. index.php bootstrap file

<?php
require_once 'Zend/Controller/Front.php';
Zend_Controller_Front::run('application/controllers');

You will also need to set up a default controller or IndexController. The default
controller is used when no controller is specified, such as a when a request is being
made to the root of our site (i.e., http://localhost). To handle this, you'll edit the file

Getting started with Zend Framework V1.5


Page 4 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

application/controllers/IndexController.php, as shown below.

Listing 4. IndexController

<?php
/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
}
}

This will create a default controller and action. indexAction() is used to specify
the default action for a controller.

ViewRender
A nice feature of the Zend_Controller component is its integration with the
Zend_View component through the ViewRenderer helper. The Zend_View
component handles rendering the display of our Web site, and the ViewRenderer
helper hooks these two components together. For details on the various components
of the Zend Framework, check out the official Zend Framework manual (see
Resources.

By default, an instance of the Zend_View component is created with every


controller. After the code in the action method is called, the controller will look for a
view file in the application/views/scripts folder under the same directory name as the
controller and a view template with the same name as the action. Every time an
action is called, the view template will be automatically called afterward, unless we
specify otherwise.

For the default controller, it will look for application/views/scripts/index/index.phtml,


so let's add the file with the contents in Listing 5.

Listing 5. index.phtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>My Zend Framework Application</title>
</head>
<body>
<p>Hello world!</p>
</body>
</html>

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 5 of 27
developerWorks® ibm.com/developerWorks

When you view the index.phtml page in your browser, you should see Figure 1.

Figure 1. The main page of our Web site

One other special controller you should add is the error controller. It is called
anytime an error occurs within the framework, such as calling a controller or action
that doesn't exist. Its definition, shown in Listing 6, is a little different from the normal
controller definition and is saved in application/controller/ErrorController.php.

Listing 6. ErrorController

<?php
/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
}
}

You can then create the view template in the file


application/views/scripts/error/error.phtml, which is displayed when an error occurs.

Getting started with Zend Framework V1.5


Page 6 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

Using the Zend_Controller


Now that we have the base of our site set up, we can now begin building upon that
foundation. For this tutorial, we'll be building a simple Web site that will illustrate how
the basic components of the Zend Framework can be used effectively. The
Zend_Controller is designed to use short Search Engine Optimization
(SEO)-friendly URLs. This eliminates "ugly" URLs, such as those with lots of GET
parameters. It also allows you to give context to URLs and make them more
readable. Consider the following URL used to look up parts by number;
http://localhost/partslookup.php?partid=123456.

Now, let's handle this with an SEO-friendly URL. We'll have a controller named parts
that handles all part-related lookups, and we'll be calling the lookup action, which will
handle looking up a part by partid. Here is how that URL would look:
http://localhost/parts/lookup/partid/123456.

So, for Zend Frameworks Web sites using the Zend_Controller, you can use the
following format for URLs: http://localhost/controller/action/param/value/.

This specifies which controller is to be used and in that controller what action is to be
called. If the script has any parameters to it, they are included after the action with
the format of parameter name — forward slash — value. Because of the rewrite rule
we added to our .htaccess file (see Listing 2), all requests are passed the bootstrap
file, which parses the URL to determine which controller and action to call, and
pushes the parameters into the controller object so you can reference them there.

Your first controller


For the first part of the site, you'll be adding a new controller named record. It will
have five actions implementing a Create, Read, Update, Delete (CRUD) interface to
the records, which allows you to handle the various actions against a typical set of
data. The actions will be list, which by default will return a list of records; edit,
which will return one record in an edit mode; create, which will be a form to enter
new records; save, which will handle saving our record; and delete, which will
delete a record. To start off, let's begin by creating the definition for the record
controller in application/controllers/RecordController.php.

Listing 7. RecordController

<?php
/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';
class RecordController extends Zend_Controller_Action
{

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 7 of 27
developerWorks® ibm.com/developerWorks

public function indexAction()


{
$this->_redirect('/record/list');
}

So here we have added the default indexAction() for the controller, which will
redirect the user to the listAction. We are doing this since we want the default
view of the record controller to be a list of records.

Now let's look at the listAction.

Listing 8. RecordController::listAction()

public function listAction()


{
$this->view->records = array(
array("id" => 0, "name" => "record 1", "data" => "data 1"),
array("id" => 1, "name" => "record 2", "data" => "data 2"),
array("id" => 2, "name" => "record 3", "data" => "data 3"),
);
}

For this action, we will return a list of records for the view to render. In Part 2, we
look at retrieving these records from Google Base, but for now, we'll specify a static
list of records in the database in an associative array, similar to how it would be
returned from a database.

We'll also add the editAction, shown in Listing 9, which will get the record
number as a parameter and display an edit form for updating a record. Here again,
we specify the same static listing of records we used for listAction(), but also
use the parameter given to return the item in the array.

Listing 9. RecordController::editAction()

public function editAction()


{
$records = array(
array("id" => 0, "name" => "record 1", "data" => "data 1"),
array("id" => 1, "name" => "record 2", "data" => "data 2"),
array("id" => 2, "name" => "record 3", "data" => "data 3"),
);
$id = $this->_getParam('print','0');
$this->view->id = $id;
$this->view->record = $records[$id];
}

We have introduced how to retrieve a parameter passed to a form, using the


_getParam() method. You'll also notice a second parameter to the method. This
allows you to set a default value to the parameter in case it is not specified in the
URL.

Getting started with Zend Framework V1.5


Page 8 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

The createAction is similar to the editAction in Listing 10, except no data will
be filled in the return form. We can reuse the view, however, since the display logic
is identical.

Listing 10. RecordController::createAction()

public function createAction()


{
$this->view->id = '-1';
$this->view->record = array("name"=>'',"data=>'');
$this->render('edit');
}

We'll also add stubs for the other two actions: delete and save, in Listing 11. In
both cases, these will execute the delete or save code, respectively, then back to
the list view. In Part 2, we add the integration to Google Base here, but for now, we'll
have it output a message to the browser, acting like it did the save or delete we
asked for.

Listing 11. RecordController::saveAction() and


RecordController::deleteAction()

public function saveAction()


{
/* here we will save the record */
$this->_redirect('/record/list/');
}
public function deleteAction()
{
/* here we will delete the record */
$this->_redirect('/record/list/');
}
}

Adding views
Now let's add the view templates. They will be located in the directory
application/views/scripts/record/, and we will have two: list.phtml and edit.phtml.
They are standard HTML files like the index.phtml file created above. In Listing 12,
you'll see the first one, list.phtml, and it will have a list of records with the option to
edit or delete each one.

Listing 12. list.phtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Record Listing</title>

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 9 of 27
developerWorks® ibm.com/developerWorks

</head>
<body>
<p><a href="/">Home</a> |
<a href="/record">Record</a></p>
<p>List of records</p>
<ul>
<?php foreach ( $records as $id => $record ): ?>
<li>
<strong><?php echo $this->escape($record['name']);
?></strong>
&nbsp;-&nbsp;<?php echo $this->escape($record['data']); ?>
&nbsp;<a href="/record/edit/<?php echo $this->escape($record['id']);
?>">Edit</a>
&nbsp;<a href="/record/delete/<?php echo $this->escape($record['id']);
?>">Delete</a>
</li>
<?php endforeach; ?>
</ul>
</body>
</html>

Figure 2. Record list view

You will notice the use of a view helper, the escape() method. This will escape the
variable output displayed to help avoid security issues that can arise, such as
cross-site scripting attacks. We will look more into other view helpers later.

The edit view in Listing 13 is your standard HTML form, which will submit to the

Getting started with Zend Framework V1.5


Page 10 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

save action of the record controller.

Listing 13. edit.phtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Record Edit</title>
</head>
<body>
<p><a href="/">Home</a> |
<a href="/record">Record</a></p>
<form action="/record/save/id/<?php echo
$this->escape($this->record['id']); ?>" method="post">
<p>Name: <input name="name" value="<?php echo
$this->escape($this->record['name']); ?>"
type="text" size="20" /></p>
<p>Data: <input name="data" value="<?php echo
$this->escape($this->record['data']); ?>" type="text" size="20" /></p>
<p><input name="save" value="Save" type="submit" /></p>
</form>
</body>
</html>

If all is in order, your form should look like Figure 3.

Figure 3. Record Edit view

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 11 of 27
developerWorks® ibm.com/developerWorks

We have created a basic CRUD interface to our data. Now let's look into how to use
some of the advanced features of the Zend Framework to help optimize our site
design.

Section 3. Working with layouts


Now that we have a working Web site, let's look at optimizing it. In this section, we'll
use a new component, Zend_Layout, which we can use to eliminate much of the
duplicated code in our views. In addition, we'll see how easy it is to transform our
site depending upon the needs of the site, such as if we want make our pages
printer-friendly.

The Zend_Layout component


One of the biggest changes to V1.5 of the Zend Framework came with the addition
of Zend_Layout. This makes it much easier to define the layout of complex Web

Getting started with Zend Framework V1.5


Page 12 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

sites, where you may have several items consistent across many pages, such as a
navigation menu or a page header and footer. The addition of this component is
helpful for UI designers, so they can help enforce a layout without touching each
individual view template to include the additional common code, as was needed in
previous versions of the framework. It also removes the necessity of your views to
be so aware of the environment around them, and this will aid in code reuse, as
you'll see.

First, we need to update our bootstrap file to call the Zend_Layout component, as
shown in Listing 14. We will specify the path to where the layouts are stored — in
our case, application/layouts.

Listing 14. index.php bootstrap file, updated to load the Zend_Layout


component

<?php
require_once 'Zend/Controller/Front.php';
Zend_Layout::startMvc(array(
'layoutPath' => 'application/layouts'
));
Zend_Controller_Front::run('application/controllers');

Now let's define the default layout for our site. We'll extract the general template of
our site out of the view template files from before and create a file called
application/layouts/layout.phtml with those contents, as shown in Listing 15. We'll
add a call to the layout()->content property, which will hold the content from
the view being rendered.

Listing 15. layout.phtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title><?php echo $this->headTitle('My Site - '); ?></title>
</head>
<body>
<p><a href="/">Home</a> |
<a href="/record">Record</a></p>
<?php echo $this->layout()->content; ?>
</body>
</html>

The index file becomes much simpler now, as you can see in Listing 16. We will only
have the content of the index page in this file. We'll also append the title of this page
to the title in our layout using the $this->headTitle()->append() method.

Listing 16. index/index.phtml updated to remove the layout components


moved to layout.phtml

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 13 of 27
developerWorks® ibm.com/developerWorks

<?php $this->headTitle()->append('My Zend Framework Application'); ?>


<p>Hello world!</p>

This is the same for the list view, as shown in Listing 17. Again we'll use the
$this->headTitle->append() method to set the title for this page.

Listing 17. record/list.phtml updated to remove the layout components moved


to layout.phtml

<?php $this->headTitle()->append('Record List'); ?>


<p>List of records</p>
<ul>
<?php foreach ( $records as $record ): ?>
<li>
<strong><?php echo $this->escape($record['name']); ?></strong>
&nbsp;-&nbsp;<?php echo $this->escape($record['data']); ?>
&nbsp;<a href="/record/edit/<?php echo $this->escape($record['id']);
?>">Edit</a>
&nbsp;<a href="/record/delete/<?php echo $this->escape($record['id']);
?>">Delete</a>
</li>
<?php endforeach; ?>
</ul>

And we'll update the edit view in the same way.

Listing 18. record/edit.phtml

<?php $this->headTitle()->append('Record Edit'); ?>


<form action="/record/save/id/<?php echo $this->escape($this->record['id']);
?>" method="post">
<p>Name: <input name="name" value="<?php echo
$this->escape($this->record['name']); ?>" type="text" size="20" /></p>
<p>Data: <input name="data" value="<?php echo
$this->escape($this->record['data']); ?>" type="text" size="20" /></p>
<p><input name="save" value="Save" type="submit" /></p>
</form>

Using this technique has removed lots of duplicate code from the individual view
templates. You'll also notice the introduction of another view helper: headTitle().
We can use this to set the page title for this view, without having to push an extra
variable out to the layout file to handle this. It also allows us to have a base site
name (for our site, we set it as My Site), then append the page-specific title to that.
This a handy feature to help us keep the page title consistent across our entire site.

Multiple layouts
We can also have multiple layouts for a site. For example, many sites offer a print
version of a particular page without many of the graphical elements of the normal
page. While this can be achieved using print stylesheets, it can be ineffective in

Getting started with Zend Framework V1.5


Page 14 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

reducing your total page payload if you have to hide many elements in the page for
the print view. Instead, let's create a different layout file. We will call it print.phtml, as
you can see in Listing 19. In this layout, we'll remove the navigational menu from the
top of page since we don't want it to appear on a printout of the page.

Listing 19. print.phtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<?php echo $this->headTitle('My Site - '); ?>
</head>
<body>
<?php echo $this->layout()->content; ?>
</body>
</html>

Switching layouts from the default is as simple as calling the setLayout() method
of the layout object in the controller, as you can see in Listing 20. You'll notice some
new concepts here. The method init() is called before any action is called, which
is useful to handle logic that applies to all actions in a controller. We need to make
sure we call the parent::init() method before we add our own code here, so
the view and layout helpers are initialized properly. We'll leverage the print
parameter, which we'll set to 1 when we want to use the print layout template.

Listing 20. RecordController update with option to switch layouts in the


controller

<?php
/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';
class RecordController extends Zend_Controller_Action
{
public function init()
{
parent::init();
if ( $this->_getParam('print', '0') == '1' )
$this->_helper->layout->setLayout('print');
}

So now, calling http://localhost/record/list/print/1 will load the action with the


print.phtml layout file.

Disable using layout processing


We can also disable using the layout template altogether. This comes in handy in
Part 2, where we make Ajax calls and return HTML snippets or JSON strings, and
don't want the full page layout returned. To do this, call

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 15 of 27
developerWorks® ibm.com/developerWorks

$this->_helper->layout->disableLayout() within the controller or action


you wish to do this on.

Section 4. Customizing layout processing


Now that we have begun to explore what the Zend_Layout component can do, let's
take it a step further to help optimize our site. We'll look at splitting out the rendering
of our navigation menu into its own controller, then integrate it into the layout we
made in the previous section.

Optimizing the navigation menu


We can take layout processing a step further by using the ActionStack helper,
another new feature in Zend Framework V1.5. Using ActionStack enables us to
chain a series of actions together in one action, which allows us to further break
apart long, monolithic action code into smaller sections of code that can be more
easily reused within your application. The other big thing we can achieve with this
approach is the ability to render the contents of a view to different layout variables,
giving us the ability to widget-ize out different sections of our layout to be handled
with different controllers and actions.

Let's start by looking at our navigation menu. Typically, a navigation menu may have
several menu options within it, such as a primary menu of main options and a
secondary menu of suboptions that depends upon the selected option in the primary
method. For this example, we will define a new controller MenuController, which
will have a separate action for each secondary menu we might have underneath the
primary menu. Let's look at how to build this.

Listing 21. MenuController

/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';
class MenuController extends Zend_Controller_Action
{
public function init()
{
parent::init();
$this->view->controller = $this->_getParam('controller','home');
$this->_helper->viewRenderer->setResponseSegment('nav');
}
public function indexAction()
{
$this->_redirect('/menu/home');

Getting started with Zend Framework V1.5


Page 16 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

So the base of our controller looks similar to the other controllers we've built. We use
the init() method again to direct the content of our actions to go to the the $nav
layout variable. We'll also grab the action name to pass to the view so we know
which menu option is selected in the main menu. We also define the
indexAction(), which will just render the menu on the home page.

Next, let's define the main menu, as shown in Listing 22. We won't call this menu
directly, but use the other view helper to call in the view template. A parameter
passed to the action named selectedItem will specify which menu item is
selected.

Listing 22. MenuController main menu actions

public function mainAction()


{
$this->view->menuItems = array(
array('name' => 'Home', 'controller' => ''),
array('name' => 'Record', 'controller' => 'record'),
);
$this->selectedItem = $this->getParam('selectedItem','');
}

The secondary menu's work will be directly called by the originating action, as you
can see in Listing 23. For this, we'll have two types of menus: one that renders a
main menu and a submenu, and one that will only render the main menu.

Listing 23. MenuController secondary menu actions

public function homeAction()


{
$this->render('nomenu');
}
public function recordAction()
{
$this->view->menuItems = array(
array('name' => 'List', 'action' => 'list'),
array('name' => 'New', 'action' => 'create'),
);
$this->render('submenu');
}

Now that we have the different menus and their options defined, let's take a look at
the view templates. In the submenu and nomenu view templates, we'll be calling the
main menu action above using an action view helper. Action view helpers allow you
to call a controller to output its contents directly inside a view, which is helpful for
reusable content like the main menu, which gets included with every type of menu.

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 17 of 27
developerWorks® ibm.com/developerWorks

Building templates for the menu


Let's look at the definition for the main menu. We'll use the $menuItems array to
give us a list of menu items and the $selectedItem variable to specify which item
is the currently selected one, which we'll make bold.

Listing 24. Main menu view template


(application/views/scripts/menu/menu.phtml)

<p>
<?php foreach ( $this->menuItems as $menuItem ): ?>
<?php if ( $this->selectedItem == $menuItem['controller'] ): ?>
<strong>
<?php endif; ?>
<a href="/<?php echo $this->escape($menuItem['controller']); ?>">
<?php echo $this->escape($menuItem['name']); ?>
</a>&nbsp;
<?php if ( $this->selectedItem == $menuItem['controller'] ): ?>
</strong>
<?php endif; ?>
<?php endforeach; ?>
</p>

Now in the secondary menu, we'll do something similar. Here, we have the addition
of the $controller view variable, which we'll pass to the main menu as the
selected item so we can highlight the item selected there. You'll also see how we
use the action helper to grab the main menu view template and interject it into this
view.

Listing 25. Secondary menu view template


(application/views/scripts/menu/submenu.phtml)

<?php echo $this->action('menu', 'main', null, array('selectedItem'


=> $this->controller)); ?>
<p style="font-size: smaller;">
<?php foreach ( $this->menuItems as $menuItem ): ?>
<a href="/<?php echo $this->escape($this->controller); ?>/
<?php echo $this->escape($menuItem['action']); ?>">
<?php echo $this->escape($menuItem['name']); ?>
</a>&nbsp;
<?php endforeach; ?>
</p>

And the nomenu template simplifies down to a call to the main menu only.

Listing 26. Template for when we don't have a secondary menu


(application/views/scripts/menu/nomenu.phtml)

<?php $this->action('menu', 'main', null, array('selectedItem'


=> $this->controller)); ?>

Getting started with Zend Framework V1.5


Page 18 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

Pulling it together in the layout template


Finally, we'll update our layout template in the same way. For this, we could use the
same technique we used in the submenu template by calling an action directly in the
view template. However, since we've already defined a different layout variable for
the content, let's leverage this. First, we need to modify the controller to call the
navigation menu. We'll use the ActionStack helper here, which allows us to call a
series of other actions we'll render after the current action is handled. To apply it to
all items in the controller, put it in the init() method in the RecordController.

Listing 27. RecordController update that calls navigation menu controller

<?php
/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';
class RecordController extends Zend_Controller_Action
{
public function init()
{
parent::init();
if ( $this->_getParam('print', '0') == '1' )
$this->_helper->layout->setLayout('print');
$this->_helper->actionStack($this->_getParam('controller','home'), 'menu');
}
}

The init() method in the IndexController will also be updated in the same
way.

Listing 28. IndexController updated with an init() method to call the navigation
menu controller

<?php
/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';
class IndexController extends Zend_Controller_Action
{
public function init()
{
parent::init();
if ( $this->_getParam('print', '0') == '1' )
$this->_helper->layout->setLayout('print');
$this->_helper->actionStack($this->_getParam('controller','home'), 'menu');
}

Now we'll update the layout file in Listing 29. We'll call the nav member of the layout
helper, which is where we directed the output of our menu views.

Listing 29. layout.phtml with updated call to nav layout variable

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 19 of 27
developerWorks® ibm.com/developerWorks

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<?php echo $this->headTitle('My Site - '); ?>
</head>
<body>
<?php echo $this->layout()->nav; ?>
<?php echo $this->layout()->content; ?>
</body>
</html>

Section 5. DRY code


The whole point of the many enhancements made to the Zend Framework V1.5 is to
make it easier to stick to the Don't Repeat Yourself (DRY) principle. During initial
development, it's often easiest to do the easiest thing that works, but as an
application grows, duplicated code make maintenance a nightmare. Let's look at a
few areas in our sample application and see where we can apply this principle, and
what the Zend Framework provides us to help our efforts.

View helpers
View helpers give us tools to produce common code patterns without much effort.
Just as we used the headTitle() action helper to produce the title tags, we can
also use the docType() helpers to write out the HTML code for us.

Listing 30. layout.phtml using headTitle() and docType() helpers

<?php echo $this->docType('XHTML1_STRICT'); ?>


<html>
<head>
<?php echo $this->headTitle('Record Listing'); ?>
</head>
<body>
<?php echo $this->layout()->nav; ?>
<?php echo $this->layout()->content; ?>
</body>
</html>

In addition, there are headLink(), headMeta(), headScript(), and


headStyle() helpers to build many of the other common head tags we may use.
This works similar to the headTitle() helper, which allows us to define a list of
default items and have the various view templates add to them as required by the
view template. These tags allow us to add granularity to our include stylesheets and

Getting started with Zend Framework V1.5


Page 20 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

JavaScript, and only include code the current page will need.

Partial helpers
Now let's take a look at the record listing. Here, we iterate over the record listing
using a for loop. With the Partial helper, we can split small sections of the logic
off into a template so we can reuse it. Furthermore, the PartialLoop helper allows
us to render this partial template in a loop over an array of variables. So let's take
the section of the list.phtml view and split it out into its own template and put it in the
application/views/helpers/recordlistitem.phtml file.

Listing 31. recordlistitem.phtml

<li>
<strong><?php echo $this->escape($this->name); ?></strong>
&nbsp;-&nbsp;<?php echo $this->escape($this->data); ?>
&nbsp;<a href="/record/edit/<?php echo $this->escape($this->id);
?>">Edit</a>
&nbsp;<a href="/record/delete/<?php echo $this->escape($this->id);
?>">Delete</a>
</li>

And now we'll update the list.phtml file.

Listing 32. list.phtml updated to remove layout components moved to


layout.phtml

<p>List of records</p>
<ul>
<?php echo $this->partialLoop('recordlistitem.phtml', $records); ?>
</ul>

We can also do something similar with the menu code, as you can see in Listing 33.
This will give us greater reuse because of the similarities between the menu code.
We'll save this as application/views/helpers/menuitem.phtml.

Listing 33. menuitem.phtml

<a href="<?php echo $this->url; ?>">


<?php echo $this->escape($this->name); ?>
</a>

Now we'll call the Partial helper to call the helper view we created in Listing 33 in the
main menu.

Listing 34. Main menu view template


(application/views/scripts/menu/menu.phtml)

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 21 of 27
developerWorks® ibm.com/developerWorks

<p>
<?php foreach ( $this->menuItems as $menuItem ): ?>
<?php if ( $this->selectedItem == $menuItem['controller'] ): ?>
<strong>
<?php endif; ?>
<?php echo $this->partial('menuitem.phtml',array(
'url' => '/'.$this->escape($menuItem['controller']),
'name' => $menuItem['name'])); ?>
<?php if ( $this->selectedItem == $menuItem['controller'] ): ?>
</strong>
<?php endif; ?>
<?php endforeach; ?>
</p>
Now, in listing 35, we use the partial helper to render the secondary menu.
Listing 35. Secondary menu view template ( application/views/scripts/menu/submenu.phtml )
<?php $this->action('menu', 'main', null, array('selectedItem' => $this->controller)); ?>
<p style="font-size: smaller;">
<?php foreach ( $this->menuItems as $menuItem ): ?>
<?php echo $this->partial('menuitem.phtml',array(
'url' =>
'/'.$this->escape($this->controller).'/'.$this->escape($menuItem['controller']),
'name' => $menuItem['name'])); ?>
<?php endforeach; ?>
</p>

Form element helpers


We can also update our form to use the various form element helpers. These
helpers draw out the form elements for us consistently and exist for every one of the
various form input elements, as well as the select lists. In Listing 36, we'll apply the
formText() and formSubmit() helpers to our edit view to clean up our view
code.

Listing 36. record/edit.phtml using form helpers

<?php $this->headTitle()->append('Record Edit');


?><form action="/record/save/id/<?php echo
$this->escape($this->record['id']); ?>" method="post">
<p>Name: <?php echo $this->formText("name",$this->record['name']);
?></p>
<p>Data: <?php echo $this->formText("data",$this->record['data']);
?></p>
<p><?php echo $this->formSubmit("save","Save"); ?></p>
</form>

You can also use Zend_Form components, which will allow you to entirely define a
form with the controller and pass it to the view. This is very handy if you have lots of
display logic going into the generation of the form or if you wish to reuse the base
form views that in many different actions.

Optimizing the controller

Getting started with Zend Framework V1.5


Page 22 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

Outside the view, we can also help consolidate our controller code. We saw how we
can use the init() method of the controller class to specify logic that applies to all
views in a controller. But what if you want all of your site to have some certain logic it
passes through? We can subclass out the Zend_Controller_Action into our
own custom class and subclass out all of our controllers from this class. So let's pull
out the init() method from the RecordController and use it in the new
subclass library/MySite/Controller/Action.php.

Listing 37. MySite_Controller_Action

<?php
/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';
class MySite_Controller_Action extends Zend_Controller_Action
{
public function init()
{
parent::init();
if ( $this->_getParam('print', '0') == '1' )
$this->_helper->layout->setLayout('print');
$this->_helper->actionStack($this->_getParam('controller','home'), 'menu');
}
}

We've now fully optimized the code in our Web site, using the various view helpers
provided. We've also taken advantage of subclassing the various components to
apply code to different sections of our site, most notably in the Zend_Controller
component, as shown in Listing 37. These techniques truly embrace what the DRY
principle aims to accomplish: making code reusable in other parts of our Web site
and simplifying the code to make further enhancements much easier to accomplish.

Section 6. Summary
The beauty of the MVC design pattern is the modularity it provides by default, by
separating the presentation and application logic layers that give us the ability to
reuse code with ease. As we continue through this "Create a productivity package
with the Zend Framework V1.5 and Google Apps" series, we'll illustrate how we can
expand our application easily, without increasing the complexity of managing the
site.

We've set up a basic Web site using the Zend Framework, using many of the new
MVC features in V1.5. We've also touched on code reuse, using the DRY principle to
guide us on how to help refactor our site for easier maintenance in the future. In Part
2, we take the site a step further by adding authentication, Ajax, and integration with

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 23 of 27
developerWorks® ibm.com/developerWorks

Google Base.

Getting started with Zend Framework V1.5


Page 24 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

Downloads
Description Name Size Download method
Source code os-php-zend-google-pt1.example.zip
10KB HTTP

Information about download methods

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 25 of 27
developerWorks® ibm.com/developerWorks

Resources
Learn
• The Zend Framework Web site maintains the latest documentation, as well as
PHP installation FAQs.
• See the Zend Framework's Programmer's Reference Guide.
• Read an overview of the new features in V1.5.
• See the Components section of the Zend Framework manual for coverage of all
the framework components.
• Read the Zend_Layout Component Proposal.
• Thought Storms Model-View-Controller explains the MVC and the controversy
and confusion surrounding it.
• The phpPatterns Web site explains MVC from the PHP point of view.
• Visit Wikipedia for a high-level view of software frameworks.
• Get on overview of the MVC architecture from Wikipedia.
• What's new in Zend Framework V1.5.
• PHP.net is the central resource for PHP developers.
• Check out the "Recommended PHP reading list."
• Browse all the PHP content on developerWorks.
• Expand your PHP skills by checking out IBM developerWorks' PHP project
resources.
• To listen to interesting interviews and discussions for software developers,
check out developerWorks podcasts.
• Using a database with PHP? Check out the Zend Core for IBM, a seamless,
out-of-the-box, easy-to-install PHP development and production environment
that supports IBM DB2 V9.
• Stay current with developerWorks' Technical events and webcasts.
• Check out upcoming conferences, trade shows, webcasts, and other Events
around the world that are of interest to IBM open source developers.
• Visit the developerWorks Open source zone for extensive how-to information,
tools, and project updates to help you develop with open source technologies
and use them with IBM's products.
• Watch and learn about IBM and open source technologies and product

Getting started with Zend Framework V1.5


Page 26 of 27 © Copyright IBM Corporation 2008. All rights reserved.
ibm.com/developerWorks developerWorks®

functions with the no-cost developerWorks On demand demos.


Get products and technologies
• Download Zend Framework V1.5.1 from Zend Technologies.
• Download PHP V5.x from PHP.net.
• Innovate your next open source development project with IBM trial software,
available for download or on DVD.
• Download IBM product evaluation versions, and get your hands on application
development tools and middleware products from DB2®, Lotus®, Rational®,
Tivoli®, and WebSphere®.
Discuss
• Participate in developerWorks blogs and get involved in the developerWorks
community.
• Participate in the developerWorks PHP Forum: Developing PHP applications
with IBM Information Management products (DB2, IDS).

About the author


John Mertic
John Mertic graduated with a degree in computer science from Kent State University
and is currently a software engineer at SugarCRM. He has contributed to many open
source projects, most notably PHP projects; he is the creator and maintainer of the
PHP Windows Installer.

Getting started with Zend Framework V1.5


© Copyright IBM Corporation 2008. All rights reserved. Page 27 of 27

You might also like