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);
}
}
Related
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
I am trying to implement a very simple authentication mechanism with Laravel 5.7, and am not sure of the best approach to take.
For the sake of reducing my issue to the most simple terms possible, let's say that I want to protect certain routes so they are viewable only by users from a specific IP address. If a user from a different IP address attempts to access a protected route, they will be redirected to an external URL.
Basically, I want to do this:
if ($_SERVER['REMOTE_ADDR'] != '123.45.67.89') {
return Redirect::away('https://external-url.example.com/login');
}
What is the cleanest way to implement this in Laravel? I've read a lot of tutorials that explain how to create custom Auth providers, but they seem overly complicated for what I'm doing.
Can I simply create a single middleware class that implements the code above? What are some terms that I can search for via Google, to find tutorials that will help me through implementing this?
Middleware
<?php
namespace App\Http\Middleware;
use Closure;
class VerifyIpAddress
{
/**
* Check request ip address and ..
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($request->ip() !== 123.123.123.123) {
// forbidden page or smth!
}
return $next($request);
}
}
I have a design doubt I would like to share.
I have a model in Laravel with an Observer at retrieved:
class MailingObserver
{
public function retrieved($mailing)
{
// we retrieve HTML content from disk file
$mailing->setAttribute('content', \Illuminate\Support\Facades\Storage::disk('mailings')->get("{$mailing->id}-{$mailing->slug}.html"));
$mailing->syncOriginal();
}
}
which retrieve an attribute stored in a plain text instead of database.
The site is a multibrand platform so disk('mailings') is different per each logged user. This configuration is loaded in a middleware according to the the current logged user.
Up to here all is fine.
Now the "problem". I have a Controller which injects the entity Mailing:
class MailingCrudController extends CrudController
{
/**
* Sends the mailing
* #param Request $request
* #param \App\Mailing $mailing
*/
public function send(Request $request, \App\Mailing $mailing)
{
// WHATEVER
}
}
When the model is injected the retrieved Observer method is fired but the Middleware wasn't still executed so mailings disk is still not set up.
I don't know how to change this order: first execute middleare, then the model injection.
One approach
I tried in AppServiceProvider to add:
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$middleware = new \App\Http\Middleware\CheckBrandHost();
$middleware->setBrandInformation(request());
$middleware->loadBrandConfig(request()->get('brand.code_name'));
}
Would you approve this solution? What problems can cause it to me? Is it the proper way to do it?
Thanks all!
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);
}
}
i wrote my own User-Role System, but i dont know how to implement the verification in my middleware routes.
The middleware class is calling on every request.
I recive the $request->user() but i can not access the attributes to verify if the user has the correct permissions.
My middleware controller looks like this:
namespace App\Http\Middleware;
use Closure;
use Activation;
use Cartalyst\Sentinel\Laravel\Facades\Sentinel;
class AccountMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Sentinel::findByCredentials([
'login' => $request->user()->attributes['email']
);
...
return $next($request);
}
}
It doesnt work.
If I trie to dump the $request->user() i can see all properties but there are protected.
What do i need to change, to make it work?
Accessing Eloquent model properties is done via accessors, in this case via the __get magic method. So you don't need to access them through the $attributes property array, all you need is this:
$request->user()->email;
The above will return the user email because the Illuminate\Database\Eloquent\Model::__get method already fetches the specified attribute automatically.
If you like, you can even define your own Accessors or Mutators to modify attribute values when reading or writing them to the database.