Chapter 6. Resource-Oriented Clients and Services with Zend Framework

Zend framework is a PHP component library, which simplifies the building of PHP applications. It is a collection of PHP files and not a PHP extension implemented in C like libcurl. Zend is a company that provides commercial support for PHP, and because this framework comes from that company, it has a serious standing in the industry. The framework is available for download for free.

You can find more information on Zend Framework from http://framework.zend.com/. Zend Framework comes with PHP classes that provide APIs that are easy to use when it comes to writing REST services and clients. In this chapter, we will see how we can use the Zend framework to implement REST services and clients and will also see how we can implement the library system that was introduced the in last two chapters using the Zend Framework.

Zend Framework has been designed with simplicity in mind. It provides a lightweight, loosely-coupled component library. It can also be customized to meet specific business needs. There are no configuration files and so it is easier to get started. It is a high-quality, object-oriented PHP 5 class library that is well tested and ready to use.

Installing Zend Framework

You can download the Zend Framework from http://framework.zend.com/download. Then you can extract the contents of the library folder to the directory wherever you want to place the PHP libraries. Inside the library folder of the Zend framework extract there is a top-level Zend directory which contains all Zend Framework components.

Once you copy the library folder of Zend Framework, it is installed and ready to use.

Services with Zend_Rest_Server

The Zend_Rest_Server class in Zend Framework can be used to implement REST style services. You can find the PHP class API at http://framework.zend.com/apidoc/core/Zend_Rest/Server/Zend_Rest_Server.html.

Let's first see a simple example (hello.php) on how to use the Zend_Rest_Server class. This script acts as a service and sends a "Hello World" greeting in the XML payload when accessed.

<?php
require_once 'Zend/Rest/Server.php';
/**

* Say Hello
*/

function sayHello()
{
return 'Hello World';
}
$server = new Zend_Rest_Server();
$server->addFunction('sayHello');
$server->handle();
?>

Run the PHP with URL http://localhost/hello.php?method=sayHello

The output from hello.php is shown below.

Services with Zend_Rest_Server

This PHP script implements a simple hello world REST style service using the Zend_Rest_Server class.

We would obviously require the server class.

require_once 'Zend/Rest/Server.php';

Then we define the service function. In this way we have a single function named sayHello.

/**
* Say Hello
*/

function sayHello()
{
return 'Hello World';
}

Next, we need to create the server class instance and add the service function.

$server = new Zend_Rest_Server();
$server->addFunction('sayHello');

Finally, we call the handle member method of the server class. Call to this function indicates that we should handle the incoming request with the function added to the service.

$server->handle();

We can send a HTTP GET request to the service using the URL http://localhost/hello.php?method=sayHello. Once a request is received by this service, it will call the sayHello function and get the return value of that function to form the response and send to the client. The response would be in XML format as shown below.

<?xml version="1.0" encoding="UTF-8"?>
<sayHello generator="zend" version="1.0"> <response>Hello World</response> <status>success</status> </sayHello>

Clients with Zend_Rest_Client

The Zend_Rest_Client class in Zend Framework can be used to implement REST style clients. You can find the PHP class API at http://framework.zend.com/apidoc/core/Zend_Rest/Client/Zend_Rest_Client.html.

Let us see how we can use this class to consume the Hello World service that we implemented in the previous section.

<?php
require_once 'Zend/Rest/Client.php';
$client = new Zend_Rest_Client('http://localhost');
$options['method'] ='sayHello';
$response = $client->restGet('/rest/06/hello.php', $options);
echo htmlspecialchars($response->getBody());
?>

We require the client class for this sample.

require_once 'Zend/Rest/Client.php';

And we create the client object instance with the service host information.

$client = new Zend_Rest_Client('http://localhost');

The request URL for the Hello service should include the name of the method we would like to invoke. As an example, for the Hello World service, the request URL would look like http://localhost/rest/06/hello.php?method=sayHello.

This means that the Zend REST server class expects the name of the method to be given as a request parameter in the request. Hence we use an options array to set this. The array index method is mandatory. We cannot use any other index name other than method to specify the method being invoked.

$options['method'] = 'sayHello';

Next, we tell the client to send a GET request to the server proving the resource path and the request parameters.

$response = $client->restGet('/rest/06/hello.php', $options);

We get this response and echo it as the output.

echo htmlspecialchars($response->getBody());

And the output would look like:

<?xml version="1.0" encoding="UTF-8"?> <sayHello generator="zend" version="1.0"> <response>Hello World</response> <status>success</status> </sayHello>

Library System with Zend REST classes

Now that we are familiar with the basic principles related to the REST classes that come with Zend Framework, let's explore how we can implement the library system that we used in the last two chapters as our example REST style system.

Library Service

As we saw in the last two chapters, Chapter 4 Resource Oriented Services and Chapter 5&mdash;Resource Oriented Clients, we need to be able to map the resource URL locations and the HTTP verbs to implement the various business operations in the library system.

Since we need to know the HTTP method being used, while implementing service operations we cannot implement the library service using the Zend_Rest_Server class alone with Zend Framework. This is because, by design, there is no support in the REST server class to detect the HTTP method used by the client request. As we saw in Chapter 4, the HTTP verb being used while sending a request to the service to invoke an operation determines the nature of the business operation semantics. As an example, a GET request would result in the return of currently available data and a POST request would result in the creation or update of data. In other words, GET requests would access data while POST requests would update the data. Hence, while programming services, we need to access information regarding the HTTP verb being used.

If we are to check for the client request HTTP method, we need to make use of Zend_Contoller_Request_Http class (http://framework.zend.com/apidoc/core/Zend_Controller/Request/Zend_Controller_Request_Http.html). To use this class, we need to use the Model-View-Controller (MVC) constructs that come with Zend Framework. See http://framework.zend.com/manual/en/zend.controller.html for more details on Zend_Controller and MVC model.

The Model on MVC refers to the real-world representation of the business domain. For example, in the library system, books, members and borrowings consist of the model.

The View refers to the ways that the data being managed are viewed. For example, we may have a view to see members who have borrowed books. We would also be interested in seeing which books have been borrowed by which member in that view.

The Controller refers to the actions that the system can perform. Controller operates on the Model and performs various actions. For example, we would add a new member or create a new book borrowing.

While designing RESTful services, we map resources identified by a URI to HTTP verbs to define business operations. Resources can be thought of to represent the Model. Since HTTP verbs define the actions on the resources, the HTTP verbs to resource mapping can be thought of as Controller.

RESTful clients use HTTP verbs against resource URIs to invoke business operations. So they too use Model and Controller aspects of MVC.

Hence, REST clients and services deal with Model and Controller for the most part. While designing a Web application using REST clients to consume services, we would incorporate a View to present the data to the user. It is quite similar to the way we would use tables and forms to view and update data in a database driven application. We would connect to the database, pull data, and display that to the user with a View. We would also let the user fill forms with a View and update the database using those data filled into the forms. Likewise, when using REST services, we would request the information from a service using a REST client, and display them in a View with tables, or we will request the service to invoke an update operation using a REST client with data from forms in a View.

Because it is vital to get to know the HTTP verb in use on the server side while implementing business operations for services, we need to know how to access the information regarding the HTTP verb being used in the client request. With the request class that we get with the Zend_Controller, we have the following methods to check for the kind of request sent by the client.

  • isGet()

  • isPost()

  • isPut()

  • isDelete()

  • isHead()

Because of this, we will be using the Zend_Controller model to implement our sample library service. And for this, we need a folder structure similar to the following.

library
Zend REST classes library systemlibrary services, implementing├───application
│ ├───controllers
│ ├───layouts
│ ├───models
│ └───views
│ ├───filters
│ ├───helpers
│ └───scripts
│ └───index
└───public

Since we are implementing a service, we would not require the views folder, as there are no views or in other words, display elements or HTML pages, associated with a service.

Controllers for Book and Member Resources

The controllers folder contains the controllers, those PHP scripts that are responsible for handling the request for a resource. As per our sample, there would be two main resources in our library service: book and member. Hence we need two controllers.

  • BookController.php

  • MemberController.php

Note that having Controller suffixing the resource name is a convention that needs to be adhered to while using Zend_Controller interface.

Before looking into the controller implementations, let's first look into the models used by the controllers.

Models for Book and Member Resources

The models folder contains the data mappings for the resources. They map to the database elements that we are going to use in the library system. Again we have two main data models which are placed in the models sub-folder in our system. As explained earlier, the resources in the REST service design can be mapped to the Model in MVC.

  • books.php

  • members.php

The following code shows the model for book.

<?php
class Books extends Zend_Db_Table
{
protected $_name = 'book';
}
?>

Note how much simpler it is to use the Zend framework to work with a database. We are extending our data model for book table from the Zend_Db_Table. And the Zend Framework would use PHP Data Objects (PDO) for mapping the class into a database table. See http://www.php.net/pdo for more details on PDO. Basically, we do not have to deal with any SQL directly with this model.

With

protected $_name = 'book';

We specify that we want the database table named book to be mapped to Books class.

Similarly, we have the Members PHP class that maps to the members model.

<?php
class Members extends Zend_Db_Table
{
protected $_name = 'member';
}
?>

Note that, we did not provide any database related information in any of these classes. For providing database configuration information we can use a configuration file. The Zend_Db_Table class is capable of picking up the table column information from the database automatically; hence we need not specify the database table column names explicitly. Based on the table name assigned to the $_name attribute of the PHP class, the Zend_Db_Table class would extract the column names from the database.

Application Configuration and Initialization

We can use a configuration file with various parameters like the database name and username/password for the database. Let us name this file config.ini. We can name this file using any name that we prefer because we can tell the application what the name of the configuration is. We will see how to do this later in this section.

Here are the contents of this file.

[general]
db.adapter = PDO_MYSQL db.params.host = localhost
db.params.username = sam
db.params.password = pass
db.params.dbname = library

This configuration is loaded by the index.php file, which would be located in the public folder. In addition to loading the configuration, this script also would do the other required initializations.

<?php
library services, Zend REST classes library systemconfiguration file, initializingerror_reporting(E_ALL|E_STRICT);
ini_set('display_errors', 1);
date_default_timezone_set('Europe/London');
// directory setup and class loading
set_include_path('.' . PATH_SEPARATOR . '../library/'

. PATH_SEPARATOR . '../application/models'

. PATH_SEPARATOR . get_include_path());
include "Zend/Loader.php";
Zend_Loader::registerAutoload();
// load configuration
$config = new Zend_Config_Ini('../application/config.ini', 'general');
$registry = Zend_Registry::getInstance();
$registry->set('config', $config);
// setup database
$db = Zend_Db::factory($config->db);
Zend_Db_Table::setDefaultAdapter($db);
// setup controller
$frontController = Zend_Controller_Front::getInstance();
$frontController->throwExceptions(true);
$frontController->setControllerDirectory('../application/controllers');
Zend_Layout::startMvc(array('layoutPath'=>'../application/layouts'));
// run!
$frontController->dispatch();
?>

If you follow the comments in the above code in the directory setup and class loading section, we add the models folder to the include path.

set_include_path('.' . PATH_SEPARATOR . '../library/'

. PATH_SEPARATOR . '../application/models'

. PATH_SEPARATOR . get_include_path());

This step is required because we need the PHP scripts that implement models to be on the include path. For example, books.php and members.php must be in the include path because we will be using those classes while implementing business operations.

In the load configuration section we load the config.ini file and set it to the Zend_Registry instance.

$config = new Zend_Config_Ini('../application/config.ini', 'general'),
$registry = Zend_Registry::getInstance();
$registry->set('config', $config);

As mentioned earlier, we could have named the configuration file with whatever name that we desire and used that name as a parameter to the Zend_Config_Ini() call.

Then in the setup database section, we use the database settings loaded from the configuration file to set up database parameters.

$db = Zend_Db::factory($config->db);
Zend_Db_Table::setDefaultAdapter($db);

Next, in the setup controller section, we set up the controllers folder.

$frontController = Zend_Controller_Front::getInstance();
$frontController->throwExceptions(true);
$frontController->setControllerDirectory('../application/controllers'),

Finally, in the run section, we dispatch the front controller instructing it to handle the incoming requests.

$frontController->dispatch();

Book Controller

Book controller implements the functionality related to the book resource. As we saw in last chapters, a GET request for the book URL would return the list of books and a POST request would create new books using the posted data.

A controller class needs to inherit from Zend_Controller_Action class.

class BookController extends Zend_Controller_Action {

Then we need to map actions to the request URL. We could map the book resource to the following URL of the application, http://localhost/rest/06/library/public/index.php/book.

Action mapping is done by implementing a function with the function name having the action name suffixed by Action.

function indexAction() {

We would use the book model within this action implementation because we are dealing with the book resource here.

$books = new Books();

We also need to make sure that the responses from this controller are not rendered as HTML, because we are implementing a service whose output is XML. Hence we disable rendering in the index action function.

$this->_helper->viewRenderer->setNoRender();

Next, we need to get to know the request method to distinguish between GET and POST requests.

if ($this->_request->isGet()) {

Check if it is a GET request.

} else
if ($this->_request->isPost()) {

Or if it is a POST request.

In case of GET requests, we use a Zend_Rest_Server instance to deal with the request.

if ($this->_request->isGet()) {
$server = new Zend_Rest_Server();
$server->addFunction('getBooks'),
$params['method'] = 'getBooks';
$params['book_list'] = $books->fetchAll();
$server->handle($params);
}

We add a function named getBooks to the REST server.

We also need to set the parameters to be passed to the getBooks function. We use an array named params to prepare the request parameters to the REST server instance. The first parameter is the method name as required by the Zend_Rest_Server class.

$params['method'] = 'getBooks';

The client request is received by the book controller of the service. From the controller, once we get to know that it is a GET request, we map the request to the getBooks method.

The other parameter is the list of books fetched from the database.

$params['book_list'] = $books->fetchAll();

The parameter name book_list is the same name as the parameter name used in the getBooks PHP function. It is a convention used by the Zend Framework to ensure that the controller passes the correct parameters while making the function call.

Note that, because we inherited the Books class from Zend_Db_Table, we inherit the fetchAll() member function that we are using here to fetch data.

And then we call the handle method of the REST server instance with the parameters.

$server->handle($params);

This call would basically call the getBooks function with the book_list parameter.

The getBooks function formulates the XML response from the list of books. This function will be defined in the same PHP script where we define the book controller.

function getBooks($book_list) {
$result = '<?xml version="1.0" encoding="UTF-8"?><books>';
foreach ($book_list as $book) {
$result .= "<book><id>" . $book->id . "</id>" .
"<name>" . $book->name . "</name>" .
"<author>" . $book->author . "</author>" .
"<isbn>" . $book->isbn . "</isbn></book>";
}
$result .= "</books>";
$xml = simplexml_load_string($result);
return $xml;
}

This function traverses through the list of books using a foreach loop and forms the XML response to be returned as response.

That is how the book controller is handling the GET requests.

In case of POST requests, we load the incoming XML request data posted and create new book instances in the database.

if ($this->_request->isPost()) {
$xml = simplexml_load_string($this->_request- >getRawBody());
foreach ($xml->book as $book) {
$row = $books->createRow();
$row->name = $book->name;
$row->author = $book->author;
$row->isbn = $book->isbn;
$row->save();
}
}

First, the raw XML data in the POST request body is loaded as a simple XML object instance.

$xml = simplexml_load_string($this->_request->getRawBody());

Then for each book element in the XML payload,

foreach ($xml->book as $book) {

We create a new database table row in the book table,

$row = $books->createRow();

Assign the values received in the request corresponding to the new book instance,

$row->name = $book->name; $row->author = $book->author; $row->isbn = $book->isbn;

And save the newly created database row.

$row->save();

Note that we are not using an instance of a Zend_Rest_Server in case of a POST request. Because we are not returning any response in case of a POST request and also because we could use an instance of a Books class, the book model, to deal with the database operations, use of a REST server instance would be an overkill here. If the request succeeds, the server would be sending a 200 OK response. If the request fails, the server would send some error status code, such as 500 Internal server error. This would be handled by the framework. The client can get to know the success or failure by tracking the HTTP status code.

Here is an example response for the success case.

HTTP/1.1 200 OK
Date: Sun, 14 Sep 2008 14:35:57 GMT
Server: Apache/2.2.6 (Win32) mod_ssl/2.2.6 OpenSSL/0.9.8e PHP/5.2.5
X-Powered-By: PHP/5.2.5
Content-Length: 0
Content-Type: text/html

Here is the complete code for the PHP script implementing the book controller.

<?php
require_once 'Zend/Rest/Server.php';
function getBooks($book_list) {
$result = '<?xml version="1.0" encoding="UTF-8"?><books>';
foreach ($book_list as $book) {
$result .= "<book><id>" . $book->id . "</id>" .
"<name>" . $book->name . "</name>" .
"<author>" . $book->author . "</author>" .
"<isbn>" . $book->isbn . "</isbn></book>";
}
$result .= "</books>";
$xml = simplexml_load_string($result);
return $xml;
}
class BookController extends Zend_Controller_Action {
function indexAction() {
$books = new Books();
$this->_helper->viewRenderer->setNoRender();
if ($this->_request->isGet()) {
$server = new Zend_Rest_Server();
$server->addFunction('getBooks'),
$params['method'] = 'getBooks';
$params['book_list'] = $books->fetchAll();
$server->handle($params);
} else
if ($this->_request->isPost()) {
$xml = simplexml_load_string($this->_request- >getRawBody());
foreach ($xml->book as $book) {
$row = $books->createRow();
$row->name = $book->name;
$row->author = $book->author;
$row->isbn = $book->isbn;
$row->save();
}
library services, Zend REST classes library systembook controller PHP source code}
}
}
?>

Member Controller

The implementation of the member controller class to represent the member resource is very similar to the book controller, except for a few differences.

First we could map the member resource to the following URL of the application, http://localhost/rest/06/library/public/index.php/member.

class MemberController extends Zend_Controller_Action {

And we use the member data model in the index action function.

function indexAction() {
$members = new Members();
$this->_helper->viewRenderer->setNoRender();

If it is a GET request, we call the get members function.

if ($this->_request->isGet()) {
$server = new Zend_Rest_Server();
$server->addFunction('getMembers'),
$params['method'] = 'getMembers';
$params['member_list'] = $members->fetchAll();
$server->handle($params);
}

And here is the function added to the service.

function getMembers($member_list) {
$members = array ();
$result = '<?xml version="1.0" encoding="UTF-8"?><members>';
foreach ($member_list as $member) {
$result .= "<member><id>" . $member->id . "</id>" .
"<first_name>" . $member->first_name . "</first_name>" .
"<last_name>" . $member->last_name . "</last_name></member>";
}
$result .= "</members>";
$xml = simplexml_load_string($result);
return $xml;
}

And in case of a POST request, we create new member instances.

if ($this->_request->isPost()) {
$xml = simplexml_load_string($this->_request->getRawBody());
foreach ($xml->member as $member) {
$row = $members->createRow();
$row->first_name = $member->first_name;
$row->last_name = $member->last_name;
$row->save();
}
}

Here is the complete source code for the member controller PHP class.

<?php
require_once 'Zend/Rest/Server.php';
function getMembers($member_list) {
$members = array ();
$result = '<?xml version="1.0" encoding="UTF-8"?><members>';
foreach ($member_list as $member) {
$result .= "<member><id>" . $member->id . "</id>" .
"<first_name>" . $member->first_name . "</first_name>" .
"<last_name>" . $member->last_name . "</last_name></member>";
}
$result .= "</members>";
$xml = simplexml_load_string($result);
return $xml;
}
class MemberController extends Zend_Controller_Action {
library services, Zend REST classes library systemmember controller PHP class source codefunction indexAction() {
$members = new Members();
$this->_helper->viewRenderer->setNoRender();
if ($this->_request->isGet()) {
$server = new Zend_Rest_Server();
$server->addFunction('getMembers'),
$params['method'] = 'getMembers';
$params['member_list'] = $members->fetchAll();
$server->handle($params);
} else
if ($this->_request->isPost()) {
$xml = simplexml_load_string($this->_request- >getRawBody());
foreach ($xml->member as $member) {
$row = $members->createRow();
$row->first_name = $member->first_name;
$row->last_name = $member->last_name;
$row->save();
}
}
}
}
?>

Library Clients

The previous section explained how to implement the service resources. Now let's consume those services using Zend_Rest_Client class. Again, we can use the Zend_Controller to leverage the MVC model. Since the client would be using views, we are better off using an MVC.

Again, for the client application we need a folder structure similar to the following.

library
├───application
│ ├───controllers
│ ├───layouts
│ ├───models
│ └───views
│ ├───filters
│ ├───helpers
│ └───scripts
│ └───index
└───public

Again we will require a controller for the client application, but unlike in the case of service, we will not use the controller class to map to a resource. We will use it as an entry point of the client application. The client application is a Web application. It should handle the requests from the users and provide the users with views. The controller of the client application would take care of this.

class IndexController extends Zend_Controller_Action {

List Books with GET

We will map the index action of IndexController to the request that displays the list of books.

function indexAction() {
$this->view->title = "Books";
$client = new Zend_Rest_Client('http://localhost'),
$response = $client->restGet('/rest/06/library/public/index.php/book'),
$this->view->books = simplexml_load_string($response- >getBody());
}

We are using a Zend_Rest_Client instance to access the service. We send a GET request to the book resource.

$client = new Zend_Rest_Client('http://localhost'),
$response = $client->restGet('/rest/06/library/public/index.php/book'),

We are expecting an XML document as the response for the GET request. We load the request body as a simple XML object instance and assign that to the books member of the view.

$this->view->books = simplexml_load_string($response->getBody());

The template for the book view is located in the libraryapplicationviewsscriptsindex sub folder. Since we are using the index action for listing books, the template for the view must be placed in a file named index.phtml. This is an MVC related convention used by the Zend Framework.

Here is the template for books view.

<h2>List of Books</h2>
<table>
<tr>
<th>Name</th>
<th>Author</th>
<th>ISBN</th>
</tr>
<?php foreach($this->books->book as $book) : ?>
<tr>
<td><?php echo $this->escape($book->name);?></td>
<td><?php echo $this->escape($book->author);?></td>
<td><?php echo $this->escape($book->isbn);?></td>
</tr>
<?php endforeach; ?>
</table>
<p><a href="<?php echo $this->url(array('controller'=>'index',
'action'=>'addBook'));?>">Add new book</a></p>

In the view, we loop through each book in the books XML structure that was passed on to the view from the controller and display all the book information in a table.

<?php foreach($this->books->book as $book) : ?>
<tr>
<td><?php echo $this->escape($book->name);?></td>
<td><?php echo $this->escape($book->author);?></td>
<td><?php echo $this->escape($book->isbn);?></td>
</tr>
<?php endforeach; ?>

And at the end of the page we display a link that would lead to a form that can be used to add a book.

When you access the client application's index URL, http://localhost/rest/06/library/public/index.php/index with the Web browser, you will see an output similar to the following.

List Books with GET

Add a Book with POST

Next, adding a book. For this, we add a new action addbook.

function addbookAction() {

When this action is requested by the user, by clicking on the Add new book link, as shown in the earlier screenshot, we display a form to the user and get the data for a new book.

$form = new BookForm();
$form->submit->setLabel('Add'),
$this->view->form = $form;

This will make sure that the book form would be displayed to the user. We use an instance of BookForm model to capture the data. The model script, bookForm.php is placed in the models sub-folder. BookForm class is inherited from Zend_Form class. And we capture the name, author and ISBN data for the new book using this form. Here is the PHP code for the BookForm model.

<?php
class BookForm extends Zend_Form
{
public function __construct($options = null)
{
parent::__construct($options);
$this->setName('book'),
$name = new Zend_Form_Element_Text('name'),
$name->setLabel('Name')
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator('NotEmpty'),
$author = new Zend_Form_Element_Text('author'),
$author->setLabel('Author')
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator('NotEmpty'),
$isbn = new Zend_Form_Element_Text('isbn'),
$isbn->setLabel('ISBN')
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator('NotEmpty'),
$id = new Zend_Form_Element_Hidden('id'),
$submit = new Zend_Form_Element_Submit('submit'),
$submit->setAttrib('id', 'submitbutton'),
$this->addElements(array($id, $name, $author, $isbn, $submit));
}
}
?>

We have three text form elements and a Submit button added to this form. The advantage of using Zend_Form here is that the data submitted would be accessible using simple methods in the controller. For the user, this form would be rendered through the view for the user to submit the data.

The view template corresponding to the action addbook would be named add-book.phtml and would be placed in libraryapplicationviewsscripts index folder. And the view template is very simple. All that you have to do is to render the form.

<?php echo $this->form ;?>

This will look on the browser like the following.

Add a Book with POST

Next, in the addbookAction function, we check if the request is a POST request.

if ($this->_request->isPost()) {
$formData = $this->_request->getPost();
if ($form->isValid($formData)) {
$client = new Zend_Rest_Client('http://localhost'),
$request = '<?xml version="1.0" encoding="UTF- 8"?><books>';
$request .= "<book><name>" . $form->getValue('name') . "</name>" .
"<author>" . $form->getValue('author') . "</author>" .
"<isbn>" . $form->getValue('isbn') . "</isbn></book>";
$request .= "</books>";
$response = $client->restPost('/rest/06/library/public/index.php/book', $request);
$this->_redirect('/'),
}
}

If the request is a POST, we access the form data posted.

$formData = $this->_request->getPost();

And we create a Zend_Rest_Client instance.

$client = new Zend_Rest_Client('http://localhost'),

Prepare the XML to be posted to the book resource URL.

$request = '<?xml version="1.0" encoding="UTF- 8"?><books>';
$request .= "<book><name>" . $form->getValue('name') . "</name>" .
"<author>" . $form->getValue('author') . "</author>" .
"<isbn>" . $form->getValue('isbn') . "</isbn></book>";
$request .= "</books>";

And we post that data to the book resource URL to create a new book.

$response = $client->restPost( '/rest/06/library/public/index.php/book', $request);

Here is the complete code for the add book action.

function addbookAction() {
$this->view->title = "Add New Book";
$form = new BookForm();
$form->submit->setLabel('Add'),
$this->view->form = $form;
if ($this->_request->isPost()) {
$formData = $this->_request->getPost();
if ($form->isValid($formData)) {
$client = new Zend_Rest_Client('http://localhost'),
$request = '<?xml version="1.0" encoding="UTF -8"?><books>';
$request .= "<book><name>" . $form->getValue('name') . "</name>" .
"<author>" . $form->getValue('author') . "</author>" .
"<isbn>" . $form->getValue('isbn') . "</isbn></book>";
$request .= "</books>";
$response = $client->restPost('/rest/06/library/public/index.php/book', $request);
$this->_redirect('/'),
}
}
}

List Members with GET

Listing members is quite similar to listing books.

We map the member listing URL to http://localhost/rest/06/library/public/index.php/index/members. This means that we need an action named members on the client application.

Here is the action function.

function membersAction() {
$this->view->title = "Members";
$client = new Zend_Rest_Client('http://localhost'),
$response = $client->restGet('/rest/06/library/public/index.php/member'),
$this->view->members = simplexml_load_string($response- >getBody());
}

And the view template is as follows:

<h2>List of Members</h2>
library clients, Zend REST classes library systemmembers, listing with GET<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
<?php foreach($this->members->member as $member) : ?>
<tr>
<td><?php echo $this->escape($member->first_name);?></td>
<td><?php echo $this->escape($member->last_name);?></td>
</tr>
<?php endforeach; ?>
</table>
<p><a href="<?php echo $this->url(array('controller'=>'index',
'action'=>'addMember'));?>">Add new member</a></p>
List Members with GETlibrary clients, Zend REST classes library systembooks, adding with POST

The above screenshot shows how the member listing looks when accessed with the browser.

Add a Member with POST

We would map the add member operation of the client application to the addMember action.

function addMember() {
$this->view->title = "Add New Member";
$form = new MemberForm();
$form->submit->setLabel('Add');
$this->view->form = $form;
if ($this->_request->isPost()) {
$formData = $this->_request->getPost();
if ($form->isValid($formData)) {
$client = new Zend_Rest_Client('http://localhost');
$request = '<?xml version="1.0" encoding="UTF- 8"?><members>';
$request .= "<member><first_name>" . $form->getValue('first_name') . "</first_name>" .
"<last_name>" . $form->getValue('last_name') . "</last_name></member>";
$request .= "</members>";
$xml = simplexml_load_string($request);
$response = $client->restPost('/rest/06/library/public/index.php/member', $request);
$this->_redirect('/index/members');
}
}
}

This action is similar to that of the book add operation, but we use a MemberForm model here.

Here is the member form to capture first name and last name of the new member.

<?php
class MemberForm extends Zend_Form
{
public function __construct($options = null)
{
parent::__construct($options);
$this->setName('member');
$name = new Zend_Form_Element_Text('first_name');
$name->setLabel('First Name')
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator('NotEmpty');
$author = new Zend_Form_Element_Text('last_name');
$author->setLabel('Last Name')
->setRequired(true)
->addFilter('StripTags')
->addFilter('StringTrim')
->addValidator('NotEmpty');
library clients, Zend REST classes library systemmembers, adding with POST$id = new Zend_Form_Element_Hidden('id'),
$submit = new Zend_Form_Element_Submit('submit'),
$submit->setAttrib('id', 'submitbutton'),
$this->addElements(array($id, $name, $author, $submit));
}
}
?>

And this is rendered through add-member.phtml view template.

<?php echo $this->form ;?>

And it would look like the following with the Web browser.

Add a Member with POST

Complete Client Application Controller

As we discussed in the above sections, client application supports adding and viewing book and member information. Here is the complete PHP source code for the client controller.

<?php
library clients, Zend REST classes library systemclient controller PHP source coderequire_once 'Zend/Rest/Client.php';
class IndexController extends Zend_Controller_Action {
function indexAction() {
$this->view->title = "Books";
$client = new Zend_Rest_Client'('http://localhost'),
$response = $client->restGet('/rest/06/library/public/index.php/book');
$this->view->books = simplexml_load_string($response->getBody());
}
function addbookAction() {
$this->view->title = "Add New Book";
$form = new BookForm();
$form->submit->setLabel('Add');
$this->view->form = $form;
if ($this->_request->isPost()) {
$formData = $this->_request->getPost();
if ($form->isValid($formData)) {
$client = new Zend_Rest_Client'(http://localhost'),
$request = '<?xml version="1.0" encoding="UTF- 8"?><books>';
$request .= "<book><name>" . $form->getValue('name') . "</name>" .
"<author>" . $form->getValue('author') . "</author>" .
"<isbn>" . $form->getValue('isbn') . "</isbn></book>";
$request .= "</books>";
$response = $client- >restPost('/rest/06/library/public/index.php/book', $request);
$this->_redirect('/'),
}
}
}
function membersAction() {
$this->view->title = "Members";
$client = new Zend_Rest_Client('http://localhost'),
$response = $client- >restGet('/rest/06/library/public/index.php/member');
$this->view->members = simplexml_load_string($response- >getBody());
}
function addMember() {
$this->view->title = "Add New Member";
library clients, Zend REST classes library systemclient controller PHP source code$form = new MemberForm();
$form->submit->setLabel('Add'),
$this->view->form = $form;
if ($this->_request->isPost()) {
$formData = $this->_request->getPost();
if ($form->isValid($formData)) {
$client = new Zend_Rest_Client('http://localhost'),
$request = '<?xml version="1.0" encoding="UTF- 8"?><members>';
$request .= "<member><first_name>" . $form->getValue('first_name') . "</first_name>" .
"<last_name>" . $form->getValue('last_name') . "</last_name></member>";
$request .= "</members>";
$xml = simplexml_load_string($request);
$response = $client->restPost('/rest/06/library/public/index.php/member', $request);
$this->_redirect('/index/members');
}
}
}
}
?>

Summary

In this chapter, we used the REST classes provided with the Zend Framework to implement the sample library system. The design of the service and client was covered along with the MVC concepts supported by the Zend Framework.

We discussed how resources map to the Model in MVC. Then we also discussed how HTTP verbs, when combined with resource URIs, map to the Controller in MVC.

We discussed how to combine Zend_Rest_Server with Zend_Controller to implement the business operations of the service.

We also explored how to use Zend_Rest_Client class to consume the services. And we implemented a sample web-based application using REST client to consume the REST service.

In the next chapter, we will discuss how to debug and troubleshoot

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.1.97