Laravel run code when new user registrated with default registration code - laravel

Im running a laravel 6.9 application with default authentication/registration.
I want to maintain the default registration process but i want to run a curl command if a user has registered.
Is it possible to hook into the default registration process and extend it with extra code?

Observer is good point in code where you can, well, observe if user is just registered but good place to put additional code after user has been registered is event/listener group. There is already Registered event set in EventServiceProvider so you would need to put additional listener beside one already set there (for sending email to newly registered user if opted). To have all sorted next steps should be followed (disclaimer: I am taking that you use all default auth code so far):
First copy registered(Request $request, $user) method from Illuminate\Foundation\Auth\RegistersUsers.php trait to default App\Http\Controllers\Auth\RegisterController
/**
* The user has been registered.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function registered(Request $request, $user)
{
//
}
So you would override that piece of default code which is meant to stay intact (as should every code from vendor directory).
Then, you would need to create listener. In App\Providers\EventServiceProvider::listen array, add one more class into value array so it should looks like
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
\App\Listeners\FooBarBaz::class,
],
];
Don't bother for not having created class already, next artisan command will do that for you:
php artisan event:generate
Now, in \App\Listeners\FooBarBaz::class you can make your custom code related to new user:
namespace App\Listeners;
use Illuminate\Auth\Events\Registered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class FooBarBaz
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param Registered $event
* #return void
*/
public function handle(Registered $event)
{
// $event->user is accessible here
//
// this method should return void, it is just executed
}
}
Now, back to registered method of RegisterController. Here you would need to initiate event:
/**
* The user has been registered.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function registered(Request $request, $user)
{
event(new \Illuminate\Auth\Events\Registered($user));
}
And you are done.
I wanted to show you use of already lot of prebuilt code although Observer is also good place. But also for calling event; I wouldn't put more code than this event(new \Illuminate\Auth\Events\Registered($user)); line into UserObserver::created(User $user). Whole part with event/listener is very good and decoupled now. Of course, you can make even custom event not using default Illuminate's one, just set that new key => value into EventServiceProvider.
Events
Observers

Related

How to perform action globally when record get updated in laravel

Is that possible to run this job UpdateRateZone globally wheneven Consignment Model gets updated anywhere in the system?
One method is to use Observer but observer doesn't work when update multiple reccord at once like
Consignment::where('status',1)->update(['address'=>'This']);
Is there anything else we can do?
As per laravel docs :
When issuing a mass update via Eloquent, the saving, saved, updating,
and updated model events will not be fired for the updated models.
This is because the models are never actually retrieved when issuing a
mass update.
Laravel does not fire updated event in case of mass update, so its not possible as per my knowledge. Other way is to do manually.
Other than observers there is methods such using closures for events and Registering events manually but all these methods would work if only laravel trigger an event on mass updation .
Yes you can create a Event Listener for your model. You can read up on more info here
In short first you need to create an Event for the needed model, so if its a Updated event create something like this.
php artisan make:event Consignment/Updated
In that file add
class Updated
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* #var Consignment
*/
public $consignment;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Consignment $consignment)
{
$this->consignment= $consignment;
}
/**
* Get the event consignment property
*
* #return Consignment
*/
public function getConsignment()
{
return $this->consignment;
}
}
Now you must create a Listener for this event
php artisan make:listener Consignment/UpdatedEvent
And in the handle function add youre logic
/**
* Handle the event.
*
* #param Updated $event
* #return void
*/
public function handle(Updated $event)
{
//
}
And all that is left after that is to register the events for you Model and you do that in your Consignment.php class where you add
/**
* The event map for the category.
*
* #var array
*/
protected $dispatchesEvents = [
'updated' => Updated::class,
];
When you do this:
Model::where('status',1)->update([some stuff]);
Query Builder's update() method is executed instead of Eloquent's update() method.
If you want to trigger Eloquent events, you need to update rows one by one.
You can fire these events manually, but it's tricky and it's a bad idea.
You could just run the UpdateRateZone job manually for all the Consignments that were updated

Laravel - extending Illuminate\Http\Request and using session

I've extended the Illuminate\Http\Request class and am passing it along to my controller.
use Illuminate\Http\Request;
class MyRequest extends Request
{
...
}
Controller
class MyController
{
// Doesnt work
public function something(MyRequest $request) {
var_dump($request->session())
}
// Does work
public function something(Illuminate\Http\Request $request) {
var_dump($request->session())
}
}
So when I'm trying to get session $request->session() I get RuntimeException - Session store not set on request.
I feel it has something to do with not running middlewares on my custom request but I dont know how to make it work. Helping or pionting to the right direction would be much apreciated.
To give a little bit more info. I'm trying to make a wizard. Several pages where content of one page depends on choices on previous pages. I'm storing the data in session and on the final page I do "stuff" with it and clear the session storage of current user.
Because it a lot of lines of code and since session instace lives on request I though it would be elegant to hide all those line it in custom request and in controler simply call $myRequest->storeInputs()
This is what seemed to me as "most elegant" in this particular case so I would prefer to finish it this way but I'm also open to a different solution if there is a better aproach.
Summary: basically where should I hide all those lines which are storing and retriving data from sesison?
Solution: I actually solved it by extending FormRequest since it was solution which was the best fit for what I was trying to do. However I accepted the one offered answer since I believe it is generally better solution and I would use it if not for this very particullar case.
The classic Laravel request already got a bunch of settings you didn't catch on your custom request. To achieve that, you should setup a middleware (maybe global in your use-case) which replaces old request in Laravel's container by yours.
<?php
namespace App\Http\Middleware;
use App\Http\MyRequest;
use Closure;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Http\Request;
class CustomizeRequest
{
/**
* #var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* #var \App\Http\MyRequest
*/
protected $myRequest;
/**
* #param \Illuminate\Contracts\Foundation\Application $app
* #param \App\Http\MyRequest $myRequest
*/
public function __construct(Application $app, MyRequest $myRequest)
{
$this->app = $app;
$this->myRequest = $myRequest;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$this->app->instance(
'request', Request::createFrom($request, $this->myRequest)
);
return $next($this->myRequest);
}
}

Laravel policy not running on update/delete model

I'm trying to make this policy stuff work, and i have followed the documentation. But it doesn't seem like the policy code is not even run.
I have Role model. And i created RolePolicy. The thing i want to do in the policy is to ensure that the role with the ID of 1 never-ever gets updated or deleted.
My RolePolicy looks like this:
<?php
namespace App\Policies;
use App\Models\Role;
use Illuminate\Support\Facades\Response;
class RolePolicy
{
/**
* Determine whether the user can update the model.
*
* #param \App\User $user
* #param \App\Models\Role $role
* #return mixed
*/
public function update(Role $role)
{
return $role->id === 1
? Response::deny('Cannot change super-admin role')
: Response::allow();
}
/**
* Determine whether the user can delete the model.
*
* #param \App\User $user
* #param \App\Models\Role $role
* #return mixed
*/
public function delete(Role $role)
{
return $role->id === 1
? Response::deny('Cannot delete super-admin role')
: Response::allow();
}
}
I even tried to do a dd() inside both delete and update method in the policy, but when i try to delete/update the model with the ID of 1, nothing happens. The dd wont run, nor will the response in the current code above.
I have registered the policy in the AuthServiceProvider where i also have this gate to give the super-admin all the permissions.
<?php
namespace App\Providers;
use App\Models\Role;
use App\Policies\RolePolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
Role::class => RolePolicy::class
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
// Implicitly grant "Super Admin" role all permissions
// This works in the app by using gate-related functions like auth()->user->can() and #can()
Gate::before(function($user, $ability) {
return $user->hasRole('super-admin') ? true : null;
});
}
}
Here is also my RoleController method for updating the Role model:
/**
* Edit role
*
* #param Edit $request
* #param Role $role
* #return void
*/
public function postEdit(Edit $request, Role $role)
{
# Validation checks happens in the FormRequest
# Session flash also happens in FormRequest
# Update model
$role->update([
'name' => $request->name
]);
# Sync permissions
$permissions = Permission::whereIn('name', $request->input('permissions', []))->get();
$role->syncPermissions($permissions);
return redirect(route('dashboard.roles.edit.get', ['role' => $role->id]))->with('success', 'Changes saved');
}
Does the gate i use to give all permissions have anything to do with the policy not running? Or what am i doing wrong here?
Thanks in advance if anyone can point me in the right direction.
The User model that is included with your Laravel application includes two helpful methods for authorizing actions: can and cant. The can method receives the action you wish to authorize and the relevant model. For example, let's determine if a user is authorized to update a given Role model:
if ($user->can('update', $role)) {
//
}
If a policy is registered for the given model, the can method will automatically call the appropriate policy and return the boolean result. If no policy is registered for the model, the can method will attempt to call the Closure based Gate matching the given action name.
Via Controller Helpers
In addition to helpful methods provided to the User model, Laravel provides a helpful authorize method to any of your controllers which extend the App\Http\Controllers\Controller base class. Like the can method, this method accepts the name of the action you wish to authorize and the relevant model. If the action is not authorized, the authorize method will throw an Illuminate\Auth\Access\AuthorizationException, which the default Laravel exception handler will convert to an HTTP response with a 403 status code:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Role;
use Illuminate\Http\Request;
class RoleController extends Controller
{
/**
* Update the given role.
*
* #param Request $request
* #param role $role
* #return Response
* #throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Role $role)
{
$this->authorize('update', $role);
// The current user can update the role...
}
}
The Gate::before method in the AuthServiceProvider was the problem. Removed this and rewrote the permissions, policies and some gates to get the error messages from the policies.
Decided to give the role super-admin the permission * and check for this with $user->can() and middleware .....->middlware('can:*') and everything is working now.

Laravel - redirect to route with data after register

I want to redirect to 'email/verify' with some data(newly created user) within it after registration using Laravel Auth.
Is there any way to customize the redirection after registration?
If you need to do more than just redirect to a route you can override the registered method on your App\Http\Controllers\Auth\RegisterController (which comes from the Illuminate\Foundation\Auth\RegistersUsers trait):
/**
* The user has been registered.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function registered(Request $request, $user)
{
// do what you would like and return the response you want
}
You have to use like this
protected $redirectTo = '/your_url';
After that you have to use like this
protected function registered(Request $request){
// After successful register you have to use like this
return redirect($this->redirectPath());
}

New registered user to be redirected to the password reset screen

I'm quite new to Laravel and have been stumped on a problem for 2 days - I'd be grateful for some guidance.
I'm using the default out-of-the-box User authentication system with Laravel 5.3. A new user is created automatically behind the scenes by an existing Admin user - I will in time hide the user registration page. I have also successfully set up middleware to check if a user is newly registered (by looking for a null 'last_logged_in_date' that I've added to the migration).
All I want to happen is for a new registered user to be redirected to the password reset screen that ships with Laravel (again, in time I will create a dedicated page). I would like this to happen within the middleware file. So far, my middleware looks like this:
<?php
namespace App\Http\Middleware;
use Closure;
use App\Http\Controllers\Auth;
class CheckIfNewUser
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = $request->user();
if (! is_null($user->last_logged_in_date )) {
return $next($request);
}
// This is where I'm stuck!!!
}
}
I'm not sure what code to enter at the location indicated by the comments above. I've tried sendResetLinkEmail($request); etc and have imported what I though were the correct classes but I always end up with a Call to undefined function App\Http\Middleware\sendResetLinkEmail() message irregardless of what I 'use' at the top of my class.
Where am I going wrong? Thanks!
Well that happens because you have not defined your sendResetLinkEmail($request) function yet. You can do it like this, or you can create a new class with that and then call the class.
Call the trait SendsPasswordResetEmails and then access it with $this since traits are not classes and you cannot access their members directly.
<?php
namespace App\Http\Middleware;
use Closure;
use App\Http\Controllers\Auth;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class CheckIfNewUser
{
use SendsPasswordResetEmails;
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = $request->user();
if (! is_null($user->last_logged_in_date )) {
return $next($request);
}
// This is where I'm stuck!!!
//EDIT
//return $this->SendsPasswordResetEmails->sendResetLinkEmail($request);
return $this->sendResetLinkEmail($request);
}
}

Resources