Skip to content
This repository has been archived by the owner on Jul 16, 2023. It is now read-only.

Unique validation for create and edit #94

Open
asivaneswaran opened this issue Aug 25, 2013 · 7 comments
Open

Unique validation for create and edit #94

asivaneswaran opened this issue Aug 25, 2013 · 7 comments

Comments

@asivaneswaran
Copy link

Hey,

I was just wondering how I can use the unique validation on my fields in create and edit cases?

For example, right now, let's say the username field is unique. But when someone tries to edit their profile without touching their username, it returns username already taken....

Thanks,
Ara

@markalanevans
Copy link

+1. Same issue here. This person came up with a solution, but this should be a default.

@asivaneswaran
Copy link
Author

Thanks a lot!

Yeah, it would be really awesome if it was there by default!

@asivaneswaran
Copy link
Author

Hey,
I just started implementing this and I am kind of a noob...

Where do I create this class? In my model folder?

@markalanevans
Copy link

One way to do it is to create a class that all of your models extend.

File: /app/models/AppModel.php

<?php
use LaravelBook\Ardent\Ardent;

class AppModel extends Ardent{
    //Ardent / Modification for validation.
    public function validate( array $rules = array(), array $customMessages = array() ) {

        //If custome rules are not being applied, then use default rules in class
        if (empty($rules)){
            $rules = $this->ignoreCurrentRecordForUnique ();
        }
        return parent::validate( $rules , $customMessages ) ;

    }

    //Ardent / Modification for validation.
    //If an item is marked as unique, the rule should change to the format: 'unique:users,email_address,10'  where 10 is the id of the record in quesion.
    protected function ignoreCurrentRecordForUnique (){
      $rules = static::$rules ;
      if ($this->exists && array_key_exists( 'id' , $this->attributes)) {
         foreach ( $rules as $field => &$rls ) {
            if (is_string($rls)) {
               $rlsreplace = '';
               $rlsarray =  explode('|', $rls);
               foreach ($rlsarray as $onerl) {
                  if (strpos($onerl, ':') !== false) {
                     list($rule, $parameter) = explode(':', $onerl, 2);
                     $parameters = str_getcsv($parameter);
                     // if rule is 'unique' and table is same as field table being validated  and ignore parameter is not already set
                     if ($rule == 'unique' && (count  ($parameters) == 2 || count ($parameters) == 1 ) &&  $parameters[0] == $this->getTable()) {
                        if (count ($parameters) == 1)
                           $onerl .= ',' . $field . ',' . $this->attributes['id'];
                        else
                           $onerl .= ',' . $this->attributes['id'];
                     }
                  }
                  if ($rlsreplace != '')
                     $rlsreplace .= '|';
                  $rlsreplace .= $onerl;
               }
               $rls = $rlsreplace;
            }
         }
      }
      return $rules;
    }
}
...
?>

Then

In each of your model classes, if you have for example a User model

File: /app/models/User.php

class User extends AppModel{

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    //Allow for softdelete
    protected $softDelete = true;

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = array('password');

    public $autoPurgeRedundantAttributes = true;


    public static $rules = array(
        'email'                 => 'required|email|unique:users',
        'password'              => 'required|alpha_num|between:4,8|confirmed',
        'password_confirmation' => 'alpha_num|between:4,8',
    );
...
}

An alternative would be to use PHP's "traits" which is relatively new.
http://php.net/manual/en/language.oop5.traits.php

You could create a trait
/app/models/ValidationTraits.php

<?php

    trait ValidationTraits {

    //Ardent / Modification for validation.
    public function validate( array $rules = array(), array $customMessages = array() ) {

        //If custome rules are not being applied, then use default rules in class
        if (empty($rules)){
            $rules = $this->ignoreCurrentRecordForUnique ();
        }
        return parent::validate( $rules , $customMessages ) ;

    }

    /**
    * Ardent / Modification for validation.
    * If an item is marked as unique, the rule should change to the format: 'unique:users,email_address,10'  where 10 is the id of      
    * the record in quesion.
    */

    protected function ignoreCurrentRecordForUnique (){
      $rules = static::$rules ;
      if ($this->exists && array_key_exists( 'id' , $this->attributes)) {
         foreach ( $rules as $field => &$rule ) {
            if (is_string($rule)) {
               $rulereplace = '';
               $rulearray =  explode('|', $rule);
               foreach ($rulearray as $onerl) {
                  if (strpos($onerl, ':') !== false) {
                     list($rule, $parameter) = explode(':', $onerl, 2);
                     $parameters = str_getcsv($parameter);
                     // if rule is 'unique' and table is same as field table being validated  and ignore parameter is not already set
                     if ($rule == 'unique' && (count  ($parameters) == 2 || count ($parameters) == 1 ) &&  $parameters[0] == $this->getTable()) {
                        if (count ($parameters) == 1)
                           $onerl .= ',' . $field . ',' . $this->attributes['id'];
                        else
                           $onerl .= ',' . $this->attributes['id'];
                     }
                  }
                  if ($rulereplace != '')
                     $rulereplace .= '|';
                  $rulereplace .= $onerl;
               }
               $rule = $rulereplace;
            }
         }
      }
      return $rules;
    }
    }
?>

And then in your models

/app/models/User.php

<?php
use LaravelBook\Ardent\Ardent;

class User extends Ardent{
  use ValidationTraits;
 ....
}
?>

I didn't test this code, but conceptually this should work, and because your class extends Ardent, the traits validate method should override the Ardent::validate method.

I think my first suggestion is easier and its handy to have an AppModel class so you can easily add functionality that all of your models can use.

@asivaneswaran
Copy link
Author

Perfect thank you very much!

@nightowl77
Copy link
Contributor

Not sure why this issue shows as "Open". This issue should be fixed in the latest Ardent 2.1.0. Updates were made to the function "updateUniques" which would allow you to do exactly what was said in @asivaneswaran's first post

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants