Testing for unique value during form validation

Let’s talk about what happens when a user signs up for a new account. He fills in his nickname, e-mail address and password and clicks Register. When validating the e-mail address you need to check for at least three things:

  1. the user provided one
  2. the syntax is all right – the e-mail is formally valid and can in fact exist (which doesn’t mean it really exists)
  3. the address hasn’t been used yet for some other account

So far not very difficult.

The tricky part comes when you allow the user to edit his profile. He can change any of the three values. When he submits the edit form the situation is one step more difficult than during registration. The e-mail address has in fact already been used – for the very user that is submitting the form. That is not the tricky part. The fun is how to get the user id when validating his e-mail address.


Without further ado, here’s the code:
(using NotORM initiated in BaseModel constructor)

  1.  
  2. class UserPresenter extends BasePresenter {
  3.   function createComponentAddEditForm($name) {
  4.     …
  5.     $form->addText(’email’, ‘E-mail:’)
  6.       ->setRequired(‘Please provide your e-mail address.’)
  7.       ->addRule(NFORM::EMAIL, "Sorry, this doesn’t seem to be a valid e-mail address.")
  8.       ->addRule(‘BaseModel::uniqueEmail’, ‘This e-mail is already registered.’);
  9.  
  10.     $form->addHidden(‘id’);
  11.     …
  12.   }
  13. }
  14.  
  15. abstract class BaseModel extends NObject {
  16.   static function uniqueEmail(NTextBase $control) {
  17.     // —————————————————————-
  18.     $email = $control->getValue();
  19.     $values = $control->getParent()->getValues();
  20.    
  21.     $me = new self;
  22.     $queryBase = $me->db->users->where(’email’, $email);
  23.    
  24.     // Test for any record with given e-mail address
  25.     if (empty($values[‘id’])) {
  26.       return ($queryBase->count("*") == 0);
  27.     }
  28.    
  29.     // Test for any record with given address – that isn’t this record
  30.     return ($queryBase->where(‘NOT id’, $values[‘id’])->count("*") == 0);
  31.   }
  32.  

Tags:

2 Responses to “Testing for unique value during form validation”

  1. Why is the `uniqueEmail` method in class BaseModel? I’d like more

    ->addRule(callback($usersModel, ‘uniqueEmail’), ‘This e-mail is already registered.’);

  2. True. It can be in any model/class. In my case, I used this validation for more than one model (not visible in the code above) so I placed it in a shared BaseModel.

    Thanks for the example of using callback with an instance of some class. If you happen to need an instance anyway, in your component/form factory then you can use it for the callback and get rid of instantiating the object in the method itself ($me = new self).

Leave a Reply