Skip to content

Conversation

@adamwathan
Copy link
Contributor

@adamwathan adamwathan commented Dec 14, 2016

Adds support for manually controlling how a method should be called when invoked with Container::call:

$this->app->bindMethod('App\Jobs\SomeJob@handle', function ($job, $app) {
    return $job->handle('foo', 'bar');
});

Prior to this, it was impossible to have parameters in the handle method of a job that could not be auto-resolved by the container, because there was no way to manually control what the parameters should be.

This means you are forced to use type hints for object parameters and have no ability to use primitives as parameters, or have to use the old undocumented job syntax where dependencies were passed to the constructor instead of to the handle method.

For example, it is currently impossible to write a job class like this, where the handle method has dependencies that can't be autoresolved:

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;

class AddCollaboratorToGitHubRepoJob implements ShouldQueue
{
    use Queueable;

    private $user;

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

    public function handle($githubOwner, $githubRepo, $githubToken)
    {
        (new Client)->put($this->collaboratorUrl($githubOwner, $githubRepo), [
            'headers' => ['Authorization' => "token {$githubToken}"],
            'json' => ['permission' => 'pull']
        ]);
    }

    private function collaboratorUrl($owner, repo)
    {
        return "https://api.github.com/repos/{$owner}/{$repo}/collaborators/{$this->user->github_username}";
    }
}

Using the functionality added in this PR, you could specify how handle should be called:

$this->app->bindMethod('App\Jobs\AddCollaboratorToGitHubRepoJob@handle', function ($job, $app) {
    return $job->handle(
        config('services.github.owner'),
        config('services.github.repo'),
        config('services.github.token')
    );
});

This PR intentionally adds only the minimal functionality needed to subvert this issue, and doesn't make any effort to support the when->needs->give syntax, or passing key => value parameters to optionally override things or any of those fancy more complex features.

Instead, it simply adds support for defining what should happen as a whole, much like you would with a standard container binding:

$this->app->singleton(PaymentGateway::class, function () {
    return new PaymentGateway(config('services.stripe.secret'));
});

Additional functionality like that could be added down the road, or we could simply roll with this forever, because it at least does what's needed to fix what's currently impossible.

@taylorotwell taylorotwell merged commit a153c59 into laravel:master Dec 14, 2016
@GrahamCampbell GrahamCampbell changed the title Add support for binding methods to the container [5.4] Add support for binding methods to the container Dec 15, 2016
@tillkruss
Copy link
Contributor

Neat!

@vnaki
Copy link

vnaki commented May 3, 2018

Greate!

@michael-rubel
Copy link
Contributor

If someone's interested in the feature, I've created a package that let us use method bindings with ease:
https://github.com/michael-rubel/laravel-enhanced-container

I also plan to extend the package functionality in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants