Duplicate on 2 fields - laravel

I looking a way to avoid the duplicates in Laravel. For example, I have a table with 2 fields which are name and firstname.
How to manage the duplicates on the Controller? I am newbie...
Here is my function store().
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:25',
'firstname' => 'required|string|max:25'
]);
$exists = Auteur::where('name', $request->get('name'))->where('firstName', $request->get('firstName'))->count();
if (!$exists){
Auteur::create($request->all());
return redirect()->route('auteurs.index')
->with('success', 'save');
}
}
I thank you for your help and your explanations.

If it were one field, you could use validation, or make that field unique and that would take care of it with a little error handling. However, with two fields to have to check against, it might be easiest to check if the element is already in the database and deduplicate from there. So in the store() method:
$exists = Auteur::where('name', $req->get('name'))->where('firstname', $req->get('firstname')->count();
if (!$exists){
// create the new model, now that we know there is no duplicate in the database
Auteur::create($request->all());
}

Just add unique in your validation rule. If you would like to check unique validation each field separately.
$request->validate([
'name' => 'required|unique:auteurs,name|string|max:25',
'firstname' => 'required|unique:auteurs,firstname|string|max:25'
]);
Here I hope the table name is `auteurs`

Related

Laravel validation for option list: if value is not in DB then give error

I have an option list in my front end and the data is retrieved from the DB table, named countries and nicename column.
Trying to prevent the user request for value which is not in countries table and in nicename column. I have created custom validation, which works fine but it looks like it's not too professional way of doing this control. I have seen somewhere that there is shorter way of doing this validation by in:table_name,column_name. But it did not work for me Maybe I am doing something wrong?
$rules = [
'shop_country' => [
'required',
function ($attribute, $value, $fail ) {
$found_country = '';
$countries = Country::get()->toArray();
foreach ($countries as $country) {
if ($country['nicename'] === $value) {
$found_country= $country['nicename'];
}
}
if($found_country === ''){
$fail('The country is not valid!');
}
}],
]
You can define it as:
'shop_country' => ['required|exists:table_name,column']
See docs
You may use the exists validation rule:
The field under validation must exist in a given database table.
$rules = [
'shop_country' => ['required', 'exists:countries,nicename']
];
In the above example, the table name is assumed to be countries.
You should be able to achieve this by using the exists validation rule.
You can check it in the official laravel documentation.
Also this is an example they provide
'state' => 'exists:states'
You can validate nicename as string
'shop_country' => 'required|string|exists:countries,nicename',
Or validate country id itself
'country_id' => 'required|integer|exists:countries,id',

Relationship User and children data using belongsTo

public function children()
{
return $this->belongsTo('App\User', 'parent_id', 'id');
}
$item = Item::where([
'status' => '1',
'id' => $id
])->first();
$user = User::where([
id=>Auth::id()
])->with('children')->get()
return view('item.list')->with(compact('item', 'user'));
How can I get item and authenticated user along with children and send it to view in one query or is there any other best practise.
From your code, it looks like Item is not related in any way to the User model. If that is the case, there is likely no reason to try to do this in one query, and likely not efficient or even possible. There could be some relation that I don't know of, but you are probably better off doing the two queries.. One for the $item:
$Item = Item::where([
'status' => '1',
'id' => $id
])->first();
And then one to load the children on the User object. This one is potentially a little different. If you are manually loading the User object for some reason, you can eager load the children:
$user = User::where([
'id' => $someId
])->with('children')->first();
If you are within the auth middleware, you don't need to re-load the user, it is already provided by Laravel. You can just load the children if they are not already there:
$user->load('children');
or, even easier, from your blade page, just call the load on the page:
$user->children();
You have the code correct for sending to your view:
return view('item.list')->with(compact('item', 'user'));

Laravel Coding Practice / Most Optimised Method to Store

Laravel documentation says one should store as follows:
public function store(Request $request)
{
// Validate the request...
$flight = new Flight;
$flight->name = $request->name;
$flight->save();
}
However, why not just as follows:
public function store(Request $request)
{
Flight::create($request->all());
}
The above example is quite easy, since it only has one field. But I imagine its rather tedious to do something with many fields and have to assign each one as opposed to just passing the whole $request as in the second example?
First option gives you better control as to what goes into new model. If you store everything from the request then user might inject fields that you don't want to be stored for a new model in your store method.
For example, your flight has column is_top_priority that is declared as fillable in your Flight model, but when creating new flight you want to set only name for you flight (and leave is_top_priority as null or maybe it has default value of 0 in your table). If you write Flight::create($request->all()); then user can inject <input name="is_top_priority" value="1"> and get advantage of your code.
That is why it is not recommended to use fill($request->all()). Use $request->only(...) or assign each needed field manually as provided in your first example.
For example your model have some fields like name, email, password,status and etc.
Request validate name, email and password and if you do this:
Flight::create($request->all());
Client can send with other fields status, but you change status manually. I do this:
Flight::create([
'name' => $request->get('name'),
'email' => $request->get('email'),
'password' => $request->get('password'),
'status' =>config('params.flight.status.not_active'),
]);

Simplify store controller method on laravel 5

This is my store method to save a post.
public function store(CreatePostRequest $request)
{
$post = new Post([
'title' => $request['title'],
'content' => Crypt::encrypt($request['content']),
'published_at' => Carbon::now()
]);
$post->user()->associate(Auth::user());
$newPost=Post::create($post->toArray());
$this->syncTags($newPost, $request['tag_list']);
return redirect('posts')->withMessage('Post Saved Successfully !!!');
}
In laracasts tutorial he is just doing a
Article::create($request->all());
I need to do the extra stuff like encrypt, but am i cluttering the method? could it be cleaner?
Do it in the Model. I use the set/get*Attribute() method to change stuff on the fly.
So you could use Article::create($request->all()); then in the model use the fillable array to only autofill what is allowed (such as title, content and published_at).
then use something like (in the model)
function setContentAttribute( $value ){
$this->attributes['content'] = Crypt::encrypt($value);
}
In fact you could also adapt this approach so that the published_at attribute is set to today, or even better use your database to provide now()s time.

Laravel 4: Unique Validation for Multiple Columns

I know this question has been asked earlier but i did not get relevant answer.
I want to know that how can i write a rule to check uniqueness of two columns. I have tried to write a rule like:
public $rules = array(
"event_id"=>"required",
"label"=>"required|unique:tblSection,label,event_id,$this->event_id",
"description"=>"required"
);
In my example i need to put validation so that one label could be unique for a single event id but may be used for other event id as well. For Example i want to achieve:
id event_id label description
1 1 demo testing
2 2 demo testing
In the rule defined above, somehow i need to pass current selected event_id so that it could check whether the label does not exist in the database table for selected event_id but i am getting syntax error like:
{"error":{"type":"Symfony\\Component\\Debug\\Exception\\FatalErrorException","message":"syntax error, unexpected '\"'","file":"\/var\/www\/tamvote\/app\/modules\/sections\/models\/Sections.php","line":39}}
Note: I don't want to use any package but simply checking if laravel 4 capable enough to allow to write such rules.
The answer from Mohamed Bouallegue is correct.
In your controller for the store method you do:
Model::$rules['label'] = 'required|unique:table_name,label,NULL,event_id,event_id,' .$data['event_id'];
where $data is your POST data.
And for the update method you do:
$model = Model::find($id);
Model::$rules['label'] = 'required|unique:table_name,label,NULL,event_id,event_id,'.$data['event_id'].',id,id'.$model->id;
where $data is your PUT/PATCH data, $model is the record you are editing and id is the table primary key.
I didn't try this before but I think if you get the event_Id before validating then you can do it like this:
'label' => 'unique:table_name,label,NULL,event_id,event_id,'.$eventId
//you should get the $eventId first
If you want to declare your validation rules statically you can do this as well. It's not the most efficient since it checks the database for each value.
protected $rules = [
'user_id' => 'unique_multiple:memberships,user_id,group_id',
'group_id' => 'unique_multiple:memberships,user_id,group_id',
]
/**
* Validates that two or more fields are unique
*/
Validator::extend('unique_multiple', function ($attribute, $value, $parameters, $validator)
{
//if this is for an update then don't validate
//todo: this might be an issue if we allow people to "update" one of the columns..but currently these are getting set on create only
if (isset($validator->getData()['id'])) return true;
// Get table name from first parameter
$table = array_shift($parameters);
// Build the query
$query = DB::table($table);
// Add the field conditions
foreach ($parameters as $i => $field){
$query->where($field, $validator->getData()[$field]);
}
// Validation result will be false if any rows match the combination
return ($query->count() == 0);
});
Like Sabrina Leggett mentioned, you need to create your own custom validator.
Validator::extend('uniqueEventLabel', function ($attribute, $value, $parameters, $validator) {
$count = DB::table('table_name')->where('event_id', $value)
->where('label', $parameters[0])
->count();
return $count === 0;
}, 'Your error message if validation fails.');
You can call your validator by adding the following line to your rules:
'event_id' => "uniqueEventLabel:".request("label")
If you need more fields, you could add a new where clause to the sql statement.
(Source: edcs from this answer)
As you I was looking for hours to do that but nothing worked, I test everything ... suddenly the randomness of the doc I came across this:
'email' => Rule::unique('users')->where(function ($query) {
return $query->where('account_id', 1);
})
https://laravel.com/docs/5.5/validation#rule-unique
and it works perfectly and moreover it is very flexible :)

Resources