How to save multiple related models at the same time - php

In my RegistrationController#store, I am doing the following:
Create a user (User: hasMany() Points, hasOne() Profile, belongsToMany() Role)
Attach a role (Role: belongsToMany() User)
Create a profile (Profile: belongsTo() User)
Set initial score to 0 (Points: belongsTo() User)
I realized if one of these steps fails, for example if due to slow connectivity the profile is somehow not created, my app will break. Here is my store method:
public function store(){
$profile = new Profile();
$points = new Points();
$this->validate(request(),[
'name' => 'required',
'username' => 'required|unique:users',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed',
'role_id' => 'required|between:1,2'
]);
$user = User::create([
'name' => request('name'),
'username' => request('username'),
'email' => request('email'),
'password' => bcrypt(request('password'))
]);
$role_student = Role::where('title', 'Student')->first();
$role_parent = Role::where('title', 'Parent')->first();
if(request()->input('role_id') == 1){
$user->roles()->attach($role_student);
} else if(request()->input('role_id') == 2){
$user->roles()->attach($role_parent);
}
$profile->user_id = $user->id;
$profile->date_of_birth = Carbon::createFromDate(request('year'),request('month'),request('day'));
$profile->institution = request('institution');
$profile->class = request('class');
$profile->division = request('division');
$profile->photo = 'propic/default.png';
$profile->bio = 'I am a Member!';
$profile->social_link = 'http://facebook.com/zuck';
$profile->save();
auth()->login($user);
\Mail::to($user)->send(new Welcome($user));
$points->updateOrCreateAndIncrement(0);
return redirect()->home();
}
It is worth mentioning that, all of the data is coming from a registration form. How can I execute all these steps at a time (or, in one statement) so that if the statement executes successfully, I will have a perfectly synchronized registration, otherwise, no data will be persisted to the database?

Use transactions.
Before the first DB operation, in your case: User::create, use this:
DB::beginTransaction();
From now on, put all of your db operations in try/catch braces and if any exception happens, use:
DB::rollBack();
And at the end of the function, before return statement, put this:
DB::commit();
If you can have all your operations in the same place, it's easier to do this:
DB::transaction(function () {
//all your db opertaions
}, 2);

Related

Check if record exists while registering user

In my Register controller - I have the following method to check if a record exists in another table before creating a user:
public function getCompanyDetails($id)
{
$details = Company::where('company_id', $id)->first();
return $details;
}
protected function create(array $data)
{
$company_id = $data['com_id'];
$company_details = $this->getCompanyDetails($company_id);
if ($company_details == null) {
return redirect()
->back()
->with('warning', 'We could not find the company');
} else {
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
}
However when the company record is not found. I'm getting the following error message:
Cannot use object of type Illuminate\Http\RedirectResponse as an array
I believe it's expecting a return of type user. But how can I redirect back to the registration page if the company is not found?
Thanks in Advance
Try the method withErrors():
Redirect::back()->withErrors(['warning', 'We could not find the company']);
I however recommend you to use the validation rule Exists instead of having more queries and manually return a message. You can do it like so:
$request->validate([
'company_id' => 'required|integer|exists:App\Company,id',
]);
Then you won't need the extra logic and the other method.
Source: https://laravel.com/docs/7.x/validation#rule-exists

Laravel Redirection and logic queue with email verification

I have one form in frontend where I have there is some city details , rooms details and user registration in one form like I have city name , room name , address etc email addresss and password in same form and I have done 2 logics in one controller for creating cities and registering user
It is saving the both data in correct table in the database
but I want that first user should register and if user is vcerified only the room details should be saved in database
I am in confusion wheather to apply if again or what
public function checkLogin(Request $request)
{
$user = User::create([
'name'=>$request->name,
'email'=>$request->email,
'password'=>$request->password,
'role_id' => config('quickadmin.default_role_id'),
]);
if ($user) {
if (Auth::check()) {
$city = TotalCity::create([
'name'=>$request->name,
'created_by'=>$request->created_by_id,
]);
}
return redirect()->to('/admin/home');
}
}
Let me show you how I'd probably write this logic:
public function checkLogin(Request $request)
{
$user = User::firstOrCreate([
'email'=> $request->email,
],
[
'name'=> $request->name,
'password'=> bcrypt($request->password),
'role_id' => config('quickadmin.default_role_id'),
]);
if (Auth::check()) {
// it's not clear if you utilize `email_verified_at`, if so
// if (Auth::check() && Auth::user()->email_verified_at) {
$city = TotalCity::create([
'name'=>$request->name,
'created_by'=> Auth::user()->id, // or $user->id depending on your preference
]);
}
return redirect('/admin/home');
}
The firstOrCreate() checks if an entry with that email exists, it gets it, otherwise creates it.
Furthermore, if I want to check for Authentication, I'd use 'auth' middleware in my route.
Route::get('example', 'ExampleController#checkLogin')->middleware('auth');
That removes the need of entire check:
if (Auth::check()) { ... }

Laravel- Creating new user only if there is data in another table

I have two tables the first one is the user table which have these property id, username, email,remember_token, createdat, updateat another table is called received_pay having id, email, token my task is to check if the email, and token entered by the user must match the ones in received_pay otherwise new user is not created, thanks for your time in advanced,
I'm trying to create new user on a condition that if there is data in another table then new user is created otherwise not I have put my code inside if else statement and is throwing errors.
my function for creating new user is listed below:
protected function create(array $data)
{
/*$exists = \DB::table('received_pay')->where('email', $data['email'])->first(); */
$exists=\DB::table('received_pay')->where('email', '=', $data['email'])->where('token', $data['token'])->exists();
if ($exists === null)
{
// user doesn't exist
return User::create([
'username' => $data['username'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'token' => $data['token'],
]);
}
else
{
return null;
}
}
I think that the best approach in Laravel is create a middleware to protect this url. If you already have this create user feature working is better don't modify it.
So the first step would be create a middleware (https://laravel.com/docs/5.5/middleware) to add your safeguard, something like this:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckPayment
{
public function handle($request, Closure $next)
{
$payment = \DB::table('received_pay')->where('email', $request->email)->where('token', $request->token]);
if (!$payment->count()) {
return redirect('no-payment');
}
return $next($request);
}
}
Then you would need to create a route to handle this invalid creation users (this no-payment url).
And finally you can protect your create-user url in route, by adding your middleware in your kernel.php file...
protected $routeMiddleware = [
...
'payment' => \App\Http\Middleware\CheckPayment::class,
];
and in your web.php route file:
Route::post('user', 'UserController#create')->middleware('payment');
In this way your code will look cleaner, tidier, and closer to the way Laravel works.
I hope it would work fine for you.
If you wish to do it with if statement then do it like below
protected function create(array $data)
{
/*$exists = \DB::table('received_pay')->where('email', $data['email'])->first(); */
$exists=\DB::table('received_pay')->where('email', '=', $data['email'])->where('token', $data['token']);
if (!$exists->count())
{
// user doesn't exist
return User::create([
'username' => $data['username'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'token' => $data['token'],
]);
}
else
{
return null;
}
}
the count() in the if is to make the statement evaluate true if the data exists and false otherwise and create the new user.
I think that solves your problem.

How can I login the user manually in Laravel?

Here is my code:
public function register_and_login(Request $request)
{
$this->validator_short($request->all())->validate();
$user = User::where('cell_phone', $request->cell_phone)->first();
// already registered
if ( is_null($user) ) {
$user_id = User::create([
'name' => $request->name,
'cell_phone' => $request->cell_phone,
'password' => bcrypt($request->password),
]);
} else {
$user_id = $user->id;
}
$this->guard()->login($user_id);
dd('user is logged in now');
}
My code works when the user isn't registered so far and we create it. But when he has registered already, my code throws this error:
How can I fix it?
Make sure the User model extends Authenticatable:
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
Also, use auth() helper or Auth:: facade:
$user = User::create(['name' => $request->name,
'cell_phone' => $request->cell_phone,
'password' => bcrypt($request->password)
]);
auth()->login($user);
https://laravel.com/docs/5.5/authentication#other-authentication-methods
Change your else part to -
else {
$user_id = $user;
}
The login function is not asking you for an integer id, it's asking for an Authenticable. In any default Laravel application, that's usually the User Model.
The problem lies in your else statement. You don't need to set $user_id to the id of the user you loaded when checking the cell number. You just need to use the user you loaded. Based on your logic, you don't even need the else statement.
A possible separate issue with your logic,is that you're checking to see if the cell number exists, and if it does, logging in that user, not the user that your doing the check for. This may be desired behaviour, but it doesn't seem like.
public function register_and_login(Request $request)
{
$this->validator_short($request->all())->validate();
$user = User::where('cell_phone', $request->cell_phone)->first();
// already registered
if ( is_null($user) ) {
$user = User::create([
'name' => $request->name,
'cell_phone' => $request->cell_phone,
'password' => bcrypt($request->password),
]);
}
$this->guard()->login($user);
}

how to check if a user email already exist

In laravel, when a new user is registering to my site and the email they use already exist in the database. how can tell the user that the email already exist ?. I am new to laravel framework. A sample code would be nice too.
The validation feature built into Laravel lets you check lots of things, including if a value already exists in the database. Here's an overly simplified version of what you need. In reality you'd probably want to redirect back to the view with the form and show some error messages.
// Get the value from the form
$input['email'] = Input::get('email');
// Must not already exist in the `email` column of `users` table
$rules = array('email' => 'unique:users,email');
$validator = Validator::make($input, $rules);
if ($validator->fails()) {
echo 'That email address is already registered. You sure you don\'t have an account?';
}
else {
// Register the new user or whatever.
}
);
Laravel has built-in human readable error messages for all its validation. You can get an array of the these messages via: $validator->messages();
You can learn more about validation and what all you can do with it in the Laravel Docs.
Basic Usage Of Unique Rule
'email' => 'unique:users'
Specifying A Custom Column Name
'email' => 'unique:users,email_address'
Forcing A Unique Rule To Ignore A Given ID
'email' => 'unique:users,email_address,10'
Adding Additional Where Clauses
You may also specify more conditions that will be added as "where" clauses to the query:
'email' => 'unique:users,email_address,NULL,id,account_id,1'
The above is from the documentation of Laravel
You could add:
public static $rules = [
'email' => 'unique:users,email'
];
You can add more rules to the $rules like:
public static $rules = [
'email' => 'required|unique:users,email'
];
It will automatically produce the error messages
and add:
public static function isValid($data)
{
$validation = Validator::make($data, static::$rules);
if ($validation->passes())
{
return true;
}
static::$errors = $validation->messages();
return false;
}
to the model User.php
Then in the function you're using to register, you could add:
if ( ! User::isValid(Input::all()))
{
return Redirect::back()->withInput()->withErrors(User::$errors);
}
if(sizeof(Users::where('email','=',Input::get('email'))->get()) > 0) return 'Error : User email exists';
The great resource is only Laravel Documentation #
enter link description here
I also did like below when integrating user management system
$user = Input::get('username');
$email = Input::get('email');
$validator = Validator::make(
array(
'username' => $user,
'email' => $email
),
array(
'username' => 'required',
'email' => 'required|email|unique:users'
)
);
if ($validator->fails())
{
// The given data did not pass validation
echo 'invalid credentials;';
// we can also return same page and then displaying in Bootstap Warning Well
}
else {
// Register the new user or whatever.
$user = new User;
$user->email = Input::get('email');
$user->username = Input::get('username');
$user->password = Hash::make(Input::get('password'));
$user->save();
$theEmail = Input::get('email');
// passing data to thanks view
return View::make('thanks')->With('displayEmail', $theEmail);
}
public function userSignup(Request $request, User $data){
# check user if match with database user
$users = User::where('email', $request->email)->get();
# check if email is more than 1
if(sizeof($users) > 0){
# tell user not to duplicate same email
$msg = 'This user already signed up !';
Session::flash('userExistError', $msg);
return back();
}
// create new files
$data = new User;
$data->name = $request->name;
$data->email = $request->email;
$data->password = md5($request->password);
$data->save();
//return back
Session::flash('status', 'Thanks, you have successfully signup');
Session::flash('name', $request->name);
# after every logic redirect back
return back();
}
I think when u try something like this you earn a smooth check using Model
We can use the Validator.
In your Controller.
$validator = $request->validate([
'name' => 'required',
'phone' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required',
]);
In View
#error('email') <span class="text-danger error">{{ $message }}</span>#enderror
$this->validate($request, [
'fname' => 'required',
'lname' => 'required',
'email' => 'required|min:4|email|unique:users',
'password' => 'required',
]);
Try This

Categories