Tuesday, July 14, 2009

Beginning PHP and Oracle From Novice to Professional by W. Jason Gilmore and Bob Bryla Chapter 25

Even at this likely early stage of your Web development career, chances are you’re already attempting to sketch out the features of a long-desired custom application. An e-commerce store perhaps? An
online community forum devoted to stamp collecting? Or maybe something a tad less interesting but nonetheless very practical, such as a corporate intranet? Regardless of the purpose, you should always strive to base development around sound development practices, several of which have become increasingly well-defined over time. In fact, focus on this area has become such that several groups of developers have banded together to produce a variety of Web frameworks, each of which serves to help others develop Web applications in a manner that’s efficient, rapid, and representa- tive of sound development principles.
This chapter’s purpose is threefold. First, the case is made for why you should seek to embrace one of the most crucial of these best practices, known as the Model-View-Controller (MVC) design architecture. Second, several of the most popular PHP-driven frameworks are introduced, each of which allows you to take advantage of MVC, in addition to a variety of other time-saving features such as Ajax integration. We devote additional time to the Zend Framework, which although the newest of the bunch, is rapidly becoming the most popular of these framework solutions.

Introducing MVC

The advantages of the MVC architecture are perhaps best illustrated by providing an example of the problems that are sure to arise when it isn’t implemented. Suppose you’ve recently launched a new Web site, only to find it’s soon inundated with users. Eager to extend this newfound success, the project begins to grow in ambition and, as a result, in complexity. You’ve even begun to hire a few talented staff members to help out with the design and development. Well aware of your pathetic design skills, you’re particularly keen for the designers to immediately begin an overhaul that will lead to a relaunch next month. Accordingly, you ask them to begin redesigning all of the site’s pages, many of which look like this:

<?php
// Include site configuration details and page header
INCLUDE "config.inc.php"; INCLUDE "header.inc.php";

// Scrub some data
$eid = htmlentities($_POST['eid']);

// Retrieve desired employee's contact information
$query = "SELECT last_name, email, tel
FROM employees
WHERE employee_id='$eid'";

449

// Parse and execute the query
$stmt = oci_parse($conn, $query);
oci_execute($stmt);

// Convert result row into variables
list($name, $email, $telephone) = oci_fetch_array($stmt, OCI_NUM);

?>
<div id="header">Contact Information for: <?php echo $name; ?></div> Employee Name: <?php echo $name; ?><br />
Email: <?php echo $email; ?><br /> Telephone: <?php echo $telephone; ?><br />

<div id="sectionheader">Recent Absences</div>
<?php

// Retrieve employee absences in order according to descending date
$query = "SELECT absence_date, reason
FROM absences WHERE employee_id='$eid' ORDER BY absence_date DESC";

// Parse and execute the query
$stmt = oci_parse($conn, $query);
oci_execute($stmt);

// Output retrieved absence information
while (list($date, $reason) = oci_fetch_array($stmt, OCI_NUM)) {
echo "$date: $reason";
}

// Include page footer
INCLUDE "footer.inc.php";

?>

Because the design and logic are inextricably intertwined, several problems soon arise:

• Designers who were hired with the sole purpose of making your Web site look great are now distracted by the task of having to learn PHP.
• Developers who were hired to help out with the expansion of Web site features are now distracted by fixing the bugs and security problems introduced by the novice PHP code written by the designers. In the process, they decide to make their own little tweaks to the site design, infu- riating the designers.
• Although a proper code versioning system has been deployed, the almost constant conflicts that arise due to simultaneous editing of the same set of files soon become tiresome and time consuming.

You’re probably noticing a pattern here: the lack of separation of concerns is breeding an envi- ronment of pain, distrust, and inefficiency. But there is a solution that can go a long way toward alleviating these issues: the MVC architecture.
The MVC approach renders development more efficient by breaking the application into three distinct components: the model, the view, and the controller. Doing so allows for each component to

be created and maintained in isolation, thereby minimizing the residual effects otherwise incurred should the components be intertwined in a manner similar to that illustrated in the previous example. While rather detailed definitions of each component exist in other learning resources, for the purposes of this introduction the following will suffice:

• The model: The model defines the rules for the world or the process an application is intended to represent. You can think of it as the specification responsible for both the application’s data and the behavior. For instance, suppose you create an application that serves as a conversion calculator, allowing users to convert from pounds to kilograms, feet to miles, and Fahrenheit to Celsius, among other units. The model is responsible for defining the formulas used to perform such conversions, and when presented with a value and desired conversion scenario, will carry out the conversion and return the result. Note it is not responsible for formatting the data or presenting it to the user. This is handled by the view.
• The view: The view is responsible for formatting the data returned by the model and presenting it to the user. It’s possible for more than one view to utilize the same model, depending on how the data should be presented. For instance, you might offer two interfaces for the conver- sion application: a Web-based interface, in addition to one created using PHP-GTK (http:// gtk.php.net/).
• The controller: The controller is responsible for determining how the application should respond based on events occurring within the application space (typically user actions), done by coordinating with both the model and the view to produce the appropriate response. A special controller known as a front controller is responsible for routing all requests to the appropriate controller and returning the response.

To help you better understand the dynamics of an MVC-driven framework, let’s work through a typical scenario involving the converter application, highlighting the role of each MVC component:

1. The user desires the application to perform an action, for instance, converting an input temper- ature from Fahrenheit to Celsius. The user then submits the form by clicking a submit button.
2. The controller responds by identifying the appropriate action, gathering the input, and supplying it to the model.
3. The model executes the function responsible for converting Fahrenheit to Celsius and returns the calculated value to the controller.
4. The controller calls the appropriate view, passing along the calculated value. The view is rendered and returned to the user.

The next section introduces four PHP-driven frameworks, each offering its own similar but unique MVC implementations.

PHP’s Framework Solutions

While PHP has long been perfectly suited for development the MVC way, no widespread solutions emerged until the wild success of Ruby on Rails (http://www.rubyonrails.org/) seemingly turned the spotlight away from the language long known as the reigning king of Web development. Thank- fully, PHP enthusiasts are practical folks and borrowed heavily from the compelling features espoused by not only Rails but also many other MVC frameworks. The following list highlights four of the more prominent PHP-specific solutions.

■Note You’ll also find that each of the frameworks introduced in this section has significantly more to offer than an MVC implementation. For instance, each facilitates Ajax integration, input filtering, and database interaction. You’re encouraged to carefully investigate the unique features of each in order to determine which best fits the needs of your particular application.

The CakePHP Framework

Of the four solutions described in this section, CakePHP (http://cakephp.org/) most closely corre- sponds to Rails, and indeed its developers readily mention the project was originally inspired by the breakout framework. Created by Michal Tatarynowicz in 2005, the project has since attracted the interest of hundreds of active developers and has even led to the founding of the nonprofit Cake Software Foundation (http://www.cakefoundation.org/) and CakeForge (http://cakeforge.org/), a community repository for hosting Cake-driven projects, plug-ins, and applications.
The CakeForge initiative is showing considerable success, with 100 hosted projects and more
than 2,100 registered users at the time of publication. Interesting projects include BakeSale, a Cake- driven shopping cart and catalog system, Cheesecake Photoblog, a customizable photoblog, and CakeAMFPHP, a Cake- and Flash-driven bulletin board.

■Note Unlike the three solutions that follow, Cake is capable of running on both PHP 4 and 5, meaning users
faced with hosting providers who’ve yet to upgrade to version 5 still have an opportunity to take advantage of a powerful PHP framework.

The Solar Framework

Solar (http://solarphp.com/), an acronym for simple object library and application repository for PHP 5, offers an extraordinary number of classes for facilitating rapid application development. Founded and led by Paul M. Jones, who is also responsible for several other major PHP projects, including the Savant Template System (http://phpsavant.com/), DB_Table (http://pear.php.net/ DB_Table), Text_Wiki (http://pear.php.net/Text_Wiki), and Yawp (http://phpyawp.com/), Solar benefits from both the experience gained and lessons learned from Jones’s active involvement in building other popular development solutions. Text-to-XHTML conversion, role management through a variety of mechanisms (file-based, LDAP, SQL), multiple authorization mechanisms (.ini files, htpasswd, IMAP, LDAP, and others), and interesting features such as social bookmarking components are just a few of the capabilities Solar has to offer.

The symfony Framework

The symfony framework (http://www.symfony-project.com/) is the brainchild of François Zaninotto, founder of the French Web development firm Sensio (http://www.sensio.com/). What’s unique about symfony is it’s built atop several other mature open source solutions, including the database abstrac- tion layer Creole (http://creole.phpdb.org/trac/), the Mojavi MVC layer (http://www.mojavi.org/), and the Propel (http://propel.phpdb.org/trac/) object-relational mapping layer. By eliminating the additional development time otherwise incurred in creating these components, symfony’s developers have been able to focus on creating features that greatly speed up application development time. Users of symfony can take advantage of automated forms validation, pagination, shopping cart management, and Ajax interaction using Prototype (http://prototype.conio.net/).

■Note To learn more about the symfony framework, consult the fantastic documentation found on the project Web site (http://www.symfony-project.com/). Also, check out The Definitive Guide to symfony by project founder Fabien Potencier and project documentation leader François Zaninotto (Apress, 2007).

All three of the aforementioned frameworks are extremely capable and prominent solutions used by countless developers around the globe. There is however another solution that is showing considerable promise, and accordingly is given special attention in this chapter.

The Zend Framework

The Zend Framework, an open source project fostered by the prominent PHP product and services provider Zend Technologies (http://www.zend.com/) was at the time of this writing the most aggressively developed of the four frameworks. Additionally, the Zend Framework provides a variety of task-specific components capable of carrying out tasks that are becoming increasingly commonplace in today’s cutting-edge Web applications. In addition to facilitating MVC-driven development, the Zend Framework can automate CRUD (create, retrieve, update, delete) database operations, and perform data caching and filter input. But what makes the Zend Framework particularly intriguing is the assortment of components it offers for performing nonessential but increasingly commonplace tasks such as creating PDFs, interacting with the Amazon, Flickr, and Yahoo! APIs, and consuming RSS feeds.
The rest of this chapter is focused on a fast-paced introduction to the Zend Framework’s key features, serving to acquaint you with its usage as well as to excite you about the amazing boost in productivity it and similar frameworks have to offer.

Introducing the Zend Framework

Although all of the frameworks presented in the previous section are very powerful and worthy of further consideration, Zend’s particularly unique approach to framework development led to the decision to explore it further in this chapter. To begin, Table 25-1 summarizes the components avail- able by way of the framework, which should give you a pretty good idea of its diverse set of capabilities. This is followed by an overview of the installation process, and finally two examples. The first example is intended to show you just how easy it is to construct a Web site skeleton using the framework, while the second offers a somewhat more practical twist, using the Yahoo! Web Services component to facilitate sales research.
To begin, take a moment to review Table 25-1, which presents a partial list of the most inter-
esting Zend Framework components accompanied by a brief description. In the two examples found later in this section, you’ll learn how to deploy several of these components.

Table 25-1. A Partial Listing of Zend’s Feature-Specific Components

Component Purpose
Zend_Amazon Facilitates interaction with Amazon E-Commerce Service.

Zend_Cache Caches data into speedy backend adapters such as RAM, SQLite, and
APC (Alternative PHP Cache).

Zend_Config Facilitates the management of application configuration parameters.

Zend_Controller Manages the framework’s controller component.

Table 25-1. A Partial Listing of Zend’s Feature-Specific Components (Continued)

Component Purpose

Zend_Db Drives the framework’s PDO-based database API abstraction layer.

Zend_Feed Consumes RSS and Atom feeds.

Zend_Filter Facilitates the filtering and validation of data, including the ability to validate proper syntax for commonplace values such as e-mail addresses, credit card numbers, dates (according to ISO 8601 format), and phone numbers.

Zend_Filter_Input Relies upon the methods provided by Zend_Filter to filter input.

Zend_Gdata Provides an interface to several of Google’s services, including, among others, Google Blogger, Google Calendar, and Google Notebook.

Zend_HTTP_Client Performs HTTP requests. Presently capable of executing GET, POST, PUT, and DELETE requests.

Zend_Json Facilitates interaction between JavaScript and PHP by serializing PHP data to JSON (JavaScript Object Notation) and vice versa. See http:// www.json.org/ for more information about JSON.

Zend_Log Facilitates application logging. Zend_Mail Sends text and MIME-compliant e-mail. Zend_Mime Parses MIME messages.
Zend_Pdf Creates PDF documents.

Zend_Search_Lucene Facilitates search engine development using the Lucene library. Zend_Service_Amazon Facilitates interaction with the Amazon Web Services API. Zend_Service_Flickr Facilitates interaction with the Flickr Web Services API. Zend_Service_Yahoo Facilitates interaction with the Yahoo! Web Services API. Zend_View Manages the framework’s view component.
Zend_XmlRpc Provides support for consuming and serving XML-RPC implementations.

Downloading and Installing the Zend Framework

Proceed to http://framework.zend.com/download to download the latest stable version of the Zend Framework. There are three available options for retrieving the source code, including downloading zip and tar packages, or checking out the code from Zend’s Subversion repository. Choose which- ever option is most convenient for you, uncompress the code if you choose one of the former options, and move the library directory to a convenient location, within the PHP installation directory’s includes directory, for instance. Only this library directory is relevant, so you can disregard all other files in the uncompressed package. Also, consider changing the library directory name to something very easy to reference, such as zfw.

■Caution The Zend Framework requires PHP 5.1.4 or newer.

Because the Zend Framework works by routing all requests through a single script, you’ll also need to configure Apache’s mod_rewrite module. Create an .htaccess file and place the following contents in it, saving the file to the document root:
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

■Note Apache’s mod_rewrite module is a powerful feature of Apache used to manipulate requested URLs. On
Windows, mod_rewrite is disabled by default. To enable it, you’ll need to open up httpd.conf and uncomment the line LoadModule rewrite_module modules/mod_rewrite.so, update the appropriate AllowOverride directive to allow .htaccess files to be used, and then restart the Apache server. See the Apache documentation for more information about this directive.

Finally, because you’ll need to reference several Zend Framework components from within your application, and it’s always wise to ensure maximum application portability, this directory should be directly accessible by appending it to the php.ini file’s include_path directive. For example, on Linux this directive might look like this:

include_path = ".:/usr/local/lib/php/includes/zfw/"

On Windows this directive might look like this:

include_path = ".;c:\php\includes\zfw"

If you don’t have control over the php.ini file, not to worry; you can place the following directive in the .htaccess file, which should reside in the server’s document root:

php_value include_path ".:/usr/local/lib/php/includes/zfw/"

On Windows the directive might look like this:

php_value include_path "C:\php\includes\zfw\"

The Zend Framework has been configured. If you added the include_path information to
php.ini, you’ll need to restart your Web server in order for the changes to take effect.

Creating Your First Zend Framework-Driven Web Site

It’s a fair bet that even a very simple example will leave you utterly convinced that frameworks are a development tool you won’t be able to live without.

Create the Directory Structure

By default, the Zend Framework relies upon a highly organized application directory structure known as the conventional modular directory structure. In its most basic form, this structure looks like this:

Web server document root/
index.php application/
modules/
default/ controllers/ views/
scripts/

This structure opens up the possibility to manage multiple hosted MVC applications within the same location. In a situation where multiple MVC applications exist, you would add additional module directories under the modules directory. However, for the purposes of the examples in this chapter, we’ll just stick with a single (default) application.
Therefore, a simple Web application might be structured as follows. Note how there are three
controllers and each of those controllers matches up to a corresponding view directory:

Web server document root/
index.php application/
modules/
default/
controllers/ IndexController.php BookController.php AboutController.php
views/ footer.phtml header.phtml scripts/
about/ contact.phtml index.phtml
book/ index.phtml toc.phtml
index/
index.phtml

Don’t worry about the oddly named files and structure too much at this point. Just understand that based on the provided controllers and views and a typical configuration, the following URLs would work:

http://www.example.com/ http://www.example.com/about/ http://www.example.com/about/contact/ http://www.example.com/book/ http://www.example.com/book/toc/
Because this directory structure won’t suit every developer, it’s possible to change the default settings; however, coverage of this feature is out of the scope of this chapter.

Create the Front-End Controller

To begin, create a file named index.php and place the code found in Listing 25-1 inside it. The index.php script is known as the front-end controller and, believe it or not, it will be responsible for ensuring that every request for this application receives the appropriate response. This document should reside in your desired application document root.
Additionally, in the same directory, create a directory named application, and in that directory create a modules directory, and within that a default directory. Finally, within the default directory create two more directories named controllers and views, and within the views directory create a directory named scripts, each of which you’ll use later.

Listing 25-1. The Application’s Front-End Controller (index.php)

<?php

// Load the Front Controller class require_once('Zend/Controller/Front.php');

// Instantiate an instance of the Front Controller Class
$frontController = Zend_Controller_Front::getInstance();

// Point to the module directory
$frontController->addModuleDirectory('./application/modules');

// Throw exceptions (useful during debugging)
$frontController->throwExceptions(true);

// Start the Front Controller
$frontController->dispatch();

?>

It is assumed the Zend Framework application will reside in the server’s document root. However,
because this isn’t always possible, you can use the setBaseUrl() method to override the front-end controller’s default behavior. See the Zend Framework documentation for more information.

The Controllers

Next we’ll create two controllers, namely IndexController.php and AboutController.php. These views should be placed in the directory application/modules/default/controllers. First, create the default controller class (IndexController.php), which defines the action that will occur when the Web site’s home page is requested (for the sake of consistency throughout the remainder of this chapter we’ll refer to http://www.example.com/ as the target domain). This script is shown in Listing 25-2.

Listing 25-2. The IndexController Class (IndexController.php)

<?php

// Load the Zend_Controller_Action class require_once('Zend/Controller/Action.php');

class IndexController extends Zend_Controller_Action
{

// Accessed through http://www.example.com/
public function indexAction()
{
$this->view->title = "Welcome to Our Chess Club Web Site!";
}

}

?>

In this example, I’ve created a view property named title that will be used to assign the Web
page’s title.

Finally we’ll create one more controller intended to display information pertinent to the Web site’s purpose and, for the sake of demonstration, some information about the visiting user. This controller, titled AboutController.php, is displayed in Listing 25-3.

Listing 25-3. The AboutController Controller (AboutController.php)

<?php

// Load the Zend_Controller_Action class require_once('Zend/Controller/Action.php');

class AboutController extends Zend_Controller_Action
{

// Accessed through http://www.example.com/about/
public function indexAction()
{
$this->view->title = "About Our Chess Club";
}

// Accessed through http://www.example.com/about/you/
public function youAction()
{
// Page title
$this->view->title = "About You!";

// Retrieve the user's IP address
$this->view->ip = $_SERVER['REMOTE_ADDR'];

// Retrieve browser information
$this->view->browser = $_SERVER['HTTP_USER_AGENT'];
}

}

?>

Defining the Views

Next we’ll create the views that correspond to these three actions: one for the home page, one for the
/about/ page, and one for the /about/you/ page. The home page view should be placed in the directory
/application/modules/default/views/scripts/index/, and the other two in /application/modules/ default/views/scripts/about/. These views are presented in Listings 25-4, 25-5, and 25-6, respec- tively. Each of these views is intended to demonstrate different facets of the behavior of views.

Listing 25-4. The index.phtml View

<?php
echo $this->render('header.phtml');
?>

<div id="header">Next Chess Club Meeting: April 12</div>

<p>

Welcome to our Chess Club's Web site! We're a bunch of chess enthusiasts who travel the globe in search of worthy opponents. Join us at our next meeting, held at the coffee shop on the corner of Third and Neil
each Tuesday at 6 p.m.
</p>

<?php
echo $this->render('footer.phtml');
?>

Listing 25-5. The index.phtml View

<?php
echo $this->render('header.phtml');
?>

<div id="header">About Our Chess Club</div>

<p>

</p>

Founded: 1997<br />
City: Columbus, Ohio<br />
Where we meet: Cup of Love, corner of Third and Neil<br /> When we meet: Each Tuesday at 6 p.m.<br />
Notes: Bring your board and pieces if you have them!

<?php
echo $this->render('footer.phtml');
?>

Listing 25-6. The you.phtml View

<?php
echo $this->render('header.phtml');
?>

<div id="header">About You!</div>

<p>

</p>

Your IP Address: <?php echo $this->escape($this->ip); ?><br /> Your Browser: <?php echo $this->escape($this->browser); ?><br />

<?php
echo $this->render('footer.phtml');
?>

As demonstrated in these views, you should pass all data originating in the controller through
the escape() method, as it will properly filter data through PHP’s htmlspecialchars() function.
You’ll see each of these views refer to header.phtml and footer.phtml files (both of which are available at the book’s Source Code/Download page at http://www.apress.com), which serve as the page template headers and footers, respectively. These global templates can be placed in the
/application/modules/default/views/scripts/ directory and will automatically be located and integrated into the view when using the render() method. Not surprisingly, the header could include

references to the page masthead as well as the CSS and JavaScript files. The footer could include things such as copyright information and the closing page tags.

■Tip Quite conveniently, the Zend Framework supports the ability to take advantage of more sophisticated
templating solutions than those demonstrated here, such as Smarty (see Chapter 19). See the Zend Framework manual for more information.

Try It Out

With the actions and views defined, it’s time for the moment of truth. Try navigating to the following pages and see what happens:

• To access the home page, navigate to this URL: http://localhost/.

• To access the about.phtml view, navigate to this URL: http://localhost/about/.

• To access the you.phtml view, navigate to this URL: http://localhost/about/you/.

Next, consider experimenting by adding a new action and class and set of corresponding views. Just copy and rename one of the controllers, being sure to follow the same conventions used in the original class.

Searching the Web with Zend_Service_Yahoo

Table 25-1 presented just some of the dozens of Zend Framework components at your disposal, therefore as you might imagine it’s difficult to decide which to demonstrate in this brief chapter. After some consideration it seems ideal to introduce the Zend_Service_Yahoo component, as it shows how the framework can really shine at simplifying otherwise fairly complex operations, in this case Web Services interaction.
The Zend_Service_Yahoo component allows you plug into Yahoo!’s search engine, as well as search images, businesses, and news. Therefore, suppose you want to add a page to the chess club Web site that displays the latest chess news. This news page will appear at http://www.example.com/
news/, meaning a new controller and view will need to be added.

■Note In order to follow along with these examples you’ll need to register for a free Yahoo! application ID. Navigate
to http://developer.yahoo.com/ for more information.

Create the Controller

The controller, named NewsController.php, should be placed in the application/modules/default/ controllers directory. This controller is responsible for retrieving the news via the Yahoo! compo- nent and sending that data to the view. The NewsController.php script is found in Listing 25-7.

Listing 25-7. The Chess Club’s News Controller (NewsController.php)

<?php

// Load the Zend_Controller_Action class require_once('Zend/Controller/Action.php');

// Load the Yahoo! Service class require_once('Zend/Service/Yahoo.php');

class NewsController extends Zend_Controller_Action
{

public function indexAction()
{

// Invoke the Yahoo! service
$yahoo = new Zend_Service_Yahoo("INSERT_YAHOO_ID_HERE");

// Execute the search
$results = $yahoo->newsSearch("chess");

// Send the search results to the view
$view->results = $results;

}
}

Of course, in a real-world situation you might use the controller to retrieve some user prefer- ences from a database pertinent to region, allowing for more geographically targeted chess-related news results. Those preferences could then be passed to the view much in the same way the other properties were passed in previous examples.

Create the View

The view’s role is simple: render the search results in an easily readable format. This is done by looping through each result and outputting it to the browser. This file, named index.phtml, should be placed in the directory application/modules/default/views/scripts/news/. Listing 25-8 presents this simple but effective view.

Listing 25-8. The Chess Club’s News View (index.phtml)

<?php
echo $this->render('header.phtml');
?>

<h4>The Latest Chess News</h4>

<?php
foreach ($this->results as $result) {
printf("<p><a href='%s'>%s</a> | %s <br />",
$this->escape($result->NewsSourceUrl),
$this->escape($result->NewsSource),
date("F j, Y", $this->escape($result->PublishDate))
);
printf("%s </p>", $this->escape($result->Summary));
}

?>

<?php
echo $this->render('footer.phtml');
?>

Executing this code will produce news-related output similar to that shown in Figure 25-1.

Figure 25-1. Output of the latest chess news

Summary

This chapter provided but a glimpse of what the Zend Framework is capable of; but hopefully it has served its purpose: to get your mind racing about just how productive Web frameworks can make you.
In the following chapter, an introduction to Oracle, you’ll begin the next learning phase of this book.

0 comments: