Update profile function - laravel

I have a function that check updates the users profile info. Currently, if I put |unique:users in the validator every time I try to update the profile info on the form it will not let me because a user (which is me) has my email. So I figured out the unique means that nobody, including the current user can have the email that is being updated.
So I need to compare the current auth email to the one in the database. If it matches then it is ok to update the profile info. I know this is simple but I am not sure how to implement it and if that is the right logic.
So where in this code would I post if (Auth::user()->email == $email){..update email...} http://laravel.io/bin/GylBV#6 Also, is that the right way to do this?
public function editProfileFormSubmit()
{
$msg = 'Successfully Updated';
$user_id = Auth::id();
$user = User::find($user_id);
$first_name = Input::get('first_name');
$last_name = Input::get('last_name');
$email = Input::get('email');
$phone_number = Input::get('phone_number');
$validator = Validator::make(Input::all(), array(
'email' => 'required|email',
'first_name' => 'required',
'last_name' => 'required',
'phone_number' => 'required'
));
if ($validator->fails()) {
return Redirect::route('edit-profile')
->withErrors($validator)
->withInput();
}else{
if(Input::hasFile('picture')){
$picture = Input::file('picture');
$type = $picture->getClientMimeType();
$full_image = Auth::id().'.'.$picture->getClientOriginalExtension();
if($type == 'image/png' || $type == 'image/jpg' || $type == 'image/jpeg'){
$upload_success = $picture->move(base_path().'/images/persons/',
$full_image);
if($upload_success) {
$user->picture = $full_image;
} else {
$msg = 'Failed to upload picture.';
}
}else{
$msg = 'Incorrect image format.';
}
}
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->email = $email;
$user->phone_number = $phone_number;
$user->save();
return Redirect::route('invite')->with('global', $msg);
}
}

Worry not, Laravel has already considered this potential issue! If you take a look at the docs for the unique validation rule you'll see that it can take some extra parameters. As it happens, you can give it an id to ignore when looking at the unique constraint. So what you need to do is work out the id for the current model to update and pass that in. In the case of updating a logged-in user's profile it's made easy by Auth::id() as you already have in your code.
$rules = [
'email' => ['required', 'email', 'unique:users,email,'.Auth::id()],
'first_name' => ['required'],
// etc...
];
Obviously I chose to use the array syntax for validation rules there, but you can do the same with the pip syntax too. In a less specific system (create-or-add in a crud postSave type action) you can still do it by simply dong something like $model = Post::find($id) and then if $model is null you're creating and you just use 'unique' whereas if $model is not null, use 'unique:table,field,'.$model->getKey().

Related

Laravel avoid duplication between existing data and new inputs

I have an edit form where it shows users, sub-users and I need to make my update method the way that it can update existed sub-users as well as add new ones.
Logic
User can have a maximum of 5 sub-users
Let's assume my user already have 2 sub-users s/he can add up to 3 more
I want to be able to update those 2 that are existed already
I want to be able to add those 3 new sub-users
Code
Here is what I have currently. Code is commented for better understanding
public function subUsersUpdate(Request $request, $id) {
$will = Will::where('id', $id)->where('user_id', Auth::id())->first();
// main user
$user = User::where('id', $will->user_id)->first();
// making custom emails for new users like (admin1#example.com)
// admin is email name of main user, originally (admin#gmail.com)
// 1~5 are added to names (separate those 5 sub-users)
// example.com is website domain
$userMail = substr($user->email, 0, strpos($user->email, '#'));
$websiteName = env('DOMAIN_NAME');
// here is what I get from edit form including 2 existed sub-users and 3 new sub-users
foreach($request->input('subs') as $index => $sub) {
// trying to separate existed sub-users from new ones
$existedUser = User::where('name', $sub)->where('user_id', $user->id)->first();
if($existedUser) {
// if already existed just update the name
$existedUser->update(['name' => $sub]);
} else {
// if new add them as new sub-user
$num = $index+1;
$password = str_random(15);
User::create([
'name' => $sub,
'email' => $userMail . $num ."#" . $websiteName,
'password' => Hash::make($password),
'user_id' => $user->id,
]);
}
}
return redirect()->back();
}
Error
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'admin4#example.com' for key 'users_email_unique'
It appears that my code works in order to separate old and new sub-users but the problem is it makes the same email for new-users as old ones based on $num provided in my foreach. I need somehow avoid that duplication.
Any suggestion?
Update
What I did
I've added hidden input in my form which has sub-user email as value (if user existed) and if user is newly added it is null.
Then I merged those emails array and names array into one
Finally I've validate if the email field is null or not in order to update or create new sub-user.
Issue
Issue is name of all sub-users will be same as last input (sub-user 5), regardless of user being newly created or updated all 5 get same name!
public function subUsersUpdate(Request $request, $id) {
$will = Will::where('id', $id)->where('user_id', Auth::id())->first();
$user = User::where('id', $will->user_id)->first();
$userMail = substr($user->email, 0, strpos($user->email, '#'));
$websiteName = env('DOMAIN_NAME');
//Changed part
$mails = $request->input('mails');
$names = $request->input('subs');
// created array of data
$finalInputs = [];
foreach($mails as $index => $mmm) {
foreach($names as $index2 => $nnn) {
$finalInputs[$index] = ['email' => $mmm, 'name' => $nnn];
}
}
foreach($finalInputs as $index => $sub) {
if(!empty($sub['email'])) {
$existedUser = User::where('email', $sub['email'])->where('user_id', $user->id)->first();
$existedUser->update(['name' => $sub['name']]);
// $userMail2 = substr($sub['email'], 0, strpos($sub['email'], '#'));
} else {
if($sub['name'] != null) {
$num = $index+1;
$password = str_random(15);
User::create([
'name' => $sub['name'],
'email' => $userMail . $num ."#" . $websiteName,
'password' => Hash::make($password),
'user_id' => $user->id,
]);
}
}
}
// end of changed parts
}
Using updateOrCreate()
updateOrCreate() can handle conditional updating or creating of records for you.
This could be what you are asking, hope you get the idea:
foreach($finalInputs as $index => $sub) {
$pwHash = Hash::make( str_random(15) );
$num = $index+1;
$search = [
'user_id' => $user->id,
'email' => $userMail . $num ."#" . $websiteName,
];
$update = [
'name' => $sub['name'],
];
// Only add 'password' for new users
if (empty($sub['email']))) {
$update['password'] = $pwHash;
}
User::updateOrCreate(
$search,
$update
);
}
This will update or create users with the given email address and user-id and create if they don't exist. I don't know how your form works in detail, but I think you can adjust to your exact use-case.

Laravel Socialite Facebook images are incorrect

I have a strange problem which I cannot figure out. I am using Laravel Socialite to allow login with Facebook account, there is a lot of users complaining that the profile image displayed on their account is incorrect, however the name etc is all fine.
It makes no sense to me as the name and the profile pic are pulled directly from FB at the same time.
public function socialUser(ProviderUser $providerUser)
{
$account = SocialFacebookAccount::whereProvider('facebook')->whereProviderUserId($providerUser->getId())->first();
if ($account) {
return $account->user;
} else {
$account = new SocialFacebookAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => 'facebook'
]);
$user = User::whereEmail( $providerUser->getId() )->first(); // changed from getEmail to getId as FB doesnt always give an email
if (!$user) {
$profilePicName = md5(rand(1,10000)) . ".jpg";
$contents = file_get_contents( $providerUser->avatar_original );
Storage::disk('local')->put( 'profiles/' . $profilePicName, $contents );
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
'profile_path' => $profilePicName
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}
}
Instead of using md5, you can use the UUID generator. One of the reasons for this problem because md5 generates the same hash for the same input. for instance, when you pass md5(111) it'll generate 698d51a19d8a121ce581499d7b701668. so if for a different user you generate the same hash key, the latest image profile will take a place and the former will replace by the latter.
Scenario:
User1:
$profilePicName = md5(111) . ".jpg";
$contents = file_get_contents( $providerUser->avatar_original );
Storage::disk('local')->put( 'profiles/' . $profilePicName, $contents );
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
'profile_path' => $profilePicName
]);
Scenario:
User2:
$profilePicName = md5(111) . ".jpg";
$contents = file_get_contents( $providerUser->avatar_original );
Storage::disk('local')->put( 'profiles/' . $profilePicName, $contents );
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
'profile_path' => $profilePicName
]);
Now they both have 698d51a19d8a121ce581499d7b701668.jpg saved in their profile. And in this case the first user profile will be the same as the second user image profile.

in laravel if condition not working in controller

i am trying to use if condition in controller ( IF IMAGE NOT UPLOADED it go to ELSE condition Or else go to IF ) but it was not working , it just redirecting registration from page when submitting a form
code
public function Enrollment(Request $request)
{
$this->validate($request, [
'name' => 'required|string|max:255',
'father_name' => 'required|string|max:225',
'address' => 'required|string|max:255',
'card_id' => 'required|string|max:255',
'image' => 'required|image|mimes:jpeg,png,jpg',
]);
if ($request->image != '')
{
$input['name'] = strtoupper ($request['name']);
$input['father_name'] = strtoupper ($request['father_name']);
$input['address'] = strtoupper ($request['address']);
$input['card_id'] = strtoupper ($request['card_id']);
$input['image'] = time().'.'.$request->image->getClientOriginalExtension();
$folder1 = public_path('IMAGE/');
$path1 = $folder1 . $input['image']; // path 1
$request->image->move($folder1, $input['image']); // image saved in first folder
$path2 = public_path('IMAGE/BACKUP_IMAGE/') . $input['image']; // path 2
\File::copy($path1, $path2);
}else{
$input['name'] = strtoupper ($request['name']);
$input['father_name'] = strtoupper ($request['father_name']);
$input['address'] = strtoupper ($request['address']);
$input['card_id'] = strtoupper ($request['card_id']);
}
Card::create($input);
return back()->with('success','Enrolled Successfully.');
}
try this
if($request->hasfile('user_image'))
Nice that you use laravel. At first I will give you some hints to improve your code snippet.
You've written
it just redirecting registration from page when submitting a form
that's correct, because if you submit the form without an image, the validation will say "false".
You can't check an required in this way:
if ($request->image != '') {
because it's required.
Actually your code skips the validation at all, it would be better if you use the following:
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'father_name' => 'required|string|max:225',
'address' => 'required|string|max:255',
'card_id' => 'required|string|max:255',
'image' => 'required|image|mimes:jpeg,png,jpg',
]);
if ($validator->fails()) {
Session::flash('error', $validator->messages()->first());
return redirect()->back()->withInput();
}
If you dump your dd($validator); you will see all opertunities to validate the $request. Your errors you will find here: $validator->errors().
If something went wrong you should redirect back with the
->withInput()
so all data will stay in the form. Also possible with some explanation for the user ->withErrors():
// message information for the user
$messages = $validator->errors();
$messages->add('Your explanation');
// redirect
return redirect()->route('index')->withErrors($messages)->withInput();
Actually I am unsure why you save all $request in $input.
You can check https://laravel.com/docs/5.8/validation#using-rule-objects that for find an great solution for the strtoupper() usement.
Helpful links:
https://laravel.com/docs/5.8/validation
https://laravel.com/docs/5.8/session#flash-data

Method not allowed exception while updating a record

Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpExceptionNomessage
I'm getting this error while trying to update a record in the database. Don't know what's the problem. This question might be a duplicate but I've checked all and couldn't find the answer. Please Help me with this.
Controller Update Method:
public function updateEvent(Request $request, $id=''){
$name = $request->name;
$startdate = date_create($request->start_date);
$start_date = $startdate;
$time = $request->start_time;
$start_time = $time;//date("G:i", strtotime($time));
$endDate = date_create($request->end_date);
$end_date =$endDate;
$time_e = $request->end_time;
$end_time = $time_e;//date("G:i", strtotime($time_e));
$location = $request->location;
$description = $request->description;
$calendar_type = $request->calendar_type;
$timezone = $request->timezone;
if ($request->has('isFullDay')) {
$isFullDay = 1;
}else{
$isFullDay = 0;
}
DB::table('events')->where('id', $id)->update(
array(
'name' => $name,
'start_date' => $start_date,
'end_date' => $end_date,
'start_time' => $start_time,
'end_time' => $end_time,
'isFullDay' =>$isFullDay,
'description' => $description,
'calendar_type' => $calendar_type,
'timezone' => $timezone,
'location' => $location,
));
// Event Created and saved to the database
//now we will fetch this events id and store its reminder(if set) to the event_reminder table.
if(!empty($id))
{
if (!empty($request->reminder_type && $request->reminder_number && $request->reminder_duration)) {
DB::table('event_reminders')->where('id', $id)->update([
'event_id' => $id,
'type' => $request->reminder_type,
'number'=> $request->reminder_number,
'duration' => $request->reminder_duration
]);
}
}
else{
DB::table('event_reminders')->insert([
'type' => $request->reminder_type,
'number'=> $request->reminder_number,
'duration' => $request->reminder_duration
]);
}
return redirect()->back();
}
Route:
Route::post('/event/update/{id}', 'EventTasksController#updateEvent');
Form attributes :
<form action="/event/update/{{$event->id}}" method="POST">
{{ method_field('PATCH')}}
i'm calling the same update function inside my calendar page and it working fine there. Don't know why it doesn't work here.
Check the routeing method.
Route::patch('/event/update/{id}', 'EventTasksController#updateEvent');
patch should be the method called on route facade.
Change your route to patch:
Route::patch('/event/update/{id}', 'EventTasksController#updateEvent');
For your comment:
You can send the method to the ajax call by something like data-method attribute on the element you click on,take the method and use it in your ajax call. see this question/answer for help. How to get the data-id attribute?

Laravel Simultaneously input one to many in database

I have a card, this card has tags. So a Card has many tags and a Tag belongsTo a Card.
A user fills a form. He gives both the information for the card aswell as the tags.
Now I need to give each tag the information 'card_id' so it can be connected.
Now is my problem that I don't know this 'card_id' yet because the database did not yet assign a id as they are both being created simultaneously.
My situation:
public function create(Request $request)
{
$this->validate($request,[
'function' => 'max:255',
'description' => 'max:255',
'rate' => 'max:255',
'location' => 'max:255'
]);
$card = new Card;
$card->user_id = Auth::id();;
$card->function = $request->function;
$card->description = $request->description;
$card->rate = $request->rate;
$card->location = $request->location;
// I also tried this: $card->tag()->saveMany($tagsArray); (Did not work)
$card->save();
$tagsArray = explode(',', $request->tagsarray);
foreach($tagsArray as $tagInput) {
$tag = new Tag;
$tag->card_id = 'Cant know this yet :(';
$tag->tag = $tagInput;
$tag->save();
}
return redirect('/page');
}
Does someone know how to go about this?
You may try something like this:
$card = new Card([
'card_name' => request()->get('card_name'),
'something_else' => request()->get('something_else')
]);
if($card->save()) {
$tags = [];
// Get the tag information from request
$tagsFromRequest[
['tag_title' => 'A Tag', 'tag_slug' => 'a_tag'],
['tag_title' => 'Another Tag', 'tag_slug' => 'another_tag']
];
foreach($tagsFromRequest as $tag) {
$tags[] = new Tag($tag);
}
$card->tags()->saveMany($tags);
}
Now, prepare your tags from request where each tag item should be an array as given above and I can't be more specific because you gave nothing that you've tried and which might help me to understand your scenario. Check the documentation.

Resources