I’m going to create a simple user registration form with a confirm password field!
Features of this implementation:
- Uses AuthComponent
- Confirm password field
- Ensures unique usernames
- User feedback if any errors occur
- Remember me feature (cookies)
Prerequisites
I assume you have a database structure similar to the following:
Note: CakePHP automagically updates the created and modified fields.
App Controller
Place the following code in /app/controllers/app_controller.php
<?php
class AppController extends Controller {
var $components = array( 'Auth', 'RememberMe' );
function beforeFilter() {
$this->Auth->logoutRedirect = '/';
$this->Auth->loginRedirect = '/';
$this->RememberMe->check();
}
}
?>
The two lines $this->Auth->log*** determine where the user is directed after they login. Another option (instead of ‘/’), is $this->referer(). That will bring the user back to the page they were just at (sweet)!
What’s this remember me crap though?
Remember Me
This guy wrote an excellent component that you can simply pop in your /app/controllers/components folder and you’re ready to go.
The Form
Place the following code in /app/views/users/register.ctp
<?php
echo $form->create('User', array( 'url' => array( 'action' => 'register' ) ) );
echo $form->input('username',
array('after' => $form->error('username_unique', 'The username is taken. Do try again!' ) ) );
echo $form->input('password');
echo $form->input('confirm_password', array( 'type' => 'password' ) );
echo $form->input('email');
echo $form->end('Sign-up');
?>
The only tricky piece right now should be in the username piece. In the second parameter, I specified ‘after’ that associates with a $form->error(…). The username_unique property is something I will define in the User Model shortly.
Users Controller
Place the following code in /app/controllers/users_controller.php inside your UsersController class.
function beforeFilter()
{
parent::beforeFilter();
// This allows our login() function to execute
$this->Auth->autoRedirect = false;
}
// Note, this function is called AFTER Auth has handled it, but BEFORE redirecting to the afterLogin redirect specified (because of the flag we set in beforeFilter)
// Basically, this means the password field is already encrypted and the session was already created. Easy! =)
function login()
{
// Check if Auth got a hold of it and created a session
if( $this->Auth->user() )
{
// If form data was sent, set the remember_me cookie IF they checked the box
if( isset( $this->data ) )
{
if( empty( $this->data['User']['remember_me'] ) || $this->data['User']['remember_me'] == 0 )
{
$this->RememberMe->delete();
}
else
{
$this->RememberMe->remember(
$this->data['User']['username'],
$this->data['User']['password'] );
}
$this->Session->setFlash('You are logged in!');
}
// Redirect to our loginRedirect page specified
$this->redirect($this->Auth->redirect());
}
}
function logout(){
// Set logout message and call auth component's logout
$this->Session->setFlash('You are logged out! Good bye!');
// Delete the cookie
$this->RememberMe->delete();
// Call Auth to delete our session
$this->redirect($this->Auth->logout());
}
function register() {
if ( isset($this->data) )
{
// Set group to regular user
// NOTE: This may be different for you
$this->data['User']['group_id'] = 2;
$this->User->create();
if ($this->User->save($this->data))
{
$this->Session->setFlash( 'Thank you for registering!' );
$this->redirect(array('action'=>'index'));
}
else
{
// Make the password fields blank
unset($this->data['User']['password']);
unset($this->data['User']['confirm_password']);
$this->Session->setFlash('An error occurred, try again!');
}
}
}
Excellent! Now we just have one more step… let’s validate the user’s input.
The User Model
Place the following code in /app/models/user.php
<?php
class User extends AppModel {
var $name = 'User';
// Prevent the input from having an id
// Username: MUST be alphanumeric
// Password: We specify a function that returns a bool value
var $validate = array(
'id' => array(
'rule' => 'blank',
'on' => 'create'
),
'username' => array(
'rule' => 'alphanumeric',
'message' => 'Please enter a valid username',
'required' => true
),
'password' => array(
'rule' => array('confirmPassword', 'password'),
'message' => 'Passwords do not match',
'required' => 'true'
),
'confirm_password' => array(
'rule' => 'alphanumeric',
'required' => 'true'
),
'email' => array( 'email',
array( 'rule' => array('email'),
'message' => 'Please enter a valid email!' )
),
'group_id' => array( 'numeric' )
);
function confirmPassword($data)
{
// We must manually hash the second piece in the same way the AuthComponent would
// if they match, return true!
if ($data['password'] == Security::hash(Configure::read('Security.salt') . $this->data['User']['confirm_password'])) {
return true;
}
// hashed passwords did NOT match
return false;
}
// Check if the username already exists by doing SELECT COUNT(*) FROM users WHERE username = 'your_username'
function beforeValidate()
{
if( !$this->id )
{
if( $this->findCount( array('User.username' => $this->data['User']['username'] ) ) > 0 )
{
// If any rows are found, send an error and call it 'username_unique'
// In our view, we can check for this by doing $form->error('username_unique','Not Unique Username!!!')
// As specified in the view code I placed above
$this->invalidate('username_unique');
return false;
}
}
return true;
}
// Associations
var $belongsTo = 'Group';
}
?>
Great!
Conclusion
There you have it. Something that may take you places in your projects (hopefully). Any questions?