ficus
ficus

Reputation: 194

Laravel - Initialize class only for specific routes

In my app I've got a group of routes which need some bootstraping before dispatching.

To illustrate the situation:

There is a special routes group with prefix 'app'. All of this routes have also some params:

site.dev/app/index?age=11&else=af3fs4ta21

Without these params user shouldn't be allowed to access route. I've got it done by creating a simple route middleware.

if (!$request->exists('age') || !$request->exists('else')) {
        return redirect('/');
}

Next step is to initialize a class which takes route parameters as a construct arguments. Then param "else" is being used as a argument to db calls. I need to access this class in every route from /app route group.

In order to achive that I tried setting up a serviceprovider:

public function register()
{
    $this->app->singleton(Dual::class, function ($app) {
        return new Dual($this->app->request->all());
    });
}

Then I created a special controller extending BaseController and passing Dual class to its constructor.

class DualController extends Controller
{
    public function __construct(Request $request, Dual $dual)
    {
        $this->middleware(\App\Http\Middleware\DualMiddleware::class);

        $this->dual = $dual;
    }
}

And then every single controller is extending DualController and accessing Dual class by $this->dual->method().

It is working if route params are in their place and there is already a row in a database.

The problem

This middleware is executed AFTER ServiceProvider & DualController are initializing class Dual. So, middleware is not really working. If route params are not present it is going to fail.

Moreover, in case that there is no required row in database for some reason, Dual class will not be initialized (as it depends on calls to db) and whole app will crash saying that I am trying to perform operations on null.

Desired behaviour

First check route for params presence.

Second, check if there is row in db with key from route.

Third - try to initialize Dual class and pass it to all controllers used by route group /app.

If any of the steps fail -> display proper message.

Part of dual class:

class Dual
{
    protected $client = null;
    public $config = [];

    public function __construct($config)
    {
        $this->config = $config;
        $this->bootstrap();
    }

    public function getEli()
    {
        $eli = Eli::where(['else' => $this->config['else']])->first();
        return $eli;
    }

    public function instantiateClient()
    {
        $client = Client::factory(Client::ADAPTER_OAUTH, [
            'entrypoint' => $this->getEli()->eli_url,
            'client_id' => '111',
            'client_secret' => '111',
        ]);

        $client->setAccessToken($this->getEli()->accessToken()->first()->access_token);

        return $client;
    }

    public function getClient()
    {
        if ($this->client === null)
        {
            throw new \Exception('Client is NOT instantiated');
        }

        return $this->client;
    }

    public function bootstrap()
    {
        $this->client = $this->instantiateClient();
    }

Upvotes: 2

Views: 1579

Answers (1)

Alexey Mezenin
Alexey Mezenin

Reputation: 163768

You can do this in middleware:

$isElseExists = Model::where('else', request('else'))->first();
if (request('age') && request('else') && $isElseExists) {
    return $next($request);
} else {
    return back()->with('error', 'You are not allowed');
}

If everything is fine, controller method will be executed. Then you'll be able to inject Dual class without any additional logic.

If something is wrong, a user will be redirected to previous URI with error message flashed into session.

Upvotes: 1

Related Questions