How to send data colected with Laravel Livewire to Fortify? - laravel

I'm not familiar with Vue.js at all, so found a good replacement using Livewire.
The challenge that I've got to solve is to have a user friendly registration on my website using Fortify + Livewire. The registration process is a multistep one and depends on the choices that the user makes it will load the relative fields.
So far I set up the Fortify views by adding in the FortifyServiceProvider.php file the following code:
Fortify::loginView(function () {
return view('auth.login');
});
Fortify::registerView(function () {
return view('auth.register');
});
The auth/login.blade.php view loading the livewire component which is basically a form:
<form action="{{ route('register') }}" method="POST" wire:submit.prevent="submit">
/**
* Here would go the inputs that must be shown depends on what users choice
* (is it an ordinar user or a company)
*/
<button type="submit">Save<button/>
</form>
The multiform challenge would be resolved by adding $step property into the Register.php class:
class RegisterForm extends Component
{
public $step;
public function mount()
{
$this->step = 0;
}
public function submit()
{
if ($this->step < 3) {
$this->step++;
} else {
// pass all the data to the fortify register method
// <-- Here is my trouble!
}
}
}
which will be incremented by passing each of the registration steps ($this->step++).
The most important thing that is quite complicated for me is how to prevent form submission to have the validation + form changes and by the end all the set of the data to pass trough Fortify registration process?

Look at the fortify Controller for register
public function store(Request $request, CreatesNewUsers $creator): RegisterResponse
{
event(new Registered($user = $creator->create($request->all())));
$this->guard->login($user);
return app(RegisterResponse::class);
}
T
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use Laravel\Fortify\Contracts\CreatesNewUsers;
use Livewire\Component;
class Register extends Component
{
public $name;
public $email;
public $password;
public $password_confirmation;
public function submit(CreatesNewUsers $creator)
{
event(new Registered($user = $creator->create([
'name' => $this->name,
'email' => $this->email,
'password' => $this->password,
'password_confirmation' => $this->password_confirmation,
])));
Auth::guard()->login($user);
$this->redirect('home');
}
public function render()
{
return view('livewire.register');
}
}
Something like this will work for your use case.
You are still using the fortify Action and Still Firing the Event

The response is to use app container
<?php
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use App\Actions\Fortify\CreateNewUser;
use Livewire\Component;
class Register extends Component
{
public $name;
public $email;
public $password;
public $password_confirmation;
public function submit()
{
event(new Registered($user = app(CreateNewUser::class)->create([
'name' => $this->name,
'email' => $this->email,
'password' => $this->password,
'password_confirmation' => $this->password_confirmation,
])));
Auth::guard()->login($user);
$this->redirect('home');
}
public function render()
{
return view('livewire.register');
}
}

The response is to use dependency injection by injecting the Fortify CreateNewUser action in the mounting method of the Livewire component.
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use App\Actions\Fortify\CreateNewUser;
use Livewire\Component;
class Register extends Component
{
public $name;
public $email;
public $password;
public $password_confirmation;
protected $creator;
public function mount(CreateNewUser $creator)
{
$this->creator = $creator;
}
public function submit()
{
event(new Registered($user = $this->creator->create([
'name' => $this->name,
'email' => $this->email,
'password' => $this->password,
'password_confirmation' => $this->password_confirmation,
])));
Auth::guard()->login($user);
$this->redirect('home');
}
public function render()
{
return view('livewire.register');
}
}

you can use blade example
#if($step > 3)
<input name="name" type="text">
#endif

Related

Temporary identifier passed back by server does not match laravel socialite

I am facing an issue when trying to login and register a user using Twitter. Google is working except for Twitter. I cant seem to figure it out.
Temporary identifier passed back by server does not match that of stored temporary credentials. Potential man-in-the-middle.
<?php
namespace App\Http\Controllers;
use Exception;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
class TwitterController extends Controller
{
protected $redirectTo = '/home';
public function redirectToProvider($provider)
{
return Socialite::driver($provider)->redirect();
}
public function handleProviderCallback($provider)
{
$user = Socialite::driver($provider)->user();
$authUser = $this->findOrCreateUser($user, $provider);
Auth::login($authUser, true);
return redirect($this->redirectTo);
}
public function findOrCreateUser($user, $provider)
{
$authUser = User::where('provider_id', $user->id)->first();
if ($authUser) {
return $authUser;
}
return User::create([
'name' => $user->getName(),
'username' => $user->getName(),
'email' => $user->getEmail(),
'provider' => $provider,
'provider_id' => $user->getId()
]);
}
}

Laravel Roles and Permissions based on Role specific Ability

I have a project in which I want a Specific page to be viewed by a specific user which have a role of viewing for example I have User 1 that has an Admin Role and the Admin Role has the Ability to View this page in my design I made 3 models Users, Roles, and Abilities
User Model:
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password','district','area','committee','position',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function answer()
{
return $this->hasMany('App\Answer');
}
public function roles()
{
return $this->belongsToMany('App\Role');
}
public function hasRole($role)
{
if ($this->roles()->where('name', $role)->first()) {
return true;
}
return false;
}
public function assignRole($role)
{
$this->roles()->save($role);
}
}
Role Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
protected $fillable = ['name'];
public function abilities()
{
return $this->belongsToMany('App\Ability');
}
public function hasAbility($ability)
{
if ($this->abilities()->where('name', $ability)->first()) {
return true;
}
return false;
}
public function assignAbility($ability)
{
$this->abilities()->save($ability);
}
public function users()
{
return $this->belongsToMany('App\User');
}
}
Ability Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ability extends Model
{
protected $fillable = ['name'];
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
This is my UserPolicy:
<?php
namespace App\Policies;
use App\User;
use App\Role;
use Illuminate\Auth\Access\HandlesAuthorization;
class UserPolicy
{
use HandlesAuthorization;
public function view (Role $role)
{
return $role->hasAbility('view');
}
public function manage (User $user)
{
return true;
}
public function edit (User $user)
{
return true;
}
public function update (User $user)
{
return true;
}
public function add (User $user)
{
return true;
}
}
And the Controller of The Policy
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\User;
use App\Role;
class MemberController extends Controller
{
public function index(Role $role)
{
$this->authorize('view', $role);
return view ('members.create')->with('users', User::all());
}
public function manage(User $user)
{
$this->authorize('manage', $user);
return view ('members.manage')->with('users', User::all());
}
public function edit(User $user)
{
$this->authorize('edit', $user);
return view ('members.edit')->with('user', User::all())->with('roles', Role::all());
}
public function update(Request $request, User $user)
{
$this->authorize('update', $user);
$user->roles()->sync($request->roles);
return redirect('/members/edit');
}
public function store(User $user)
{
$this->authorize('add', $user);
$this->validate(request(), [
'name' => ['required', 'string', 'max:255'],
'district' => ['required', 'string', 'max:255'],
'area' => ['required', 'string', 'max:255'],
'committee' => ['required', 'string', 'max:255'],
'position' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
$data = request()->all();
$member = new User();
$member->name = $data['name'];
$member->district = $data['district'];
$member->area = $data['area'];
$member->committee = $data['committee'];
$member->position = $data['position'];
$member->email = $data['email'];
$member->password = Hash::make($data['password']);
$member->save();
return redirect('/members/create');
}
}
The index function should be the one related to the function view in the UserPolicy
and this is the can located in my blade.php file
#can('view', \App\Role::class)
<li class="">
<a class="" href="/members/create">
<span><i class="fa fa-user-plus" aria-hidden="true"></i></span>
<span>Add Member</span>
</a>
</li>
#endcan
in the policy when I link it to the name of the role of the logged in user everything works just fine but if I want to link it to an ability of the role it doesn't work so any idea on how the View Function in the UserPolicy should be implemented ?
The first parameter that is passed to the policy is the authenticated User, not its Role. I don't think it works. Maybe if you reimplement using an EXISTS query.
public function view (User $user)
{
return $user->roles()->whereHas('abilities', function ($ability) {
$ability->where('name', 'view');
})
->exists();
}
->exists() turns the query into an EXISTS query, which will return a boolean value if the query finds anything without having to return any rows.
https://laravel.com/docs/7.x/queries#aggregates
You could put that logic into an User method.
# User model
public function hasAbility($ability): bool
{
return $this->roles()->whereHas('abilities', function ($ability) {
$ability->where('name', 'view');
})
->exists();
}
public function view (User $user)
{
return $user->hasAbility('view');
}

Pass variable from controller to notification in Laravel

I am finding it hard to understand the examples from the docs to the scenario I am having. In my project I have an application form which filled up by the user then admin will update that form once the application is approved, canceled etc.
Now I want to notify the user that her/his application has been approved, canceled etc.
in my controller:
public function update(Request $request, $id)
{
$this->validate($request, [
'status' => 'required'
]);
$requestData = $request->all();
$loanapplication = LoanApplication::findOrFail($id);
$loanapplication->update([
"status" => $request->status,
"admin_notes" => $request->admin_notes,
"date_approval" => $request->date_approved
]);
if($request->notifyBorrower = 'on') {
$user_id = $loanapplication->user_id;
$status = $request->status;
$this->notify(new AdminResponseToApplication($user_id));
}
return redirect()->back()->with('flash_message', 'LoanApplication updated!');
}
In my AdminResponseToApplication.php I like to achieve this
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class AdminResponseToApplication extends Notification implements ShouldQueue
{
use Queueable;
public function __construct()
{
//
}
public function via($notifiable)
{
return ['mail','database'];
}
public function toMail($notifiable)
{
return (new MailMessage)
->line(.$user->nameHere. 'your application has been '.$statusHere.'.')
->action('check it out', url('/'))
->subject('Regarding with your loan application')
->line('This is system generated. Do not reply here.');
}
public function toDatabase($notifiable)
{
return [
'user_id' => $user->nameHere,
'status' => $statusHere,
'title' => .$user->nameHere. 'your application has been '.$statusHere.'.',
'url' => '/'
];
}
}
How can I achieve that? Thank you in advance!
Get user object and call function notify() on it. $this->notify() will not work because $this is not an instance of User class.
$user = User::find($user_id);
$user in the $user->notify(new AdminResponseToApplication($data)) function is available in notification class as $notifiable.
You can get any value of that object using $notifiable->name etc.
Remember:
AdminResponseToApplication is a class and you can do anything with it that a php class can.
So you can pass as many variables as you want to AdminResponseToApplication class in constructor and do what you want.
$user->notify(new AdminResponseToApplication($data))
As shown above I am sending a $data object to the class which is available in the constructor.
In the class
class AdminResponseToApplication extends notification implements ShouldQueue{
use Queueable;
public $myData;
public function __construct($data)
{
$this->myData = $data; //now you have a $data copied to $this->myData which
// you can call it using $this->myData in any function of this class.
}
}

Laravel : transforming a request into another

I want to log my users as soon as they register. here's my UserController's code (which works) :
<?php
namespace App\Http\Controllers;
use App\Http\Requests\Login;
use App\Http\Requests\Register;
use App\User;
class UserController extends Controller
{
public function register(Register $request)
{
User::create($request->all());
$loginRequest = new Login();
$loginRequest['email'] = $request->get('email');
$loginRequest['password'] = $request->get('password');
return $this->login($loginRequest);
}
public function login(Login $request)
{
return 'ok';
}
}
I feel I'm doing something ugly with my $loginRequest. Is there a neater way to do the same ? Aka transform my Register request into a Login request ?
You are simply trying to logged in user into his account after the registration so use Auth::login($user)
class UserController extends Controller
{
public function register(Register $request)
{
$user = User::create($request->all());
\Auth::login($user);
}
}
As soon as user register you can use this snippet of code to attempt a login
if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) {
return Redirect::route('dashboard');
}
So the code should be
User::create($request->all());
$loginRequest = new Login();
$loginRequest['email'] = $request->get('email');
$loginRequest['password'] = $request->get('password');
if (Auth::attempt(['email' => $request->get('email'),
'password' => $request->get('password')])) {
return Redirect::route('dashboard');
}

Undefined property: Illuminate\Validation\Validator::$errors in laravel

Undefined property: Illuminate\Validation\Validator::$errors in laravel
here is my controller file how to solve it i think here problem is any namespace where is it i do not know please guide me
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Route;
use Input;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Http\Request;
use App\models\Designation;
use Validator;
use Illuminate\Support\Facades\Response;
class Cdesigination extends Controller
{
public $flight;
public function __construct(){
$this->flight = new Designation;
}
public function index()
{
return view('designation');
}
public function techer(Request $request) {
$Validator =Validator::make(array(
'name'=>Input::get('name'),
'detail'=>Input::get('detail')
),array(
'name' => 'required',
'detail' => 'required'
));
if ($Validator->fails()) {
return Response::json([
'success'=>false,
'error' =>$Validator->errors->toArray()
]);
}
else{
$this->flight->name = $request->name;
$this->flight->detail = $request->detail;
$this->flight->save();
return Response::json([
'success'=>true]);
}
}
$Validator->errors()->toArray()
Errors() is function, so the braces are important

Resources