Laravel-mongodb: Validation unique and excluding current record

Created on 12 Jan 2015  Â·  8Comments  Â·  Source: jenssegers/laravel-mongodb

This is very good job I wanted to use it on my Rad4PHP CRUD (www.rad4php.com) scaffolding generator, while testing the usage I come across problem in validation when updating and checking for unique validation attribute it errors to field value already taken (it does not exclude the current record from this check): e.g $validator=Validator::make(Input::all(),array(

    'username'            =>'required|unique:users,username,'.$id,
    'email'                =>'required|unique:users,email,'.$id,
    'password'            =>'required',
    'repassword'        =>'required|same:password'
    ));

I do not have this problem on MySql only MongoDB, Any advise and suggestion to resolve it highly appreciated

Most helpful comment

After digging into the source code a bit you will find this:

/vendor/laravel/framework/src/Illuminate/Validation/Validator.php

/**
* Get the excluded ID column and value for the unique rule.
*
* @param  array  $parameters
* @return array
*/
protected function getUniqueIds($parameters)
{

    $idColumn = isset($parameters[3]) ? $parameters[3] : 'id';
    return [$idColumn, $parameters[2]];
}

It's looking for a 3rd parameter to define the id field.
Simply put: your rule should look like this: 'email' => 'required|email|unique:users,email,'.$id.',_id',

Thats:
'{field}' => '{rules}:{targetTable/Collection},{targetColumn},{exclusionRecord/ID},{exclusionColumn}',

I bet this is somewhere in the documentation but why the hell use the short way of finding information?

All 8 comments

I have sorted this problem as follows:
(please note this workaround is ok for MongoDB only)
edit (laravel bas folder)/vendor/laravel/framework/src/illuminate/Validation/Validator.php
change at line 1009 9 (just add _ to the id):
$idColumn = isset($parameters[3]) ? $parameters[3] : 'id';
to
$idColumn = isset($parameters[3]) ? $parameters[3] : '_id';

Since mongodb uses _id for id field and not id as in MySql and other databases.
I have tested this and works perfect with my Rad4PHP CRUD generator (www.rad4php.com)

Its never a good practice to edit the vendor source.
You could simply make your model use primary key as id.
protected $primaryKey = '_id';

You are absolutely right  but unfortunately there is no way around this problem but to modify the source code, I have tried your suggestion but did not work (still does not exclude the current record from checking unique rule).
So it is up to jessegers to sort this problem, meanwhile my workaround is fine as long as you are using Mongodb.
Thanks M A Shalash M.Sc. B.Sc.

 

 On Thursday, 15 January 2015, 22:48, Ahsen M <[email protected]> wrote:

Its never a good practice to edit the vendor source.
You could simply make your model use primary key as id.
protected $primaryKey = '_id';—
Reply to this email directly or view it on GitHub.

Inside Model
public static function rules ($id=0, $merge=[]) {
return array_merge(
[
'username' => 'required|min:3|max:12|unique:users,username' . ($id ? ",$id" : ''),
'email' => 'required|email|unique:member'. ($id ? ",id,$id" : ''),
'firstname' => 'required|min:2',
'lastname' => 'required|min:2',
],
$merge);
}

Validation on create:
$validator = Validator::make($input, User::rules());

Validation on update:
$validator = Validator::make($input, User::rules($id));

Validation on update, with some additional rules:

$extend_rules = [
'password' => 'required|min:6|same:password_again',
'password_again' => 'required'
];
$validator = Validator::make($input, User::rules($id, $extend_rules));

Giving me an error
MongoResultException (15959)
localhost:27017: exception: the match filter must be an expression in an object

/var/www/html/fitadmin/vendor/jenssegers/mongodb/src/Jenssegers/Mongodb/Collection.php
{
$query[] = '{...}';
}
}

    $start = microtime(true);

    $result = call_user_func_array(array($this->collection, $method), $parameters);

    // Once we have run the query we will calculate the time that it took to run and

edit (laravel bas folder)/vendor/laravel/framework/src/illuminate/Validation/Validator.php
change at line 1009 9 (just add _ to the id):
$idColumn = isset($parameters[3]) ? $parameters[3] : 'id';
to
$idColumn = isset($parameters[3]) ? $parameters[3] : '_id';

but does not work

Hi SanJay1688
According to Laravel docs,I use rules as follows:
protected $rules =array(
'username' => 'required|unique:users,username,{id}',
);

Use my generater at (www.rad4php.com) current version it will generate CRUD scaffolding and all the models, views, routes ...
If you wait a week I will upload a new version with graphical interface.
Thanks

i like how L5 handle validations, You have different class which extends formRequest. Maybe take a look at that. Cleaner and effective code.

After digging into the source code a bit you will find this:

/vendor/laravel/framework/src/Illuminate/Validation/Validator.php

/**
* Get the excluded ID column and value for the unique rule.
*
* @param  array  $parameters
* @return array
*/
protected function getUniqueIds($parameters)
{

    $idColumn = isset($parameters[3]) ? $parameters[3] : 'id';
    return [$idColumn, $parameters[2]];
}

It's looking for a 3rd parameter to define the id field.
Simply put: your rule should look like this: 'email' => 'required|email|unique:users,email,'.$id.',_id',

Thats:
'{field}' => '{rules}:{targetTable/Collection},{targetColumn},{exclusionRecord/ID},{exclusionColumn}',

I bet this is somewhere in the documentation but why the hell use the short way of finding information?

THIS IS AN EASY SOLUTION

Just add $this->route('id') as the third parameter

if your route was defined like this:

Route::put('{company}', 'CompanyController@update')
        ->name('update');

then your parameter name is "company"

So in your FormRequest:

public function rules()
{
    $rules = [
        'url' => [
            'required',
            'url',
            'unique:companies,url,'.$this->route('company') ?? 0
        ],    
    ];
    // dd($rules); << check yourself

    return $rules;
}

This FormRequest works the same for insert or update.

this line will instruct to ignore "0" in case of insert

$this->route('company') ?? 0

Was this page helpful?
0 / 5 - 0 ratings

Related issues

geofflancaster picture geofflancaster  Â·  3Comments

pirmax picture pirmax  Â·  3Comments

viacheslavpleshkov picture viacheslavpleshkov  Â·  3Comments

lgt picture lgt  Â·  3Comments

ricardofontanelli picture ricardofontanelli  Â·  3Comments