Unique validation with 2 columns - Laravel 8.x - php

I've been trying make my validation so that an extension must be unique to it's own company but not to other companies. Here is my DB table:
$table->id();
$table->foreignId('user_id')->constrained();
$table->foreignId('account_id')->constrained()->onDelete('cascade');
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
$table->string('email');
$table->string('extension');
$table->string('password')->nullable();
$table->string('user_type')->default('user');
$table->timestamps();
$table->unique(['extension', 'account_id'], 'unique_extension');
And my validation rule looks like this:
public function rules()
{
return [
'editExtension.first_name' => 'required|max:255',
'editExtension.last_name' => 'required|max:255|',
'editExtension.email' => ['required', 'email','max:255', Rule::unique('account_users', 'email')->ignore($this->editExtension->id)],
'editExtension.extension' => ['required', 'numeric', Rule::unique('account_users', 'extension', $this->client_id)->ignore($this->editExtension->id)],
'editExtension.password' => 'required|max:255',
'editExtension.user_type' => 'required|in:user,admin',
];
}
But still I got errors saying that the extension number is already taken.
It seems that the Unique rule doesn't accept multiple columns, only one. Is this true?
How can I fix this?

Forcing A Unique Rule To Ignore A Given ID:
UPDATING AN EXISTING RECORD.
"account_users" => Table name.
"account_id", "extension" => The 2 fields to check for uniqueness.
ID of currently edited row here. => The id (primary key) to ignore. (The currently updated/edited table row id.)
Rule::unique("account_users")->where(
function ($query) use ($request) {
return $query->where(
[
["account_id", "=", $request->account_id],
["extension", "=", $request->extension]
]
);
})->ignore(/* ID of currently edited row here. */)
CREATING A NEW RECORD.
Rule::unique("account_users")->where(
function ($query) use ($request) {
return $query->where(
[
["account_id", "=", $request->account_id],
["extension", "=", $request->extension]
]
);
})
Addendum
By default, the unique rule will check the uniqueness of the column
matching the name of the attribute being validated. However, you may
pass a different column name as the second argument to the unique
method:
Rule::unique("account_users", "extension")->where(...)

Related

Laravel 8 unique validation rule doesn't work with user_id

I'm using Laravel 8 and the unique validation rule to ensure that a record remains unique, I'm now trying to extend this so that it's unique per user as well, but when expanding the functionality and using the rule in array form it doesn't seem to validate the user ID and instead gives me a integrity constraint violation.
So I have a table called brands, and this table contains two columns in question: brand and user_id, I need to ensure that when storing a record that the brand is unique against the brand column and that the logged in in user's ID the one making the request, e.g:
Two users can have the same brand, but a single user can't have multiples of the same brand.
$validator = Validator::make($request->all(), [
'brand' => [
'required',
'string',
Rule::unique('brands')->where(function ($query) {
return $query->where('user_id', Auth::id());
})
],
'url' => 'required|string',
'telephone' => 'required|string|min:11|max:11'
]);
I've also tried:
'brand' => 'required|string|unique:brands,brand,user_id,' . Auth::id()
What am I missing?
According to the documentation you have to use the ignore() function:
Rule::unique('users')->ignore($user->id),
on your case:
Rule::unique('brands')->ignore($user->id, 'user_id'),

How to make Laravel unique validation work on an input array?

UpdateEntityRequest.php:
'phones' => 'sometimes|nullable|array',
'phones.*.id' => 'sometimes|required|integer|distinct|exists:entity_phones,id,entity_id,'.$this->id,
'phones.*.number' => 'required|alpha_num|max:255|distinct|unique:entity_phones,number,'.$this->id.',entity_id',
entity_phones table:
id, number, entity_id.
unique constraint: (number, entity_id)
EntityRepository.php:
foreach ($attributes['phones'] as $phone) {
if (isset($phone['id'])) {
$entity->phones()->updateOrCreate([
'id' => $phone['id'],
'entity_id' => $entity->id
], $phone);
} else {
$entity->phones()->create($phone);
}
}
My entity can have more than phone associated, but not a repeated number. My intention is to check the unique (entity_id, number) in the UpdateEntityRequest.php so:
If the phone object comes without an id, it should check that the combination of number, entity_id doesn't exists. But the number can exist with other entity_id.
If the request comes with an id, it should check that the combination of number, entity_id doesn't exists only in other ids, but ignore the given id.
I'm having trouble witht the Laravel Unique rule validating only when i want it to make the validation. Any ideas how could I make this solution would be appreciated.
If you need to ignore a given ID during the unique check try using the Rule class to fluently define the rule.
use Illuminate\Validation\Rule;
Validator::make($request_data, [
'number' => [
'required',
'alpha_num', (...all your other rules)
Rule::unique('entity_phones')->ignore($entity_id),
],
]);
You can read more in laravel docs about unique rule in paragraph: Forcing A Unique Rule To Ignore A Given ID.
I ended up doing this:
$phoneIds = $this->input('phones.*.id');
'phones.*.number' =>
[
'required_with:phones',
'alpha_num',
'max:255',
'distinct',
Rule::unique('entity_phones', 'number')
->where('entity_id', $this->id)
->where(function ($query) use ($phoneIds) {
return $query->where('id', '!=', array_shift($phoneIds));
})
],

Laravel validation rule fails when trying to update the same record with no changes

I've got a table called Sides which consists of id, name, side_category_id and some other fields not important at the moment.
I wanted to validate that when creating a new side record, the record doesn't exist already. So, let's say I've got in the database a record such as:
id: 1
name: Salad
side_category_id: 3
If I try to insert a new record with name = 'salad' and side_category_id = 3 then the creation must fail and return an error.
I've achieved this by using the following rule:
$rules = [
'name' => 'required',
'side_category_id' => 'required|exists:side_categories,id|unique:sides,side_category_id,NULL,id,name,' . $this->request->get('name')
]
So far so good. It works as it's supposed to. But now it's returning an error if I want to edit a record and save it without any modifications and this is not my desired outcome.
If I try to update the record with no modifications it should succeed. How can I update my rule to achieve this?
you can use Rule::unique()
for create use like this
$rules = [
'name' => ['required'],
'side_category_id' => ['required',Rule::unique('sides', 'name')->where(function ($query) use($category_id) {
return $query->where('side_category_id', $category_id);
}),Rule::exists('side_categories')]
]
for update
$rules = [
'name' => ['required'],
'side_category_id' => ['required',Rule::unique('sides', 'name')->where(function ($query) use($category_id) {
return $query->where('side_category_id', $category_id);
})->ignore($id),Rule::exists('side_categories')]
]
//$id should be you parameter

Column not found: Unknown column using Model reference but work with object reference laravel 6

I am updating my user table with validations in controller. I have created the same validation for two tables in the same controller.
When I use this code:
User::where('id',$data->user_id)->update($this->validateField($data->user_id));
it show
Error: Column not found: 1054 Unknown column 'address_name'
Which is right because user table does not have column "address_name" but its works with this code without any error
$user = User::where("id",$data->user_id)->firstOrFail();
$user->update($this->validateField($data->user_id));
What is different between these two codes, why does its not work (show unknown column Error) and why it worked without column Error?
Here is my validateField method
public function validateField($id)
{
return request()->validate([
'address_name' => 'required|string|max:255',
'mobile' => 'required|numeric|digits_between:10,13',
'land_line' => 'required|numeric|digits_between:10,13',
'min_order' => 'required',
'payment_method' => 'required',
'open_time' => 'required',
'close_time' => 'required',
'address'=>'required|string|max:255',
'city'=>'required|string|max:255',
'country'=>'required|string|max:255',
'is_active' => 'required',
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|email|max:255|unique:users,email,'.$id.',id,deleted,0',
'password' => 'sometimes|required|min:8',
]);
}
my user table
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('first_name');
$table->string('last_name');
$table->string('email');
$table->string('password');
$table->string('mobile');
$table->tinyInteger('user_role')->unsigned();
$table->tinyInteger('is_active')->unsigned()->default(1);
$table->datetime('last_login')->nullable();
$table->tinyInteger('deleted')->unsigned()->default(0);
$table->dateTime('created_at')->nullable();
$table->dateTime('updated_at')->nullable();
$table->integer('updated_by')->nullable();
$table->rememberToken();
});
Well
User::where('id',$data->user_id)->update($this->validateField($data->user_id));
this will update all the records that correspond to the where with the fields passed as parameter to the update function, it's just a case that the where will have just one match (because you are applying the where clause to the primary key), if there were more than one match, all the records will be update.
Keep in mind that the where function will return a Builder, and so the update function is the update of the class Builder: it means that there will be only one query (update ... set ... where id = /*your id*/).
This instead
User::where("id",$data->user_id)->firstOrFail()->update($this->validateField($data->user_id))
will first get the first Record that match the where clause, so there will be a Query like select .. from .. where id= /*your id*/, than on that Model will be called the update function, so the function invoked here id the Model -> update function, where previously was Builder -> update, and so there will be a second query with the update.
The different behavior is caused by the different implementation of the update function in the two classes. Actually, on my server, both the methods will throw an error if some fields inside the array passed to update aren't table fields, don't know why on your the first one works fine

Laravel create user statement doesn't store specific columns

I am using Laravel version 5.4 . I have a table called Users and each user has the below columns :
Schema::create('users', function (Blueprint $table) {
$defaultValue = 0;
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('facebook_id')->unique();
$table->string('avatar');
$table->integer('newsletter')->default($defaultValue); // <-
$table->bigInteger('category_1')->default($defaultValue); // <-
$table->bigInteger('category_2')->default($defaultValue); // <-
$table->bigInteger('category_3')->default($defaultValue); // <-
$table->timestamp('unlocked_tip_of_category_1_at')->nullable();
$table->timestamp('unlocked_tip_of_category_2_at')->nullable();
$table->timestamp('unlocked_tip_of_category_3_at')->nullable();
$table->rememberToken();
$table->timestamps();
});
The problem is that when i use the function to create a user category_1, category_2 and category_3 don't take the new value which is 1.
After taking auth from facebook i use the below to store user's information :
return User::create([
'name' => $facebookUser->name,
'email' => $facebookUser->email,
'facebook_id' => $facebookUser->id,
'avatar' => $facebookUser->avatar,
'newsletter' => 0,
'category_1' => 1,
'category_2' => 1,
'category_3' => 1,
]);
For example name changes to facebook user's name. Also i tried changing
'name' => $facebookUser->name,
to
'name' => $facebookUser->name . " HEY",
Which successfuly stored the name and + " HEY" at the end. (Just to be sure that this runs).
Categories are bigInteger that means a bigint(20) type. I am thinking something happens with the default values which i've set it to 0.
Any ideas? If you need any more information please let me know.
From what i am trying to accomplish the best way to solve this is to change the $defaultvalue to 1, but i don't understand why this doesn't work.
If you're using the default laravel scaffolding then you need to ensure you're updating the default App\User model based on all columns you need to have as fillable:
class User extends Model {
protected $fillable = [
'name', 'email', 'password','facebook_id','avatar','newsletter',
'category_1', 'category_2', 'category_3'
];
...
}
Same applies if you're creating your own model.

Categories