Make custom Error validation rule - php

I'm trying to store student info in database id, name with course_1, course_2 from a form.
Same student can't register for same course again.
Students Table
id name
1 X
2 Y
Courses Table
id course_name
1 A
2 B
Student_courses Table
student_id courses_id
1 1
2 1
2 2
Student controller like this :
public function studentRegistration(Request $request)
{
$student = new Student();
$student->name = $request->Input(['student_name']);
$student->save();
$courses = array(
$request->Input(['course_1']),
$request->Input(['course_2']),
$request->Input(['course_3'])
);
foreach ($courses as $course)
{
$studentCourse = new StudentCourse();
$studentCourse->student_id = $student->id;
$studentCourse->course_id = $course;
$studentCourse->save();
}
}
How to make this custom validation with Laravel so same student can't take same course again?

Could you use an existing rule?
Validation rules:
'course_1' => 'different:course_2,course_3|...',
'course_2' => 'different:course_3|...',
I am not sure how exact the actual problem is to the example. If these fields are more dynamic than that, then a custom rule would make sense.
That is just for validating the input to be unique values for those fields. To check against the database is where the unique rule can come in:
'course_1' => [..., $uniqueRule = Rule::unique('student_courses', 'course_id')->where('student_id', $whoEverTheStudentToCheckAgainstIs)],
'course_2' => [..., $uniqueRule],
'course_3' => [$uniqueRule],
Could hide that behind a custom rule if you really needed to.

Related

Laravel 6.x relationship default value on first relation

I want to set a default value for the first relation element and after that another. For example:
Customer can have multiple addresses.
The addresses table has the column main_address.
When I create a customer and the first address for him, Laravel should then give the column main_address the value 1. The second should get the value 0 (if not specified different).
Is Laravel capable of doing this?
My creating prozess of a customer is the following:
$customer = \App\Customer::create(["data"]);
$customer->customerAddress()->create(["data"]);
$customer->contactPerson()->create(["data"]);
Can this prozess be improved?
The relations are both Many to one. A customer can have multiple contact persons and addresses.
You can do this
$customer = \App\Customer::create(["data"]);
$address = $customer->customerAddress()->create(["data"]);
$main_address_exists = $customer->customerAddress()->where('main_address', 1)->first();
if (!$main_address_exists) {
$address->main_address = 1;
$address->save();
}
So you first check whether this customer has an address with field main_address, 1 and if it doesn't have any such record it will make the last address as 1
OR
$customer = \App\Customer::create(["data"]);
$data_for_addresses = [
'main_address' => 0
];
$main_address_exists = $customer->customerAddress()->where('main_address', 1)->first();
if (!$main_address_exists) {
$data_for_addresses['main_address'] = 1;
}
$customer->customerAddress()->create($data_for_addresses);

Laravel Replace existing DB value - Favourites

I am trying to setup a favourites button on an article. The following code works ...
public function favouriteNotfavouriteArticleParent(Request $request){
$data = [];
$data['user_id'] = Auth::id();
$data['person_id'] = GetPersonData()['id'];
$data['article_id'] = $request->get('article_id');
$data['action'] = $request->get('action');
UserFavourites::updateOrCreate($data,$data);
}
However, i want it to firstly check for any existing values set for that article ID. If it has favourite set and notfavourite is clicked, it should remove the favourite table row.
At the minute it just adds a row for favourite and notfavourite. I've attached a screenshot of the current sql behaviour.
Any help is massively appreciated!
UpdateOrCreate takes two arguments. The first argument is an array of attributes to look for and the second argument is an array of attributes to change. If there isn't a row in the database that has attributes from the first array the arrays will essentially be combined to make a new row in the database.
To achieve what you're after you could do the following:
UserFavourites::updateOrCreate([
'article_id' => $request->input('article_id'),
'user_id' => auth()->id(),
], [
'person_id' => GetPersonData()['id'],
'action' => $request->input('action'),
]);
The above will look for a row that matches the article_id and user_id and then either update the person_id and action for that row or (if the row doesn't exist) create a new row with all the attributes.

Laravel Validate if there is already a record with similar combination of two columns

For example, I have an auction where Users can bid on items.
When a user creates a new bid I want to be sure that this user didn't bid on this item before.
The BID table structure is id, item_id, user_id, price. So basically I need to check if there is a record that has same item_id and same user_id at the same time.
Is there any way to do this using Laravels Validator?
$validator = Validator::make($request->all(), [
'item_id' => 'unique:item_id,user_id,NULL,id,'. auth()->user()->id,
'price' => 'required|integer'
]);
The error I have:
Undefined offset: 1
According to Laravel docs:
[
'item_id' => 'unique:bids,item_id,null,id,user_id,' . auth()->id(),
]
Create a model for Users table.
Now,
$itemIds= User:: where ('user_id',$userId)->pluck('item_Id');
foreach($itemIds as $itemId){
if ($itemId == $newItemId) {
// write code if item id is already present
}
else {
// write code if item id is not present
}
}
you can use laravel unique validation as
'user_id' => 'unique:item_id,user_id,NULL,id,'.$user->id

Laravel validation: exists two column same row

Is there a way of referencing another field when specifying the exists validation rule in Laravel?
My request :
public function rules()
{
return [
'numero_de_somme' => 'unique:personnels,numero_de_somme|exists:fonctionnaire,num_somme',
'cin' => 'unique:personnels,cin|exists:fonctionnaire,cin',
];
}
in my validation rules I want to be able to make sure that:
num_somme exists within the fonctionnaire table
cin exists within the fonctionnaire table and cin input must be
on the same row of the num_somme
num_somme : 12345 cin : s89745
num_somme : 78945 cin : U10125
Explaining : for example
1st scenario if the input num_somme = 12345 and cin = U10125 the validation must fail
2nd scenario if the input num_somme = 12345 and cin = s89745 the validation must success
I hope this makes sense.
Thank you
You can simply use this:
'request_input' => exists:table,col,alternative_col_1,alternative_val_1,alternative_col_2,alternative_val_2, ...'
The SQL query is like below:
select count(*) as aggregate from `table` where `id` = [request_input] and `alternative_col1` = "alternative_val1" and `alternative_col2` = "alternative_val2"
I came across the same need today and I think I have a solution using the validation Rule class: Rule example.
Here is my scenario: I have an email verifications table and I want to ensure that a passed machine code and activation code exist on the same row.
Be sure to include use Illuminate\Validation\Rule;
$activationCode = $request->activation_code;
$rules = [
'mc' => [
'required',
Rule::exists('email_verifications', 'machineCode')
->where(function ($query) use ($activationCode) {
$query->where('activationCode', $activationCode);
}),
],
'activation_code' => 'required|integer|min:5',
'operating_system' => 'required|alpha_num|max:45'
];
The first argument in the exists method is the table and the second is the custom column name I'm using for the 'mc' field. I pass the second column I want to check using the 'use' keyword and then use that field in a a where clause.
You can achieve validating multipe columns by using Rule.
Include :
use Illuminate\Validation\Rule;
use Validator;
$AdminId = $request->AdminId;
$Validate = Validator::make($request->all(),[
'TaxId' => [ 'required', Rule::exists('tax','id')
->where(function ($query) use ($AdminId) {
$query->where('u_id', $AdminId);
})],
]);
if($Validate->fails())
{`Your ERROR HERE`}
else
{`SUCCESS`}
Here in my example I'm checking u_id and Id which is in same row and 2 columns.
Explaining : for example
My DB HAS 2 ROWS IN tax TABLE
id = 1 , u_id = 1, tax = "GST" , value -> 8
id = 2 , u_id = 2, tax = "GST" , value -> 5
1st scenario if the input id = 2 and u_id = 1 the validation must fail because this row belongs to u_id = 2.
2nd scenario if the input id = 2 and u_id = 2 the validation must success
i managed to solve it using the most simple method
for numero_de_somme
'numero_de_somme' => 'unique:personnels,numero_de_somme|exists:fonctionnaire,num_somme,cin,'.Request::get('cin'),
for cin
'cin' => 'unique:personnels,cin|exists:fonctionnaire,cin',
PS . don't forget to call use Illuminate\Http\Request;
if (is_numeric($request->get('emailOrphone'))){
$request->validate([
'emailOrphone'=>'exists:users,phone',
],
[
'emailOrphone.exists'=>'phone is invalid.'
]);
}else{
$request->validate([
'emailOrphone'=>'exists:users,email',
],
[
'emailOrphone.exists'=>'email is invalid.''
]);
}

Import large number of records in laravel, each record having multiple relations

I have a case where user uploads a file containing large number of rows(let's say 1000). Each row contain information about a user.
This data is turned into PHP array with objects
E.g
$userArray = [{first_name: 'Peter', last_name:'Pan', email 'peter#example.org'},
{first_name: 'David', last_name:'Hasslehof', email 'david#example.org'}...]
Now for each row I would have to create
foreach ($usersArray as $user) {
$createdUser = User::create(array('email' => $user['email'], 'pin' => $user['id_code']));
$profile = Userprofile::create(array('first_name' => $user['first_name'], 'last_name' =>$user['last_name']));
$createdUser->profile()->associate($profile);
$createdUser->save();
$usergroup->addMember($createdUser);
}
This would mean that if I had 1000 rows, atleast 4000 queries, which is obviously too much. Is there a eloquent way to do this more elegantly?
I tried using querybuilder and insert first all profiles and then users but this did not work, because I dont know which profiles to retrieve(first_name and last_name are not unique fields) and therefore cannot link profile_id's to users that I would like to create.
I think you can use this this laravel library for import.
However, to import multiple relationships, i think there is no other way than use associate() or sync().
$model_object = new YourModelHere();
//your model id here
$model_object->id = $sheet->id;
//your model id fields
$model_object->field_1 = (int)$sheet->field_1;
$model_object->field_2 = (int)$sheet->field_2;
//related id of models heres
$id_of_related_1 = (int) $sheet->id_of_related_1 ;
$id_of_related_2 = (int) $sheet->id_of_related_2;
//in your Model.php the relation i.e. hasMany or Belongs to must be declared first.
$model_object->relationToModelOne()->associate(RelatedModelOne::find($id_of_related_));
$model_object->relationToModelTwo()->associate(RelatedModelTwo::find($id_of_related_2));
$model_object->save();

Categories