0
votes

Database Structure

I have two tables, users and nicks. In users table I have a field username and in nicks table I have a field nick_name

There is a hasMany association between users and nicks

    public $hasMany = array(
        'Nick' => array(
            'className' => 'Nick',
            'foreignKey' => 'user_id',
            'dependent' => true
        )

    );

In the User model I am validating to allow only unique username during registration by

            'username must be unique' => array(
                'rule' => 'isUnique',
                'message' => 'username is already taken'

            )

but I also don't want to allow users to register any previously used nick names as their username. for that.

            'somebody use that name as a nickname' => array(
                'rule' => 'checkNickName',
                'message' => 'That name is already in use'
            )

and

    public function checkNickName(){
        $nick2 = $this->find('all');
        $nickNames = array();
        foreach($nick2 as $name2){
            foreach($name2['Nick'] as $name1){
                array_push($nickNames,strtolower($name1['nick_name']));
            }

        }

        $username = strtolower($this->data['User']['username']);
        return in_array($username,$nickNames);

    }

But that's not working. What should I to make it work?

4

4 Answers

2
votes

If I understand correctly, you want to ensure the username is unique but also that the username has not been used as a nickname by anybody also, so why not use something like this?

public function checkNickIsUnique($check = array()) {
    $value = array_values($check);

    $nicknameExists = $this->Nick->find('count', array(
        'conditions' => array(
            'Nick.nick_name' => $value[0]
        )
    ));

    return ($nicknameExists > 0) ? false : true;
}

And in your user model, assuming it's directly related to nick, have this in the validation.

public $validate = array(
    'username' => array(
        'isUnique' => array(
            'rule' => 'isUnique',
            'message' => 'That username has already been taken'
        ),
        'checkNickIsUnique' => array(
            'rule' => array('checkNickIsUnique'),
            'message' => 'Your username has already been taken as a nickname'
        )
    ),
);

All it's doing is passing the value from the validation to the method, and checking if that value exists as a nickname within the nicks table, if it does it fails validation otherwise it passes.

0
votes

First find the nicknames.

$nick2 = $this->Nick->find('all');

Then the result array will be

nick2 = array(
    0    => array(                       //first foreach
        'Nick' => array(
             nickname => 'TEST'
             )
         )
     )

so remove the second foreach and save the value as using $name2['Nick']['nickname']

public function checkNickName(){
    $nick2 = $this->Nick->find('all');
    $nickNames = array();
    foreach($nick2 as $name2){
         array_push($nickNames,strtolower($name2['Nick']['nick_name']));
    }

    $username = strtolower($this->data['User']['username']);
    return in_array($username,$nickNames);

}
0
votes

just need use the username of the input form. in your view example:

<?php echo $this->Form->input('username', array(
                              'label' => array(
                                'text' => 'Provide your username'
                              )
                              )); ?>

and in your model you need change

      'username' => array(
        'nonEmpty' => array(
            'rule' => array('notEmpty'),
            'message' => 'not empty please',
            'allowEmpty' => false
        ),
        'unique' => array(
            'rule'    => array('isUniqueUsername'),
            'message' => 'username is already taken'
        ),
       ),


        'nickname' => array(
           'nonEmpty' => array(
              'rule' => array('notEmpty'),
              'message' => 'not empty',
              'allowEmpty' => false
            ),
           'unique' => array(
              'rule'    => array('checkNickName'),
              'message' => 'That name is already in use'
            )
        )

your condition example for is validation is unique user name, use this:

EDIT

  'username' => array(
    'unique' => array(
        'rule'    => array('checkNickName'),
        'message' => 'username is already taken'
    ),
   ),

in your function:

public function checkNickName($check) {
  $this->loadModel('Nick');
  $username = $this->Nick->find(
      'first',
      array(
          'fields' => array(
              'Nick.id',
              'Nick.nickname'
          ),
          'conditions' => array(
              'Nick.nickname' => $check['username']
          )
      )
  );

  if(!empty($username)){
      if($this->data[$this->alias]['id'] == $username['User']['id']){
          return true;
      }else{
          return false;
      }
  }else{
      return true;
  }
}
0
votes

A better solution that doesn't require tons of additional code is this:

        $valid = $this->User->saveAll($this->request->data, array(
            'atomic' => false,
            'validate' => 'only'
        ));
        debug($valid);

It will validate the record and all other records attached to it as well, no more code required, just make sure you have the isUnique rule in your associated nicknames model. It will as well invalidate the correct fields in your form.