In the previous parts, we have seen how to setup the environment (Part 1), start the project (part 2), create the model layer and list the database contents (Part 3). In this fourth part, we will describe Zend_From and how to insert, edit and delete data from the database.
Creating a form using Zend_Form
To create a form, we will use the Zend_Tool and edit the created file afterwards. So, to create the empty form class, execute:
1 | zf create form UserRegistration |
This command will create the directory application/forms/ with the class file UserRegistration.php. Let’s open that file and insert the elements. The source code will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | <?php class Application_Form_UserRegistration extends Zend_Form { public function init() { // Set the method for the display form to POST $this->setMethod('post'); $name = new Zend_Form_Element_Text('name'); $name->setLabel('Full name') ->setRequired(true) ->addFilter('StringTrim') ->addFilter('StripTags') ->addValidator('Regex', false, array('/[a-zA-Z ]$/')); // Only chars from a-z and spaces $this->addElement($name); $email = new Zend_Form_Element_Text('email'); $email->setLabel('Email') ->setRequired(false) ->addFilter('StringTrim') ->addFilter('StripTags') ->addValidator('EmailAddress'); $this->addElement($email); $username = new Zend_Form_Element_Text('username'); $username->setLabel('Username') ->setRequired(true) ->addFilter('StringTrim') ->addFilter('StripTags') ->addValidator('StringLength', false, array(3, 20)) ->addValidator('Regex', false, array('/[a-zA-Z0-9_.-]$/')); // Only chars from a-z, numbers, underline, dot and dash $this->addElement($username); $password = new Zend_Form_Element_Password('password'); $password->setLabel('Password') ->setRequired(true) ->addFilter('StringTrim') ->addValidator('StringLength', false, array(6, 50)); $this->addElement($password); $password_confirmation = new Zend_Form_Element_Password('password_confirmation'); $password_confirmation->setLabel('Password Confirmation') ->setRequired(true) ->addFilter('StringTrim') ->setIgnore(true) ->addValidator('StringLength', false, array(6, 50)); $this->addElement($password_confirmation); // Add a captcha $captcha = new Zend_Form_Element_Captcha('captcha', array ( 'label' => 'Please type the words displayed below:', 'captcha' => array ( 'captcha' => 'Figlet', 'wordLen' => 6, 'timeout' => 300 ) ) ); $this->addElement($captcha); // And finally add some CSRF protection $hash = new Zend_Form_Element_Hash('csrf'); $hash->setIgnore(true); $hash->removeDecorator('label'); $this->addElement($hash); // Add the submit button $this->addElement('submit', 'submit', array( 'ignore' => true, 'label' => 'Register', )); } } |
We have added eight elements to the form that will be inputs to insert information about the user: name, email, username, password, password confirmation, captcha (to prevent spam submissions), CSRF protection token and a submit button.
Next, we will create an action in the UserController, called registerAction, which wil process the form. To create it, as well as a view script, type the following command:
1 | zf create action register Users |
Now that we have the form and also already have the save method in your mapper, let’s add some logic into our user controller’s register action. Basically we will check the request type, validate the posted data and save it. The code will be like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | public function registerAction() { // create the login form object $form = new Application_Form_UserRegistration(); $form->setAttrib('id','loginForm'); // verify if it is a post if ($this->getRequest()->isPost()) { // validate the form and save user if ($form->isValid($this->getRequest()->getPost())) { // verify is passwords match if($form->getElement('password')->getValue() != $form->getElement('password_confirmation')->getValue()) $form->getElement('password')->setErrors(array('Passwords don\'t match')); else { $user = new Application_Model_User($form->getValues()); // set status of password and registration $user->setPasswordStatus(Application_Model_User::ENUM_PASSWORD_STATUS_DEFINITIVE); $user->setRegistrationStatus(Application_Model_User::ENUM_REGISTRATION_STATUS_ACTIVE); $mapper = new Application_Model_UsersMapper(); // save user in the database if ($mapper->save($user)) { $this->_redirect('/users'); } else { // redirect to edit same content again $this->_redirect($this->getRequest()->getPathInfo()); } } } } // set the form in the view $this->view->form = $form; } |
The last step to conclude the registration is to edit the view script (application/views/scripts/users/register.phtml) and add the form to the view.
1 2 | <h2>Register user</h2> <?php echo $this->form; ?> |
Now browse to “http://zfguide/user/register” and check if it is being displayed and working correctly. In the steps bellow we will discuss several improvements to be done in our implementation.
Adding verification to check if the username has already been taken
Usually, usernames are unique in the systems. We will now add a verification to avoid duplicate usernames in our system. To do that, what we have to do it to add a function findByUsername in the mapper and implement the verification in the controller. So, in the mapper, add the following function:
1 2 3 4 5 6 7 8 9 10 11 | public function findByUsername($username) { $where = $this->_dbTable->getAdapter()->quoteInto(Application_Model_DbTable_Users::COL_USERNAME . ' = ?', $username); $resultSet = $this->_dbTable->fetchAll($where); $entries = array(); foreach ($resultSet as $row) { $entry = new Application_Model_User(); $entries[] = self::mapToModelObject($row); } return $entries; } |
Next, in the controller, add the verification:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | . . . $mapper = new Application_Model_UsersMapper(); // verify if the username has been used if(count($mapper->findByUsername($form->getElement('username')->getValue())) > 0) // send message to interface warning the user about an already used username $form->getElement('username')->setErrors(array('Username already taken!')); else { // save user in the database if ($mapper->save($user)) { $this->_redirect('/users'); } else { // redirect to edit same content again $this->_redirect($this->getRequest()->getPathInfo()); } } . . . |
Now your controller always check if the username is already taken.
Improving Security of stored passwords by adding salt
An interesting security feature to be added is to add a “salt” to the password. Basically it consists on adding a random value to the password before hashing it. This improves security because even when we have 2 passwords that are equal, they will generate different hashes due to a different salt value. So, let’s create a class to handle this. Go to library folder and create the following path and file: /library/Mcc/Security/PasswordHandler.php. The source code of this class will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php /** * Class to handle passwords, adding salt to it. */ class Mcc_Security_PasswordHandler { public static function createPasswordWithSalt($plainText, $saltLength = 4) { $salt = substr(md5(uniqid(rand(), true)), 0, $saltLength); return $salt . sha1($salt . $plainText); } public static function verifyPasswordWithSalt($plainText, $encPassword, $saltLength = 4) { $salt = substr($encPassword, 0, $saltLength); $password = substr($encPassword, $saltLength); $result = sha1($salt . $plainText); return ($result == $password); } } |
Now we need to add this custom library to the path, otherwise other application will not find it. To add this new library to the path, open the Bootstrap.php and add the following function:
1 2 3 4 5 6 7 8 9 10 11 | protected function _initAutoload() { $moduleLoader = new Zend_Application_Module_Autoloader(array( 'namespace' => '', 'basePath' => APPLICATION_PATH)); $autoloader = Zend_Loader_Autoloader::getInstance(); $autoloader->registerNamespace(array('Mcc_')); return $moduleLoader; } |
To conclude our changes, we need to “apply” the salt to the password typed in the password field before saving it. To do that, add the following lines just after the lines that we have set the registration and password status:
1 2 | // calculate password hash with salt $user->setPassword(Mcc_Security_PasswordHandler::createPasswordWithSalt($form->getElement('password')->getValue())); |
And that’s it !! now your passwords are stored in a more secure way.
Adding notification messages using Flash Messenger helper
To conclude our improvements to our form, let’s add a message that gives a feedback to the user when the data is added to the database (after redirecting to users/index). Zend Framework offers a useful helper called flashMessenger which prints a message on the screen, and just once. So, let’s add a confirmation message after we save the contents to the database. The UsersController.php will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | . . . if ($mapper->save($user)) { $this->_helper->FlashMessenger->addMessage('Record saved!'); $this->_redirect('/users'); } else { // redirect to edit same content again $this->_helper->FlashMessenger->addMessage('Error saving record!'); $this->_redirect($this->getRequest()->getPathInfo()); } . . . |
As you could see we added the confirmation messages and also the send the messages to the view by using the postDispatch method. Since the getMessages returns an array, you will have to handle it in the view. A way to simplify it is by creating a view helper in our library. So, create a folder in /library/Mcc/View/Helper and add the FlashMessages.php file there:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php /** * Class to print the flash messages in the view */ class Mcc_View_Helper_FlashMessages extends Zend_View_Helper_Abstract { public function flashMessages() { $messages = Zend_Controller_Action_HelperBroker::getStaticHelper('FlashMessenger')->getMessages(); $output = ''; if ( count($messages) > 0 ) { $output .= '<div id="flash-messages">'; $output .= '<ul>'; foreach ($messages as $message) $output .= '<li>' . $message . '</li>'; $output .= '</ul>'; $output .= '</div>'; } return $output; } } |
To conclude the view helper setup, open the Bootstrap.php and add the following line in the _initViewHelpers() function:
1 | $view->addHelperPath('../library/Mcc/View/Helper','Mcc_View_Helper_'); |
At last, let’s recover the messages in the view and use the helper we created. Open the /application/layouts/scripts/layout.phtml and call the helper like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php echo $this->doctype(); ?> <html> <head> <?php echo $this->headTitle(); ?> <?php echo $this->headMeta(); ?> <?php echo $this->headLink(); ?> <?php echo $this->headLink()->appendStylesheet($this->baseUrl() . '/styles/default.css'); ?> <?php echo $this->headScript(); ?> </head> <body> <div id="header"> <h1>ZF Basics</h1> </div> <div id="content"> <?php echo $this->flashMessages(); ?> <?php echo $this->layout()->content; ?> </div> </body> </html> |
And that’s it, now open your browser and add a new user. When you are redirect to /users/index will you see the message
Removing registers from the database
The last item of this part of our series will describe how to delete a record from the database. This is a very simple process. We will basically create a new action called deleteAction and add a new column in the users list (index.phtml) that will include a delete icon.
So, type the following command:
1 | zf create action delete Users |
And add the following code to the deleteAction function in the UsersController:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public function deleteAction() { if($this->getRequest()->getParam('id') != null) { $mapper = new Application_Model_UsersMapper(); // delete user that has the specified id if($mapper->delete($this->getRequest()->getParam('id'))) { $this->_helper->FlashMessenger->addMessage('Record Removed!'); } else { $this->_helper->FlashMessenger->addMessage('Error removing record!'); } } // redirect to the listing $this->_redirect('/users'); } |
Basically this function gets the “id” parameter and deletes the user who has this id. And also use the flash messenger to notify the results of this action.
Now open the index.phtml in the /application/views/scripts/users/index.phtml and let’s add the column which will link to the delete action. The final code will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | Registered Users: <br /> <p><?php echo $this->paginator->getTotalItemCount() . " registers. Showing page " . $this->paginator->getCurrentPageNumber() . " of " . $this->paginator->count(); ?></p> <?php if (count($this->paginator)): ?> <table> <tr> <th>Name</th> <th>Email</th> <th>Login</th> <th>Registration Date</th> <th>Last Login</th> <th>Actions</th> </tr> <?php foreach ($this->paginator as $user): ?> <tr> <td> <?php echo $this->escape($user->getName()); ?> </td> <td> <?php echo $this->escape($user->getEmail()); ?> </td> <td> <?php echo $this->escape($user->getUsername()); ?> </td> <td> <?php echo $this->escape($user->getRegistrationDate()); ?> </td> <td> <?php echo $this->escape($user->getLastLogin()); ?> </td> <td> <a href="<?php echo $this->url( array('controller' => 'users', 'action' => 'delete')); ?>/id/<?php echo $user->getId(); ?>">delete</a> </td> </tr> <?php endforeach; ?> </table> <?php endif; ?> <?php echo $this->paginationControl($this->paginator, 'Sliding', 'pagination_control.phtml'); ?> |
And now we can delete users by clicking on “delete”
This concludes this part of the series. The next part will demonstrate how to add menus to our application using Zend_Navigation.
Popularity: 44% [?]
Related posts:
- Part 3: Creating the model, database and retrieving values from them – A not so quick quickstart to Zend Framework
In the 3rd part of our series, we will now start implementing a user’s management... - Part 2: Creating your project – A not so quick quickstart to Zend Framework
In this second part (click here to check the previous part) of this series we... - Part 1: Setting Up – A not so quick quickstart to Zend Framework
Welcome to a series of tutorials to introduce the most important features of Zend Framework.... - How to setup Apple’s Mail.app to have a great integration with Gmail
Gmail is an excellent webmail. It has great features, brilliant performance and amazing usability. However, there...





