ryanpitts1
ryanpitts1

Reputation: 894

Laravel 5.5 Unresolvable dependency resolving

I'm having an issue with some dependency injection and could use a hand. I'm new to all this and Laravel so let me know if you need more clarity/context/code examples.

The error is get is thise:

Illuminate\Contracts\Container\BindingResolutionException: Unresolvable dependency resolving [Parameter #0 [ iterable $validators ]] in class App...\JWTAuthenticationService

AuthenticationServiceProvider.php

class AuthenticationServiceProvider extends ServiceProvider
{
    private const TAGGED_VALIDATORS = 'jwt_validators';

    public function register()
    {
        $this->app->bind(JWTValidatorInterface::class, function () {
            return new JWTAuthenticationService(
                $this->app->tagged(self::TAGGED_VALIDATORS)
            );
        });

        $this->app->tag(
            [
                ExternalJWTValidator::class,
                ManualJWTValidator::class,
            ],
            self::TAGGED_VALIDATORS
        );
    }
}

JWTAuthenticationService.php

class JWTAuthenticationService implements JWTValidatorInterface
{
    /** @var iterable|JWTValidatorInterface[] */
    private $validators;

    /**
     * @param iterable|JWTValidatorInterface[] $validators
     */
    public function __construct(iterable $validators)
    {
        $this->validators = $validators;
    }

    /**
     * Validate a JWT token.
     *
     * @param string $token
     *
     * @return bool
     */
    public function validate(string $token): bool
    {
        foreach ($this->validators as $validator) {
            dd('Made it to: JWTAuthenticationService');
        }
    }
}

JWTValidatorInterface.php

interface JWTValidatorInterface
{
    /**
     * Validate a JWT token.
     *
     * @param string $token
     *
     * @return bool
     */
    public function validate(string $token): bool;
}

ManualJWTValidator.php

class ManualJWTValidator implements JWTValidatorInterface
{
    /**
     * Validate a JWT token.
     *
     * @param string $token
     *
     * @return bool
     */
    public function validate(string $token): bool
    {
        foreach ($this->validators as $validator) {
            dd('Made it to: ManualJWTValidator');
        }
    }
}

ExternalJWTValidator.php

class ExternalJWTValidator implements JWTValidatorInterface
{
    /**
     * Validate a JWT token.
     *
     * @param string $token
     *
     * @return bool
     */
    public function validate(string $token): bool
    {
        foreach ($this->validators as $validator) {
            dd('Made it to: ManualJWTValidator');
        }
    }
}

Full error stacktrace: enter image description here

Upvotes: 0

Views: 2788

Answers (2)

ryanpitts1
ryanpitts1

Reputation: 894

I ended up abandoning the iterable type hinting and changed up the service provider to use the splat operator. Worked like i needed.

$this->app->bind(JWTValidatorInterface::class, function () {
    $validators = $this->app->tagged(self::TAGGED_VALIDATORS);

    return new JWTAuthenticationService(...$validators);
});

Upvotes: 0

Felippe Duarte
Felippe Duarte

Reputation: 15131

My guess is that you can't enforce the type in your constructor, because laravel will try to find a class and resolve the dependency.

So, basically, replace:

public function __construct(iterable $validators)

With

public function __construct($validators)

In case you need to be sure, just check inside the constructor:

if(!is_iterable ($validators)) {
    throw new \Exception('Validator should be iterable!');
}

Upvotes: 1

Related Questions