Os PHP Zend Google pt1 PDF
Os PHP Zend Google pt1 PDF
24 Jun 2008
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.
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
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.
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.
application/
controllers/
IndexController.php
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.
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
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.
<?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
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.
Listing 5. index.phtml
When you view the index.phtml page in your browser, you should see Figure 1.
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()
{
}
}
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.
Listing 7. RecordController
<?php
/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';
class RecordController extends Zend_Controller_Action
{
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.
Listing 8. RecordController::listAction()
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()
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.
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.
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.
</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>
- <?php echo $this->escape($record['data']); ?>
<a href="/record/edit/<?php echo $this->escape($record['id']);
?>">Edit</a>
<a href="/record/delete/<?php echo $this->escape($record['id']);
?>">Delete</a>
</li>
<?php endforeach; ?>
</ul>
</body>
</html>
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
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.
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.
<?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.
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.
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.
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
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.
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.
<?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');
}
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.
/** 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');
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.
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.
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.
<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>
<?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.
And the nomenu template simplifies down to a call to the main menu only.
<?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.
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.
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.
<li>
<strong><?php echo $this->escape($this->name); ?></strong>
- <?php echo $this->escape($this->data); ?>
<a href="/record/edit/<?php echo $this->escape($this->id);
?>">Edit</a>
<a href="/record/delete/<?php echo $this->escape($this->id);
?>">Delete</a>
</li>
<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.
Now we'll call the Partial helper to call the helper view we created in Listing 33 in the
main menu.
<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>
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.
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.
<?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
Google Base.
Downloads
Description Name Size Download method
Source code os-php-zend-google-pt1.example.zip
10KB HTTP
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