Demo – Zend Auth and Zend ACL (Part 3)

This part focuses on adding AJAX capabilities to the authentication form that we developed in parts 1 and 2. This is in my opinion the greatest benefit of the Zend Framework – It makes it so easy to extend and adapt the application because of its modular construct.

First and foremost, I would like to give credit to Quentin Zervaas (author of Practical Web 2.0 Applications with PHP) for writing about this in his exceptional book. I strongly recommend this book to anyone looking to understand the Zend Framework. In my opinion, It is THE most informative book on ZF, PHP and good programming practices.

The first change that we will make is to the AuthController class. We need a way to isolate our AJAX calls from a normal POST submit. ZF provides an easy way to do this using the isXmlHttpRequest() function on the request object. This function returns true if the request is an AJAX request.. false otherwise.

Our logic for interleaving ajax calls is : If the request is from XML, then just do a validate of the form fields and return the errors array – The JavaScript in the login form will read the ‘errors’ array, and will either display the errors or do a form submit (if the ‘errors’ array is empty).

$request = $this->getRequest();
$validate = $request->isXmlHttpRequest();



if ($validate)
{
$json = array(‘errors’=>$errors);
$this->sendJson($json);
}
else
{
$this->view->errors=$errors;
$this->_forward(‘login’);
}

We will make use of JSON (Javascript object Notation) to transmit data to the form. The Zend Framework provides the ability to easily convert PHP arrays to JSON objects. The sendJson() function is detailed below (note that this function is housed in the BaseController class since it can potentially be used by every form):

public function sendJson($data)
//change the header so as to send json data to accepting page
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender();
$this->getResponse()->setHeader(‘content-type’,’application/json’);
echo Zend_Json::encode($data);
}

Quite trivial really..

  • suppress the layout from displaying,
  • suppress the view from displaying,
  • change the header to ‘application/json’ and
  • finally call the Zend_Json::encode() method.

Now, we begin the Javascript part of the exercise. First step is to download the prototype library into the ‘js’ folder of the app. Then, add a reference to it (preferably) in the layout page in order to make it available globally.

<script type=”text/javascript” src=”<?php echo $this->baseUrl?>/js/prototype.js”> </script>

We will name our script as validateAjax.js. This script will make the ajax call and fill in the div sections that we setup for errors.

ValidateAjax = Class.create();
ValidateAjax.prototype={
form:null,
initialize:function(form)
{
this.form=$(form);
this.form.observe(‘submit’,this.onSubmit.bind(this));
},
resetErrors:function()
{
this.form.getElementsBySelector(‘.error’).invoke(‘hide’);
},
showErrors:function(key,val)
{
var formElement = this.form[key];
var container = formElement.up().down(‘.error’);
if (container)
{
container.update(val);
container.show();
}
},
onSubmit:function(e)
{
Event.stop(e);
var options={
parameters:this.form.serialize(),
method:this.form.method,
onSuccess:this.onFormSuccess.bind(this)
}
this.resetErrors();
new Ajax.Request(this.form.action, options);
},
onFormSuccess:function(transport)
{
var json = transport.responseText.evalJSON(true);
var errors = $H(json.errors);
if (errors.size()>0)
{
this.form.down(‘.error’).show();
errors.each(function(pair){
this.showErrors(pair.key, pair.value);
}.bind(this));
}
else
{
this.form.submit();
}
}
};

The above javascript uses the prototype library to create a class that handles the validation. The constructor (initialize) takes as input the id of the form and establishes an event listener on the submit method (Note that this IS the recommended way to capture events. The old way was to invoke the script on window.load. If true separation of javascript from the HTML is desired, the event capture should live outside the HTML file)

The ‘resetErrors’ method gets all the elements marked with “class=error” and invokes the ‘hide’ method on each block

The showErrors method is responsible for displaying the error messages within the appropriate DIV section. This is important .. The display process works on the following premises:

  1. The errors array returns json in the format “fieldname”:”error message”
  2. A reference to the form element  is obtained using the javascript square bracket [] notation.
  3. It is assumed that the error div is inside the div that displays the field (Once the form element is obtained, go up() to the parent div, then move down() to the actual div tagged with the error class.)

The onSubmit function is the event handler for the submit event. Invoke the Ajax.Request method. Note that the form.action is used instead of the actual URL. This is to promote reuse of this js file. This file is now capable of handling the AJAX validation of ANY form that is built with the divs in the prescribed format.

The onFormSuccess is the function that is executed on success of our asynchronous call. The responseText from the server contains the JSON formatted array that looks like (I used a simple alert message – alert(transport.responseText); to display this)

image

The evalJSON(true) call evaluates the JSON string and returns an object. The ‘true’ parameter is a security measure and is a good practice to make sure that there a
re no XSS (cross-site scripting issues)

In case there are multiple errors, they will all be grouped under errors. The $H() prototype function is used to convert the errors object into an array.

In case there are errors (the array size is > 0), then the errors are displayed in their appropriate div sections, and if there are no errors, the form is submitted using the form.submit javascript function.

The final part of the puzzle is including and calling the javascript object that we constructed form the login web page. The complete login.phtml page is shown below:

<h1>Login</h1>

<div class=”error”> <?php if (isset($this->errors[‘auth’])) echo $this->errors[‘auth’]?> </div>
<p>Please log in here</p>
<form method=”post” id=”login” action='<?php echo $this->baseUrl?>/auth/identify’>
<div>
<label>Username</label>
<input type=”text” name=”username” value=””/>
<div class=”error”> <?php if (isset($this->errors[‘username’])) echo $this->errors[‘username’]?> </div>
</div>
<div>
<label>Password</label>
<input type=”password” name=”password” value=”” />
</div>
<div>
<input type=”submit” name=”login” value=”Login” />
</div>
</form>
<script type=”text/javascript” src=”<?php echo $this->baseUrl?>/js/ValidateAjax.js”></script>
<script type=”text/javascript”>
new ValidateAjax(‘login’);
</script>

Note that the javascript inclusion is at the END of the webpage.. this is to insure that the DOM is fully loaded before calling the ValidateAjax function (also, for SEO purposes, it is best to add JS at the end of HTML).

There! We now have a complete login/authentication form with Ajax functionality built using the Zend Framework.

For details about my ACL implementation, check out this post

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s