How to make default request values inside $validated array in Laravel? - php

Controller code:
public function store(UserStoreRequest $request) {
$validated = $request->validated();
$validated['user_type_id'] = 2;
$validated['user_gender_id'] = $request->user_gender_id;
$validated['last_login_at'] = Carbon::now();
$validated['password'] = Hash::make($request->password);
User::create($validated);
return to_route('all-users');
}
Is there a better way to do this?
I tried something like this but didn't work:
$validated = $request->validated([
'user_type_id' => 2,
'user_gender_id' => $request->user_gender_id,
'last_login_at' => Carbon::now(),
'password' => Hash::make($request->password),
]);

there is not official laravel way to do this but you could make most of those values default in a migration.
you could also clean up the controller a little bit by doing something like this.
public function store(UserStoreRequest $request) {
User::create([
...$request->validated(),
'user_gender_id' => $request->user_gender_id;
'password' => Hash::make($request->password)
]);
return to_route('all-users');
}
And then for the default values you can do this in your migration
Schema::create('flights', function (Blueprint $table) {
$table->foreignId('user_type_id')
->nullable()
->default(2)
->constrained();
});
and then lastly to cast the last_login_at to a now by default you can do that a few ways but using a mutator on the model is probably the best.

I did like this:
User::create([
...$request->validated(),
'last_login_at' => now(),
'user_type_id' => 2,
'password' => Hash::make($request->password)
]);
If you store some images do something like this:
$validated = $request->validated();
if($request->hasFile('photo')) { ..etc
$validated['photo'] = $filename;
}
User::create([
...$validated,
'last_login_at' => Carbon::now(),
'user_type_id' => 2,
'password' => Hash::make($request->password)
]);

Related

Laravel 8: photo_id does not added to users table at One To Many relationship

I'm using Laravel 8 to develop my project and in this project, I have a page for adding new users and uploading their profile picture.
Now at the store() of Controller, I coded this:
public function store(Request $request)
{
$user = new User();
$validate_data = Validator::make(request()->all(),[
'name' => 'required|min:4',
'email' => 'required|email|unique:users',
'status' => 'required',
'role' => 'required',
'password' => 'required|min:6',
])->validated();
if($file = $request->file('avatar')){
$name = time() . $file->getClientOriginalName();
$file->move('images', $name);
$photo = new Photo();
$photo->name = $file->getClientOriginalName();
$photo->path = $name;
$photo->user_id = Auth::id();
$photo->save();
$user->photo_id = $photo->id; //Adding photo id to the new user at users table
}
$creation = User::create([
'name' => $validate_data['name'],
'email' => $validate_data['email'],
'status' => $validate_data['status'],
'role_id' => $validate_data['role'],
'password' => bcrypt($validate_data['password'])
]);
if($creation){
alert()->success('User was added', 'Success');
return redirect('/admin/users/');
} else {
return '1003';
}
}
It works fine and correct and adds the new user to users table and the photo to photos table.
But this line that should add the photo_id to users table, does not work and the photo_id of the new user is empty somehow!
And the relationship between User and Photo Models goes like this:
User.php:
public function photos()
{
return $this->hasMany(Photo::class);
}
Photo.php:
public function user()
{
return $this->belongsTo(User::class);
}
And I have also added photo_id as fillbale at User Model.
So what is going wrong here ? How can I fix this issue ?
I would really appreciate any idea or suggestion about this...
Thanks in advance.
Here are the Migrations, if you would like to see:
create_photos_table table:
public function up()
{
Schema::create('photos', function (Blueprint $table) {
$table->increments('id');
$table->string('path');
$table->string('name');
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
}
add_avatar_to_users_table:
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->integer('photo_id')->unsigned()->nullable();
});
}
In add_avatar_to_users_table migration change integer to bigInteger as follows:
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->integer('photo_id')->unsigned()->nullable();
});
}
Remove the following line from code:
$user = new User();
Update the following chunk of code:
$creation = User::create([
'name' => $validate_data['name'],
'email' => $validate_data['email'],
'status' => $validate_data['status'],
'role_id' => $validate_data['role'],
'password' => bcrypt($validate_data['password']),
'photo_id' => isset($photo) ? $photo->id : null
]);
You need to save that model:
$user->save()
Otherwise the the change you made has no effect to the DB
There are 3 things:
If your users can have many photos then you won't need the photo_id on your users table, because all photos have a user_id, hence the one to many relationship
You define $user = new User() and assign the value to this object. But later you are creating an new User with this code:
$creation = User::create([
'name' => $validate_data['name'],
'email' => $validate_data['email'],
'status' => $validate_data['status'],
'role_id' => $validate_data['role'],
'password' => bcrypt($validate_data['password'])
]);
Therefore you have 2 User models and only one of them gets saved to the database.
And last, if you save the auth()->id() as the user_id of your photo the photo will not belong to the correct user. You will first have to create the user and then take this id.
some code of your store is wrong
at first you use
$user = new User();
after
$creation = User::create([
'name' => $validate_data['name'],
'email' => $validate_data['email'],
'status' => $validate_data['status'],
'role_id' => $validate_data['role'],
'password' => bcrypt($validate_data['password'])
]);
use this code
$user->name=$validate_data['name'];
$user->email=$validate_data['email'];
$user->status=$validate_data['status'];
$user->role_id=$validate_data['role'];
$user->password=bcrypt($validate_data['password']);
$user->save();

Laravel saving data to two locations

I'm working on a larvel project where the user can create appointments. In addition I've created another model called clients so when a user creates an appointment the users "client" data is saved.
In my appointments controller I have the following: -
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required',
]);
//create appointment
$apt = new Appointment;
$apt->name = $request->input('name');
$apt->user_id = auth()->user()->id;
$apt->save();
//create client
$client = new Client;
$client->first_name = $request->input('name');
$client->user_id = auth()->user()->id;
$client->save();
return redirect('/appointments')->with('success', 'Appointment created');
}
When saving the data it works and stores the data in the clients table however I know this isn't the cleanest way of saving the data, but what is the "laravel" way of doing this?
There's nothing wrong with your code. It's totally fine keeping it that way.
I prefer to say Model::create() to create models in one statement.
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required',
]);
Appointment::create([
'name' => request('name'),
'user_id' => auth()->id()
]);
Client::create([
'first_name' => request('name'),
'user_id' => auth()->id,
]);
return redirect('/appointments')->with('success', 'Appointment created');
}
You can also use tap() function:
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required',
]);
tap(Appointment::create(['name' => request('name'), 'user_id' => auth()->id()]), function ($newAppoinment) {
Client::create([
'first_name' => $newAppoinment->name,
'user_id' => auth()->id,
]);
});
return redirect('/appointments')->with('success', 'Appointment created');
}
Or the best approach could be using model events:
class Appointment extends Model
{
public static function boot()
{
parent::boot();
static::created(function ($appointment) {
Client::create([
'user_id' => $appoinment->user_id,
'first_name' => $appoinment->name,
])
});
}
}

Retry logic on model save - Laravel

User_code is generated and must be unique. What would be the easiest/cleanest way to do retry logic on this model save? I would like to verify the generated code first, and then if it's not found on the users table, create the user, if found, loop to retry. What would be the syntax for that? Thanks
public function create(array $data)
{
$user = User::create([
'user_name' => 'My user name',
'user_code' => bin2hex(openssl_random_pseudo_bytes(16))
]);
$user->save();
return $user;
}
Why don't you check the database when generating the code? That way, you only try to create once you got it right and the end user doesn't have to face an error that is not up to him/her.
do {
$code = bin2hex(openssl_random_pseudo_bytes(16));
$record = User::where('user_code', $code)->get();
} while(!empty($record));
$user = User::create([
'user_name' => 'My user name',
'user_code' => $code
]);
return $user;
You could avoid the retry:
public function create(Request $request)
{
$request->merge(['user_code' => bin2hex(openssl_random_pseudo_bytes(16))]);
$this->validate($request, [
'user_name' => 'required|unique:users',
'user_code' => 'required|unique:users',
]);
$user = new User;
$user->user_name = $request->user_name;
$user->user_code = $request->user_code;
$user->save();
return $user;
}
You should create a unique string from the beginning. Still go for validation, of course.
public function create(Request $request)
{
$user_code = bcrypt($request->user_name . openssl_random_pseudo_bytes(16));
$request->merge(['user_code' => $user_code]);
$this->validate($request, [
'user_name' => 'required|unique:users',
'user_code' => 'required|unique:users',
]);
$user = User::create($request);
return $user;
}
A save() is implied by create().

Assign new user a plan upon registration in Laravel 5

When a new user registers, they should be automatically assigned to a plan subscription. I can do that manually in Tinker (Laravel 5):
$token = Input::get('stripeToken');
$user = User::all();
$user->subscription('monthly')->create($token);
flash('Your account has been created with a membership');
Where, in Laravel 5, do I put such logic?
Edit
public function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'company_name' => $data['company_name'],
// I have added the below:
$token = Input::get('stripeToken');
$user = User::all();
$user->subscription('loop')->create($token);
]);
}
If you are using Laravels Registrar service then I'd do it in there. That could look like this:
public function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'company_name' => $data['company_name']
]);
$token = Input::get('stripeToken');
$user->subscription('loop')->create($token);
return $user;
}
You might also want to get the stripeToken from the $data array but I'll leave that to you.

Laravel: Validation unique on update

I know this question has been asked many times before but no one explains how to get the id when you're validating in the model.
'email' => 'unique:users,email_address,10'
My validation rule is in the model so how do I pass the ID of the record to the validation rule.
Here is my models/User
protected $rules_update = [
'email_address' => 'required|email|unique:users,email_address,'.$id,
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6"
];
models/BaseModel
protected $rules = array();
public $errors;
/*
* #data: array, Data to be validated
* #rules: string, rule name in model
*/
public function validate($data, $rules = "rules") {
$validation = Validator::make($data, $this->$rules);
if($validation->passes()) {
return true;
}
$this->errors = $validation->messages();
return false;
}
Just a side note, most answers to this question talk about email_address while in Laravel's inbuilt auth system, the email field name is just email. Here is an example how you can validate a unique field, i.e. an email on the update:
In a Form Request, you do like this:
public function rules()
{
return [
'email' => 'required|email|unique:users,email,'.$this->user->id,
];
}
Or if you are validating your data in a controller directly:
public function update(Request $request, User $user)
{
$request->validate([
'email' => 'required|email|unique:users,email,'.$user->id,
]);
}
Update:
If you are updating the signed in user and aren't injecting the User model into your route, you may encounter undefined property when accessing id on $this->user. In that case, use:
public function rules()
{
return [
'email' => 'required|email|unique:users,email,'.$this->user()->id,
];
}
A more elegant way since Laravel 5.7 is:
public function rules()
{
return [
'email' => ['required', 'email', \Illuminate\Validation\Rule::unique('users')->ignore($this->user()->id)]
];
}
P.S: I have added some other rules, i.e. required and email, in order to make this example clear for newbies.
One simple solution.
In your Model
protected $rules = [
'email_address' => 'sometimes|required|email|unique:users',
..
];
In your Controller, action:update
...
$rules = User::$rules;
$rules['email_address'] = $rules['email_address'] . ',id,' . $id;
$validationCertificate = Validator::make($input, $rules);
There is an elegant way to do this. If you are using Resource Controllers, your link to edit your record will look like this:
/users/{user}/edit OR /users/1/edit
And in your UserRequest, the rule should be like this :
public function rules()
{
return [
'name' => [
'required',
'unique:users,name,' . $this->user
],
];
}
Or if your link to edit your record look like this:
/users/edit/1
You can try this also:
public function rules()
{
return [
'name' => [
'required',
'unique:users,name,' . $this->id
],
];
}
From Laravel 5.7, this works great
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
Forcing A Unique Rule To Ignore A Given ID:
Test below code:
'email' => 'required|email|unique:users,email_address,'. $id .'ID'
Where ID is the primary id of the table
If i understand what you want:
'email' => 'required|email|unique:users,email_address,'. $id .''
In model update method, for exemple, should receive the $id with parameter.
Sorry my bad english.
Here is the solution:
For Update:
public function controllerName(Request $request, $id)
{
$this->validate($request, [
"form_field_name" => 'required|unique:db_table_name,db_table_column_name,'.$id
]);
// the rest code
}
That's it. Happy Coding :)
The Best Option is here try just once no need more code when unique validation on updating data
'email' => 'unique:users,email_address,' . $userId,
hereemailis field name and users is table name and email_address is table attribute name which you want unique and $userid is updating row id
public function rules()
{
switch($this->method())
{
case 'GET':
case 'DELETE':
{
return [];
}
case 'POST':
{
return [
'name' => 'required|unique:permissions|max:255',
'display_name' => 'required',
];
}
case 'PUT':
case 'PATCH':
{
return [
'name' => 'unique:permissions,name,'.$this->get('id').'|max:255',
'display_name' => 'required',
];
}
default:break;
}
}
an even simpler solution tested with version 5.2
in your model
// validator rules
public static $rules = array(
...
'email_address' => 'email|required|unique:users,id'
);
You can try this.
protected $rules_update = [
'email_address' => 'required|email|unique:users,email_address,'. $this->id,
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6"
];
In Laravel 8.x you can use Rule::unique method as well
Forcing A Unique Rule To Ignore A Given ID:
use Illuminate\Validation\Rule;
public function update(Request $request, Post $post)
{
$validatedData = $request->validate([
'name' => ['required', 'max:60', Rule::unique('posts')->ignore($post->id)],
]);
$post->update($validatedData);
return redirect(route('posts.index'))->with('status', 'post updated successfully');
}
Do One step in controller
Works Fine with Laravel 9
$request->validate([
'name'=>'required|unique:categories,name,'.$id,
]);
If you have a separate rules method. You can use easier the following syntax.
public function rules()
{
return [
'email' => "required|unique:users,email,{$this->id}"
];
}
$rules = [
"email" => "email|unique:users, email, '.$id.', user_id"
];
In Illuminate\Validation\Rules\Unique;
Unique validation will parse string validation to Rule object
Unique validation has pattern: unique:%s,%s,%s,%s,%s'
Corresponding with: table name, column, ignore, id column, format wheres
/**
* Convert the rule to a validation string.
*
* #return string
*/
public function __toString()
{
return rtrim(sprintf('unique:%s,%s,%s,%s,%s',
$this->table,
$this->column,
$this->ignore ?: 'NULL',
$this->idColumn,
$this->formatWheres()
), ',');
}
There is a simple and elegant way to do this. If you are passing the user_id in a body request or through a query parameter.
e.g
/update/profile?user_id=
Then in your request rules
public function rules(Request $request)
{
return [
'first_name' => 'required|string',
'last_name' => 'required|string',
'email' => ['required','email', 'string', Rule::unique('users')->ignore($request->user_id )],
'phone_number' => ['required', 'string', Rule::unique('users')->ignore($request->user_id )],
];
}
Better Still, you can pass in auth->id() in place of $request->user_id to get the login user id.
Found the easiest way, working fine while I am using Laravel 5.2
public function rules()
{
switch ($this->method()) {
case 'PUT':
$rules = [
'name' => 'required|min:3',
'gender' => 'required',
'email' => 'required|email|unique:users,id,:id',
'password' => 'required|min:5',
'password_confirmation' => 'required|min:5|same:password',
];
break;
default:
$rules = [
'name' => 'required|min:3',
'gender' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|min:5',
'password_confirmation' => 'required|min:5|same:password',
];
break;
}
return $rules;
}
i would solve that by doing something like this
public function rules()
{
return [
'name' =>
'required|min:2|max:255|unique:courses,name,'.\Request::get('id'),
];
}
Where you get the id from the request and pass it on the rule
You can also use model classpath, if you don't want to hard code the table name.
function rules(){
return [
'email' => ['required','string',
Rule::unique(User::class,'email')->ignore($this->id)]
];
}
Here $this->id is either 0 or the record Id to be updated.
Use for Laravel 6.0
use Illuminate\Validation\Rule;
public function update(Request $request, $id)
{
// Form validation
$request->validate([
'category_name' => [
'required',
'max:255',
Rule::unique('categories')->ignore($id),
]
]);
}
After researching a lot on this laravel validation topic including unique column, finally got the best approach. Please have a look
In your controller
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class UserController extends Controller
{
public function saveUser(Request $request){
$validator = Validator::make($request->all(),User::rules($request->get('id')),User::$messages);
if($validator->fails()){
return redirect()->back()->withErrors($validator)->withInput();
}
}
}
saveUser method can be called for add/update user record.
In you model
class User extends Model
{
public static function rules($id = null)
{
return [
'email_address' => 'required|email|unique:users,email_address,'.$id,
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6"
];
}
public static $messages = [
'email_address.required' => 'Please enter email!',
'email_address.email' => 'Invalid email!',
'email_address.unique' => 'Email already exist!',
...
];
}
This is what I ended up doing. I'm sure there is a more efficient way of doing this but this is what i came up with.
Model/User.php
protected $rules = [
'email_address' => 'sometimes|required|email|unique:users,email_address, {{$id}}',
];
Model/BaseModel.php
public function validate($data, $id = null) {
$rules = $this->$rules_string;
//let's loop through and explode the validation rules
foreach($rules as $keys => $value) {
$validations = explode('|', $value);
foreach($validations as $key=>$value) {
// Seearch for {{$id}} and replace it with $id
$validations[$key] = str_replace('{{$id}}', $id, $value);
}
//Let's create the pipe seperator
$implode = implode("|", $validations);
$rules[$keys] = $implode;
}
....
}
I pass the $user_id to the validation in the controller
Controller/UserController.php
public function update($id) {
.....
$user = User::find($user_id);
if($user->validate($formRequest, $user_id)) {
//validation succcess
}
....
}
While updating any Existing Data Write validator as following:
'email' => ['required','email', Rule::unique('users')->ignore($user->id)]
This will skip/ignore existing user's id's unique value matching for the specific column.
Test below code:
$validator = Validator::make(
array(
'E-mail'=>$request['email'],
),
array(
'E-mail' => 'required|email|unique:users,email,'.$request['id'],
));
Since you will want to ignore the record you are updating when performing an update, you will want to use ignore as mentioned by some others. But I prefer to receive an instance of the User rather then just an ID. This method will also allow you to do the same for other models
Controller
public function update(UserRequest $request, User $user)
{
$user->update($request->all());
return back();
}
UserRequest
public function rules()
{
return [
'email' => [
'required',
\Illuminate\Validation\Rule::unique('users')->ignoreModel($this->route('user')),
],
];
}
update: use ignoreModel in stead of ignore
Very easy to do it ,
Write it at your controller
$this->validate($request,[
'email'=>['required',Rule::unique('yourTableName')->ignore($request->id)]
]);
Note : Rule::unique('yourTableName')->ignore($idParameter) , here $idParameter you can receive from get url also you can get it from hidden field.
Most important is don't forget to import Rule at the top.
If a login user want to update the email then auth() helper function will give us the login user id auth()->user()->id
Laravel helpers#method-auth
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore(auth()->user()->id),
],
]);
if Admin want to change the specific user information from User list then validation will be like this :
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($request->user),
],
Laravel validation#rule-unique
$request object contain the current route related model objects. Which gives the model.
Try dd($request)
Most answers to this question refer to email_address, but in Laravel's inbuilt authentication system, the email field name is just email. Here is an example of validating a unique field, i.e. an email on the update:
Form Requests look like this:
public function rules()
{
return [
'email' => [ 'required','email', Rule::unique('users')->ignore($this->id ?? 0)]];
}
?? 0 If you use this then if hare id does not exist this request will not give you an error
Save
Whenever you access the id property of $this->user, you may encounter an undefined property if you haven't injected the User model into your route. If that is the case, use:
public function rules()
{
return [
'email' => 'required|email|unique:users,email,'.$this->user()->id ?? 0,
];
}
?? 0 If you use this then if hare id does not exist this request will not give you an error
My solution:
$rules = $user->isDirty('email') ? \User::$rules : array_except(\User::$rules, 'email');
Then in validation:
$validator = \Validator::make(\Input::all(), $rules, \User::$messages);
The logic is if the email address in the form is different, we need to validated it, if the email hasn't changed, we don't need to validate, so remove that rule from validation.
For unique rule in the controller - which obviously will be different for the store method and the update method, I usually make a function within the controller for rules which will return an array of rules.
protected function rules($request)
{
$commonRules = [
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6"
];
$uniqueRules = $request->id
//update
? ['email_address' => ['required', 'email', 'unique:users,email' . $request->get('id')]]
//store
: ['email_address' => ['required', 'email', 'unique:users,email']];
return array_merge($commonRules, $uinqueRules);
}
Then in the respective store and update methods
$validatedData = $request->validate($this->rules($request));
This saves from defining two different rule sets for store and update methods.
If you can afford to compromise a bit on readability, it can also be
protected function rules($request)
{
return [
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6",
'email_address' => ['required', 'email', 'unique:users,email' . $request->id ?: null]
];
}

Categories