31

I'm building a Laravel project and in one of the controllers I'm injecting two dependencies in a method:

public function pusherAuth(Request $request, ChannelAuth $channelAuth) { ... }

My question is really simple: How do I pass parameters to the $channelAuth dependency?

At the moment I'm using some setters to pass the needed dependencies:

public function pusherAuth(Request $request, ChannelAuth $channelAuth)
{
    $channelAuth
        ->setChannel($request->input('channel'))
        ->setUser(Auth::user());

What are the alternatives to this approach?

P.S. The code needs to be testable.

3 Answers 3

32

Thanks to the help I received on this Laracast discussion I was able to answer this question. Using a service provider it's possible to initialize the dependency by passing the right parameters to the constructor. This is the service provider I created:

<?php namespace App\Providers;

use Security\ChannelAuth;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;

class ChannelAuthServiceProvider extends ServiceProvider {

    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('Bloom\Security\ChannelAuthInterface', function()
        {
            $request = $this->app->make(Request::class);
            $guard   = $this->app->make(Guard::class);

            return new ChannelAuth($request->input('channel_name'), $guard->user());
        });
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

But what if your input doesn't have 'channel_name' set? This code may get called before you've had a chance to validate your input.
@omarjebari I guess that depends on where you're injecting Bloom\Security\ChannelAuthInterface which, in my case, is after the inputs have been validated.
I am looking for something similar. Is there a way to do this but for console/artisan input instead of HTTP request?
@MathewParet I guess the principle is the same. You just need to find out which interface you want to bind and return an instance of a class that implements that interface with your changes.
3

You can pass parameters (as a string indexed array) when resolving a dependence like this:

<?php namespace App\Providers;

use Security\ChannelAuth;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Support\ServiceProvider;

class ChannelAuthServiceProvider extends ServiceProvider {

    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('Bloom\Security\ChannelAuthInterface', function($params)
        {
            $channelName = $params['channelName'];
            $guard   = $this->app->make(Guard::class);

            return new ChannelAuth($channelName, $guard->user());
        });
    }
}

Then when resolving eg in a controller:

public function pusherAuth()
{
    $channelAuth = app()->makeWith('Bloom\Security\ChannelAuthInterface', [
        'channelName' => $request->input('channel_name')
    ]);
    // ... use $channelAuth ...
}

Comments

0

You can create and register your own service provider and create object with constructor's requests parameters.

I don't know how to do this in Laravel, but in Symfony2 you can inject in your own service something like RequestStack. It's the best way, because you have small service providers that are fully testable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.