Can't update user information in Laravel - laravel

On my current project (a school management system) I want to give admins the ability to register users. Admins can create courses and subjects for example, which I've managed to do using resource controllers. However, I thought I could do the same for users, since the process appears the same to me. That is: I can show, edit, create, update and delete users.
However, I've run into several problems so far. Right now I can create users, but not update them.
Here's my code:
web.php
Route::middleware(['auth', 'admin'])->group(function () {
Route::get('/admin', 'HomeController#admin');
Route::post('register', 'UserController#store');
Route::resources([
'admin/cursos' => 'CursoController',
'admin/turmas' => 'TurmaController',
'admin/semestres' => 'SemestreController',
'admin/materias' => 'MateriaController',
'admin/usuarios' => 'UserController',
]);
});
UserController.php
public function update(Request $request, $id)
{
$rules = array(
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'role' => 'required|string',
'password' => 'required|string|min:6|confirmed',
);
$validator = validator::make(Input::all(), $rules);
if ($validator->fails()) {
// return dd();
return Redirect::to('/admin/usuarios/' . $id . '/edit')
->withErrors($validator);
} else {
// store
$user = User::find($id);
$user->name = Input::get('name');
$user->email = Input::get('email');
$user->role = Input::get('role');
$user->password = Input::get('password');
$user->save();
// redirect
Session::flash('message', 'Sucesso!');
return Redirect::to('/admin/usuarios');
}
}
Validation fails every time I try to update user information. What exactly is going on here? I'm relatively new to Laravel, so I'm a bit lost now.

If the request is failing when a user is trying to update their information without changing the email address, you need additional logic to ignore the id for user associated with the email.
Sometimes, you may wish to ignore a given ID during the unique check. For example, consider an "update profile" screen that includes the user's name, e-mail address, and location. Of course, you will want to verify that the e-mail address is unique. However, if the user only changes the name field and not the e-mail field, you do not want a validation error to be thrown because the user is already the owner of the e-mail address.
To instruct the validator to ignore the user's ID, we'll use the Rule class to fluently define the rule. In this example, we'll also specify the validation rules as an array instead of using the | character to delimit the rules:
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
Applied to your set of validation rules it would look like:
$rules = array(
'name' => 'required|string|max:255',
'email' => [
'required',
'string',
'email,
'max:255',
Rule::unique('users')->ignore(auth()->id())
],
'role' => 'required|string',
'password' => 'required|string|min:6|confirmed',
);

You have to except the User ID ($id) in email validation, since u use "unique" rule.
you can check the guide in here
https://laravel.com/docs/5.6/validation#rule-unique

Related

how to edit user email in laravel

i want to edit my user email in laravel, but when i submit the form and then it gives me an error message
The selected Email is invalid.
what do I have to do?
whats wrong with this code?
//in Create Function
'email' => 'required|email|unique:users,email',
//in Update Function is this correct?
'email' => 'required|email|exists:users,email',
Controller
This is my userController for update users
public function update(Request $request, User $user)
{
$validator = Validator::make(
$request->all(),
[
'name' => 'required|string|max:30',
'email' => 'required|email|exists:users,email',
'role' => 'required',
'avatar' => 'required|string|max:150'
],
[],
$this->attributes()
);
if ($validator->fails()) {
$request['role'] = Role::select('id', 'name')->find($request->role);
return redirect()
->back()
->withInput($request->all())
->withErrors($validator);
}
DB::beginTransaction();
try {
$user->update([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'avatar' => parse_url($request->avatar)['path'],
]);
$user->syncRoles($request->role);
Alert::toast(
__('posts.alert.delete.message.success'),
'success'
);
return redirect()->route('users.index');
} catch (\Throwable $th) {
DB::rollBack();
Alert::toast(
__('posts.alert.delete.message.error', ['error' => $th->getMessage()]),
'errors'
);
return redirect()
->back()
->withInput($request->all())
->withErrors($validator);
} finally {
DB::commit();
}
}
You still want a unique validator, so the user can't update their account to someone else's email address and cause a conflict.
However, to prevent it from failing when the user isn't updating their email address (it would fail the unique validation, because a record already exists with that email - the user's own), you'll want to exempt the user's current record from the validation.
https://laravel.com/docs/9.x/validation#rule-unique
See "Forcing A Unique Rule To Ignore A Given ID":
// at the top of your file
use Illuminate\Validation\Rule;
'email' => [
'required',
'email',
Rule::unique('users')->ignore($user->id),
]
You're validating the request requiring the email to exist in the table :
'email' => 'required|email|exists:users,email',
You need to specify unique in order to check the value is not used in the table (same as creation)
'email' => 'required|email|unique:users,email',
You can't do either
'email' => 'exists:users,email'
or
'email' => 'unique:users,email'
for update function. because if you don't change the email you have to submit the old email to the controller which is not "unique" and if you do change it then it doesn't "exist" in the database.
Instead try it like this:
'email' => ['required', 'email', Rule::unique('users', 'email')->ignore($user)],
It means the email should be unique unless it is the email from current user.
See the Laravel docs for more information on this:
https://laravel.com/docs/9.x/validation#rule-unique

I have a problem with laravel validation logic when im trying to update my data

Hello guys im beginner in laravel and i need some help.I have a problem with my validation.When i store data in my bootstrap modal everyting is fine but when i press edit button and want to update, the same validation logic applies like when i create.When I want to update, if i don't change the name it won't update because it must be unique.
This is my Department Controller
public function store(Request $request)
{
$this->validate($request,[
'name'=>"required|unique:departments|max:255"
]);
$departmentId = $request->department_id;
Department::updateOrCreate(
['id' => $departmentId],
['name' => $request->name, 'description' => $request->description]
);
return response()->json(['success'=>'Department saved successfully.']);
}
As previously mentioned it would be ideal to have this be 2 different methods, but if you want this in one method you can achieve that. You will need to check if that department id is being passed or not to see if this is an update or create, then adjust the rule based on this. You can try something like this:
public function store(Request $request)
{
$unique = \Illuminate\Validation\Rule::unique('deparments');
if ($request->has('deparment_id')) {
$unique->ignore($request->department_id);
}
$this->validate($request, [
'name' => [
'required', $unique, 'max:255',
],
]);
$departmentId = $request->department_id;
Department::updateOrCreate(
['id' => $departmentId],
['name' => $request->name, 'description' => $request->description]
);
return response()->json(['success'=>'Department saved successfully.']);
}
This assumes the deparment_id is only passed for updates.
you can do this :-
$this->validate($request,[
'name' => 'required|unique:departments|max:255,'. $request->department_id,
]);

Save extra data while User Registration

I am using Breeze template.I am working with User Registration. My store() user function is like below
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|confirmed|min:8',
]);
Auth::login($user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]));
event(new Registered($user));
return redirect(RouteServiceProvider::HOME);
}
I would like to save more data (like user Date of Birth) as User details in another table while Registering User. I would like to maintain one to one relationship with User table and User details table.
Actually I would like to attache something with this event(new Registered($user));. So that I can save data to another Table along with registration. How can I do that ?
Where can I get the code of this new Registered($user) ?
create a new instance
and save all other fields with id to another table
$model2 new model2();
$model->col = $request->1;
$model->fk= $user->id;
$model->save();

Creation of related Models on auth RegisterController in laravel

In my application, I have tables related to users and some of these tables require a row be inserted as soon as a User is registered.
For example, I have the following models:
UserProfile,
UserAssignedRole,
UserSettings
As soon as a User successfully registers, they will need a corresponding row in the DB.
I've done the following:
protected function create(array $data)
{
$user = User::create([
'username' => $data['username'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
UserProfile::create([
'user_id' => $user->id,
]);
UserAssignedRole::create([
'user_id' => $user->id,
'role_id' => 1
]);
UserSettings::create([
'user_id' => $user->id,
'nsfw' => 1
]);
return $user;
}
I'm looking for a better and more elegant way to achieve this. Is there a "Laravel" way in achieving this?
In the Larvel docs there's a chapter about Recursively Saving Models & Relationships. This is probably what you're looking for. They specify the following example:
$post = App\Post::find(1);
$post->comments[0]->message = 'Message';
$post->comments[0]->author->name = 'Author Name';
$post->push();
You could achieve something similar by creating a user including all its relationships in one push().

Query regarding using Sentinel with Laravel and the $fillable array

I'm using Cartalyst Sentinel for the user authentication within Laravel.
I've created my form to add a new user.
For some strange reason the password does not come through Sentinel::register() unless I put the password field into the $fillable array in the User class model.
This is a potential security issue.
How can I get around this? There must be something I am missing when creating a new user with Sentinel (and the Sentinel documents are very light on useful info).
Just a quick rundown of what I'm doing code wise. I have my array filled with the fields that are required to create a user. This array is passed into Sentinel::register(). It all seems to go through fine, but when I go to look in the database, the password field is blank.
$newUser = array(
'_token' => Input::get('_token'),
'email' => Input::get('email'),
'password' => Input::get('password'),
'first_name' => Input::get('first_name'),
'middle_name' => Input::get('middle_name'),
'last_name' => Input::get('last_name'));
$user = Sentinel::register($newUser);
Just a side note: unfortunately I cannot switch the authentication system. I need to use Sentinel.
Just another way of doing almost same as Jeff's answer.
This should work based on Sentinel code, tho i have not used Sentinel. Test before deploying.
$newUser = array(
'_token' => Input::get('_token'),
'email' => Input::get('email'),
'password' => Input::get('password'),
'first_name' => Input::get('first_name'),
'middle_name' => Input::get('middle_name'),
'last_name' => Input::get('last_name')
);
Sentinel::register($newUser, function($user) use ($newUser) {
try {
return $user->password = \Hash::make($newUser['password']);
} catch(RuntimeException $e) {
return false;
}
});
Callback runs after fill method, so it should bypass $fillable restriction and you can remove password from fillable if your design requires that.
If false returned in callback then user will not be created.
You'd need to set the password option manually on a new user if you don't want to make it a fillable property.
$newUser = array(
'_token' => Input::get('_token'),
'email' => Input::get('email'),
'first_name' => Input::get('first_name'),
'middle_name' => Input::get('middle_name'),
'last_name' => Input::get('last_name'));
$user = Sentinel::register($newUser);
$user->password = Input::get('password');
$user->save();
You probably need to be hashing the password before you set it too, right? Something like $user->password = \Hash::make(Input::get('password'));. Unless Sentinel does that automatically.

Resources