Learn DooPHP: High performance PHP framework

Create a simple To Do List in DooPHP – Part 2

Introduction

This tutorial will guide you through all the steps required to get started using DooPHP through the creation of a simple To Do List Application. The tutorial is split into a number of sections and you will need to read the guide from the begining in order to understand whats going on.

  • Part 1 – Getting Started
  • Part 2 – The Signup Form
  • Part 3 – User Authentication – Coming Soon
  • Part 4 – The To Do List – Coming Soon
  • Part 5 – Adding AJAX Functionality – Coming Soon

Creating the Signup Form

The first thing we need to do is to create a new controller which will handel registration tasks. For this we will create a new Controller with the name RegistrationController and this will handel all aspects of registration. Right now this will consist of a single action – Signup. Therefore we must create a new file public_html\protected\controller\RegistrationController.php and the contents of this file will be:

<?php
/* This is our new Controller which extends the DooPHP default DooController class */
class RegistrationController extends DooController {

	/* This array will hold data we want to expose to the templates we return to users later */
    protected $data = array();

	/* This function is called by DooPHP before we run an action */
	public function beforeRun($resouce, $action) {
		// Get the sites base url i.e. http://localhost/ (includes the / at the end)
		$this->data['app_url'] = Doo::conf()->APP_URL;
	}

    /* This function is our "Signup Action" which we will call when a user visits /signup/ */
    public function signup() {

		/* Set the pages title */
        $this->data['pagetitle'] = 'Signup';

        /* This will instruct DooPHP that we want to render the template file in public_html\protected\view\registration\signup.html */
        $this->view()->render('registration/signup', $this->data);
    }

}
?>

We now need to create the template file to be rendered when the signup action is called. Therefore go ahead and create a new file in public_html\protected\view\registration\signup.html and enter the following code into it:

<html>
    <head>
        <title>To Doo List Manager :: {{pagetitle}}</title>
    </head>
    <body>
        <h1>To Doo List Manager :: {{pagetitle}}</h1>

        <p>Please signup for an account to start using the To Doo
           List Manager. Registration is free to everyone</p>

        <form method="post">
            <label for="txt_username">Username</label>
            <input type="text" name="txt_username" /><br />

            <label for="txt_password">Password</label>
            <input type="password" name="txt_password" /><br />

            <label for="txt_name">Name</label>
            <input type="text" name="txt_name" /><br />

            <input type="submit" value="Signup" />
        </form>
        <p>
            Already registed for an account?
            <a href="{{app_url}}login/">Login Now!</a>
        </p>
    </body>
</html>

To help make managing our code easier I have opted to place the View’s inside a folder matching the names of the controllers so in this example our controller is called Registration and the action is signup so I have placed the view template in registration\signup.html but you can use what ever location you want (as long as its under the public_html\protected\view\ folder. Also all controllers must be defined as the controllers name followed by ‘Controller’.

Now we have created the controller, the action and a template to be rendered we will configure the routes so that a visit to /signup/ will result in the user visiting out signup page. To do this you first need to open up the following file public_html\protected\config\routes.conf.php. This file defines all the the routing rules used by DooPHP. Edit the file so it contains the following:

<?php
/* Original comments here... */
$route['get']['/signup'] = array('RegistrationController', 'signup');
?>

You should have already of removed all of the predefined routes earlier.

The above route instructs DooPHP that on any GET request to http://localhost/signup it should process the RegistrationControllers signup function. If the user request the page using a POST request we will not do anything for the time being at least.

We will also ensure that auto routing is turned off (the default). To do this open up public_html\protected\config\common.conf.php and check that the following line is commented out or set to FALSE:

//$config['AUTOROUTE'] = FALSE; // Settomg this to TRUE will enable auto routing

It is recommended that you leave auto routing turned off in DooPHP as the Routing engine provides us with a lot more options than a simple mapping of Controller/Action to a controller action (which is what the Auto Routing does). To find out more on DooPHP’s routing support please check out : Routes Guide and Routing Demo

If you have not yet saved all these changes do so. Once the changes have been saved you should now be able to open up your web browser and point it to http://localhost/signup/ and hopefully if you have configured everything correctly you will see the signup form :) If you see the form you can try clicking on the signup form and you will be given a 404 error because we have not yet setup a route to catch the POST /signup/ request.

Please note we have not yet setup a root mapping i.e. http://localhost/ to anything so you must add the /signup/ at the then of the url!

If you try clicking on the submit button you will see an error. Even though the form will send the user back to /signup/ it’s now sending a POST request and we have not set up a route to handel this. To pickup and handel the POST signup request we will add another route into the routes file so reopen public_html\protected\config\routes.conf.php and update it as follows:

<?php
/* Original comments here... */
$route['get']['/signup'] = array('RegistrationController', 'signup');
$route['post']['/signup'] = array('RegistrationController', 'signup_action');
?>

Here we have added in a POST request route mapping /signup to the signup_action of the RegistrationController. We have done this so we can seperate the logic of a get request (which requires us to just render a view) from the logic of trying to sign the user up. If we where using the same controller action for both the get and post requests though we could of used the ‘*’ option but this would also include PUT and DELETE requests and would look like this

$route['*']['/signup'] = array('RegistrationController', 'combined_signup_action');

Now we have told the routing engine to send users to the signup_action action we need to define it within the RegistrationController. We will need to do the following when the user requests the page:

  1. Make sure the user has sent a username, password and name with the form
  2. Check the username, password and name are not empty (We will be using no other validation for now)
  3. Ensure the username is not "Signup" (this will be a reserved word for later)
  4. Check no one else has already registed the username
  5. If we get this far we will register the user and then inform them it went okay
  6. If we had a problem at an earlier stage then we inform the user of the problem

The code to do this should be added after the signup function in public_html\protected\controller\RegistrationController.php

<?php
/* This is our new Controller which extends the DooPHP default DooController class */
class RegistrationController extends DooController {

	/* This array will hold data we want to expose to the templates we return to users later */
    protected $data = array();

    /* This function is called by DooPHP before we run an action */
	public function beforeRun($resouce, $action) {
		// Get the sites base url i.e. http://localhost/ (includes the / at the end)
		$this->data['app_url'] = Doo::conf()->APP_URL;
	}

	/* This function is our "Signup Action" which we will call when a user visits /signup/ */
    public function signup() {

		/* Set the pages title */
        $this->data['pagetitle'] = 'Signup';

        /* This will instruct DooPHP that we want to render the template file in public_html\protected\view\registration\signup.html */
        $this->view()->render('registration/signup', $this->data);
    }

	public function signup_action() {
		/* Set the pages title */
		$this->data['pagetitle'] = 'Signup';

		if (isset($_POST['txt_username']) && isset($_POST['txt_password']) && isset($_POST['txt_name'])) {

			$username = $_POST['txt_username'];
			$password = $_POST['txt_password'];
			$name = $_POST['txt_name'];

			// Save the username and password so we can use them in the template
			$this->data['username'] = $username;
			$this->data['name'] = $name;

			if (empty($username) || empty($password) || empty($name)) {
				// Assign an errorMsg to be picked up by the template
				$this->data['errorMsg'] = 'At least one field was empty';
			} else {
				if (strtolower($username) === "signup") {
					$this->data['errorMsg'] = 'The username Signup is not allowed';
				} else {

					// Load the User Model (in public_html\protected\model\User.php)
					Doo::loadModel('User');

					// Get a new User Model Instance
					$user = new User;

					// Assign the user object the requested username
					$user->username = $username;

					// Try and find a User with the specified username
					$result = Doo::db()->find($user, array('limit' => 1));

					if ($result == false) {
						// finish populating the users data
						$user->password = md5('salt' . $password . 'moresalt');
						$user->name = $name;

						// Try saving the result
						$result = $this->db()->insert($user);

						// Determin if this went okay and let user know
						if ($result == true) {
							// Set a success message we can pick up and use in the template
							$this->data['successMsg'] = 'Account Created!';
						} else {
							$this->data['errorMsg'] = 'Unknown error when trying to create account';
						}
					} else {
						$this->data['errorMsg'] = 'This username is already in use';
					}
				}
			}
		} else {
			$this->data['errorMsg'] = 'Not all fields where provided';
		}

		$this->view()->render('registration/signup', $this->data);
	}
}
?>

I have added comments into the code and hopefully you should be able to follow what is going on. I will however provide a bit more information on the database / model part of the code.

Before we carry out any Database related tasks we first ensure the user has provided us with a valid username, password and name. This means we do not have to load up the model related code until its actually needed! Once we know we need to do something with the database we load the User model class (line 41). After we do this we can create an empty User instance (line 44) which will create a default (blank) User object.

Now we have a blank ‘User’ we can specify some of the properties on this user. As we are looking to ensure no 2 users will have the same username we specify the username we have been provided by the user in the $user object (line 47). Now we have specified a parameter we can run a search to find any other users with the same username (line 50). We also limit the result to 1 as we do not care for any other users (also there should only be a maximum of one match anyway).

If no user is found then the find(…) function will return false and we know the username is avalaible for this user to use. Should a match be found then find(…) will return a details on the matching records. If the username is free then we can specify the users other details (lines 54 and 55). We md5 the password to help ensure the security of the users password, you should also use different salt values if you use this in the real world. Once the users settings have been set we can instruct DooPHP to insert the new record (line 58) and we will store the result of this so we can let the user know how things went (lines 61-66).

We will look at some other Model and Database functions later in this tutorial but for more further information you can also refer to the DooPHP Model Guide and the Database Demo.

You will also notice in the action’s code that we have set some extra $this->data['...'] values. We will use these inside the template file to let the user know how things went. However, you may have noticed that we do not set default values for all the the variables we plan to expose to our template file. For example only the errorMsg OR successMsg will be set. This means that when we come to render the template and use these variables php will raise a warning that these variables are undefined and this will cause errors to be reported if suc warnings are enabled. Therefore we will wrap access to these potentially undefined variables using the isset function.

We can now update our signup template file (public_html\protected\view\registration\signup.html) to also be used by the signup_action action as we want to show the user the same screen. The only difference being that we now need to inform the user of whats going on. Therefore we will now update the view template just mentioned to be as follows:

<html>
    <head>
        <title>To Doo List Manager :: {{pagetitle}}</title>
    </head>
    <body>
        <h1>To Doo List Manager :: {{pagetitle}}</h1>

        <p>Please signup for an account to start using the To Doo List Manager. Registration is free to everyone</p>

		<!-- if {{isset(errorMsg)}}==true -->
		<p class="error">Error: {{errorMsg}}</p>
		<!-- endif -->

		<!-- if {{isset(successMsg)}}==true -->
		<p class="success">Success: {{successMsg}}</p>
		<!-- endif -->

        <form method="post">
            <label for="txt_username">Username</label>
            <input type="text" name="txt_username" value="<!-- if {{isset(username)}}  -->{{username}}<!-- endif -->" /><br />

            <label for="txt_password">Password</label>
            <input type="password" name="txt_password" /><br />

            <label for="txt_name">Name</label>
            <input type="text" name="txt_name" value="<!-- if {{isset(name)}}  -->{{name}}<!-- endif -->" /><br />

            <input type="submit" value="Signup" />
        </form>
        <p>
            Already registed for an account?
            <a href="{{app_url}}login/">Login Now!</a>
        </p>
    </body>
</html>

We have made a number of changes to our signup template. The simplest additions are the new value="…" for the username and name input controls. Here we are specifing that we want to set the value of each text box to whatever data the user last submitted. When a user visits /signup/ then these values will not have been defined so these will be left blank. If the user has submitted the form though and included data in one or both of these input controls we now have the signup_action function set the values of these variables to those last submitted by the user. This means we can save the user having to reenter them. We do not however send back the password.

The other addition to the template are the and markers. This is just like a simple if statement checking to see if the variable has been defined and if so displaying its contents. We will see some more of these tags as we progress through the tutorial.

Assuming this has all worked out okay then you should now be able to signup to the site by visiting http://localhost/signup/. I would suggest you try submitting the form a couple of times to see how it reacts to different data being entered into the form. This includes submitting:

  • An empty form
  • A form with some missing data
  • The form with all fields completed and a username of signup
  • The form with all valid data eg. DemoUser, p@ssw0rd, Demo User
  • The form with a username already used eg. DemoUser and different (or the same) password and name

Assuming this has all worked okay you will have seen a variety of different messages appear depending on the content you submitted. If you are not seeing these messages and getting errors etc please check over what you have done and if your still having problems ask for some help in the fourms.

We will come back to the RegistrationController later but for now we will move onto User Authentication.


  • Hi Richard, thank you for your suggestion on the routing. I never thought of setting get/post as the same /signup url

  • that’s a nice trick for having the same URL :)

  • Richard, there are some remarks on a code in this part:

    1. In public function signup()

    We have not defined variables

    ====================================
    $this->data['errorMsg'] = ”;
    $this->data['successMsg'] = ”;
    ====================================

    Therefore we will see

    ====================================
    Notice: Undefined index: errorMsg in…
    ====================================

    2. In public function signup_action()

    ==================================================
    $this->data['The username Signup is not allowed'];
    ==================================================

    change to

    ==============================================================
    $this->data['errorMsg'] = ‘The username Signup is not allowed’;
    ==============================================================

    3. In signup.html

    =================================

    =================================

    change to

    =================================

    =================================

    The same with “successMsgs”.

  • Hi,

    I’m aware of the notices and raised an issue about this with leng and have a solution I plan to incorporate into the template (And this tutorial) covering undefined variables being used in the templates. If you have display_errors off…the page will render fine…the warning will just be logged.

    I’ll update the second error you have highlighted.

    Third thing is not showing up?

  • Richard,
    Point number three – the test for passableness of a code.
    Unfortunately strip_tags () eats a code of template variables…

    Following… Some browsers, are sensitive to options of routing.
    For example – Opera very long (3 – 4 sec) loads the form page
    at …/signup in that case when routing of a conclusion of an error
    is not defined.

    I have added in its most simple way:

    ——————————————————————
    $route [' * '] ['/error '] = array (’ RegistrationController ‘, ‘ signup ‘);
    ——————————————————————

    It has increased speed of loading page in ~ x90!

  • @Zares I have found the point you where making in part 3…the html comment tags are just causing it to be hidden right now. Will make the change this evening.

    Also I’ve only been testing with FireFox for this demo and was not aware of the routing issues in opera. I would suggest opening a thread in the forum if you feel this is caused by doophp (and not opera) so it can be looked into. I’ve not personally noticed any major issues with performance on my test setup here.

  • can’t wait to see the real app demo :D

  • I’ve just updated the tutorial to take care of most issues Zares pointed out earlier.

    The only one I have not looked at is defining extra routes for keeping performance up with Opera as I’ve not been able to test this myself and the ‘fix’ is not very good for a realworld application. You will want the error page pointing to an error page ;)

  • Last problem is solved by changing local “AppServ” to “WAMPSERVER”.

  • Richard can you switch to DooForm instead of making forms in HTML, I think your example would be great for showing how to work with forms if they have live example in it.

    If you need any help for DooForms, plz message me :)
    Tnx mate!

  • Milos, I had thought about using DooForms in this tutorial and at the time decided to stick to this so the tutorial would work with the 1.2 download release to keep things simple for users e.g. Not having to download from svn.

    However, I might well change this now as it seems likely that version 1.3 will be out before I complete all 5 tutorials (been rather busy)

    I had also thought about the option of later doing ‘alternative tutorials’ which would guide users through doing other things with this set of tutorials to either use replace features already covered which might for example be another tutorial on “How to adapt the To Do Tutuorial Demo to use DooForms” or include extensions to the demo app to add new functionality (again looking to use new features added to DooPHP). This would save having to write a whole new tutorial and therefore allow the focus to be on the ‘new feature’.

    Anyway I’ll try and update this tutorial and finish up part 3 asap. Any idea when you or Leng may get the DooAuth class added from over in the forums? I quite fancy using this for Authentication being covered in part 3.

    Richard

  • Tnx Richard, I will add soon one example of mine signup, register script with DooForms. But truth is its better not to use forms until they are officialy added.
    About auth class I think Leng is working on it, since I am working on translator class now.

  • zares said: “Opera very long (3 – 4 sec) loads the form page at …/signup in that case when routing of a conclusion of an error is not defined.”

    I don’t understand the second clause of the sentence and, subsequently, the entire sentence. What is the “conclusion of an error”?

    And why define $route [' * '] ['/error '] ? How would the browser know to load site/error page?

  • Great Work from you

  • hi i’m beginner in doophp and
    i see uri routing demo but i don’t understand
    $route[Request Method][Uri] = array( class, action method, [options, etc.])
    {[URI] part }
    in my application view file is templete.html and stored in view
    and in controller i had written

    class EmployeeController extends DooController {

    public function beforeRun($resouce, $action)
    {
    $this->data['app_url'] = Doo::conf()->APP_URL;
    }

    function index()
    {
    $data = array();
    $this->data['pagetitle'] = ‘Smit’;
    $this->render(’templete’, $this->data);

    // echo $form->renderc(’templet’);

    }

    public function add()
    {
    }…
    }
    and in config file i had written

    $route['*']['/'] = array(’EmployeeController’, ‘index’);
    $route['post']['/templete'] = array(’EmployeeController’, ‘add’);

    can u suggest me that should be the problem?

  • i’m not able to access add function

  • @smit – Please see my responses over at:
    http://www.doophp.com/forum/viewtopic.php?f=7&t=634&p=2853

    A quick note to anyone else: Please leave questions on the actual forum. More people will see it and be able to help you out :-) Feedback can always be posted in comments though ;)

  • thx Richard but i want to login in actual forum but conformation mail still not come on my account(since last two days)
    and that’s why i asked question here.anyway thax for suggestion.

  • @richard -
    my actual problem is i cant access add(). why???

  • ok you told abt all method but my first question was $route[Request Method][Uri]

    i know post method and get method but problem with URI part is that written for, from which page request comes from? just like for signup.html in your application

    i mean when user submit a form then it check in routes.config.php like $route['post']['/signup'] and goes to signup function in apropriate controller

    simillarly i had make two function index which called when $route['*']['/'] and add() it well be called when $route['post']['/templete'] is called

    here ['/templete'] is page which requeste coomes from?(well it’s not too complicated but i’n not able to explain such a easy thing sorry for that :)

  • Hi,

    I think from what you are saying above (its unclear i’m affraid) that you are having problems getting to the /add url. You do not specificy though if the “Add” page will be displaying your form OR if your index page contains the form. If the add page contains the form then you will not be accessing it using POST.

    If you look at the signup example above there are 2 definitions for /signup. The first one catches GET requests and will just render the form by calling a function in the signup controller. The second instance of /signup though is a POST handeler on the same URL. This picks up on POST form submits and calls a different function in the signup controller.

    If you are unsure whats going on here you might want to try just defining your /add as $route['*']['/add'] = … instead so it will work with both POST and GET.

    Have you tried following through the actual guide before setting out on your own application?

    Richard
    PS: The only reason I could see you not getting the confirmation email is that your spam filter has moved it to a junk folder (mine did) or you mistyped your email address.

  • looking forward for your part 3!

    your tutorials is very helpful!!!

  • yeah, part three, looking forward to it. ;)

  • Why i cannot acces http://localhost/signup

    its say 404 Not found ??

  • Hi,

    I would suggest starting a new thread in the forums if your having problems. Not easy to provide help here in comments.

    As a quick suggestion (reply in new forum post) did you have the default doophp homepage working from a clean install of DooPHP (before following this guide)? If not get that working first…it should work as is if your server is setup correctly. Otherwise if that worked then check your routes.php file AND check you php log file for any errors.

    Richard

  • Hi Henny,
    Try http://localhost/index.php/signup

    Ammar

  • Hi Rechard,

    When I regestered to this blog and the forum, I notes that the activation mail did not appear in my inbox, however when I have check the spam, I founded them.

    Ammar

  • Hi,

    Not much can be done with regard to the mails going into spam folders…I’ve just grown used to checking my junk folder whenever I am signing up to a new site and then just add them the address to my safe sender lists.

    Richard

  • Will we get Part 3 soon?

    Thank you for your efforts, great job!
    It was very usefull and help’s a lot when learning how to work with DooPHP ;)

  • a year later… auth etc. is still missing ;)