Laravel service provider gives "Target [Interface] is not instantiable" error
Asked Answered
S

2

5

My error message:

Illuminate \ Container \ BindingResolutionException 
Target [Project\Backend\Service\Validation\ValidableInterface] is not instantiable.

I understand that interfaces and abstract classes are not instantiable so I know that Laravel should not be trying to instantiate my interface. Yet somehow it's trying to and I suspect this may be a binding issue...even though I believe I have bound it correctly and have registered it as a service provider.

I should mention that I have taken this example out of Chris Fidao's "Implementing Laravel" and it's almost identical!

This is the first couple of lines of my form class:

namespace Project\Backend\Service\Form\Job;

use Project\Backend\Service\Validation\ValidableInterface;
use Project\Backend\Repo\Job\JobInterface;

class JobForm {

    /**
     * Form Data
     *
     * @var array
     */
    protected $data;

    /**
     * Validator
     *
     * @var \Project\Backend\Form\Service\ValidableInterface
     */
    protected $validator;

    /**
     * Job repository
     *
     * @var \Project\Backend\Repo\Job\JobInterface
     */
    protected $job;

    public function __construct(ValidableInterface $validator, JobInterface $job)
    {
        $this->validator = $validator;
        $this->job = $job;
    }

This is the first few lines of my validator class:

namespace Project\Backend\Service\Form\Job;

use Project\Backend\Service\Validation\AbstractLaravelValidator;

class JobFormValidator extends AbstractLaravelValidator {

    // Includes some validation rules

This is the abstract validator:

namespace Project\Backend\Service\Validation;

use Illuminate\Validation\Factory;

abstract class AbstractLaravelValidator implements ValidableInterface {

    /**
     * Validator
     *
     * @var \Illuminate\Validation\Factory
     */
    protected $validator;

    /**
     * Validation data key => value array
     *
     * @var Array
     */
    protected $data = array();

    /**
     * Validation errors
     *
     * @var Array
     */
    protected $errors = array();

    /**
     * Validation rules
     *
     * @var Array
     */
    protected $rules = array();

    /**
     * Custom validation messages
     *
     * @var Array
     */
    protected $messages = array();

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

This is the code where I bind it all to the app:

namespace Project\Backend\Service\Validation;

use Illuminate\Support\ServiceProvider;
use Project\Backend\Service\Form\Job\JobFormValidator;

class ValidationServiceProvider extends ServiceProvider {

    public function register()
    {
        $app = $this->app;

        $app->bind('Project\Backend\Service\Form\Job\JobFormValidator', function($app)
        {
            return new JobFormValidator($app['validator']);
        });
    }
}

This is then registered in app/config/app.php:

.....
'Project\Backend\Service\Validation\ValidationServiceProvider',
....

Finally these are the first few lines of my controller:

use Project\Backend\Repo\Job\JobInterface;
use Project\Backend\Service\Form\Job\JobForm;

class JobController extends \BaseController {

    protected $jobform;

    function __construct(JobInterface $job, JobForm $jobform)
    {
        $this->job = $job;
        $this->jobform = $jobform;
    }
Stuckup answered 3/1, 2015 at 22:51 Comment(0)
G
8

You need to tell Laravel which instance it should use for a certain interface when injecting it into the constructor via type hinting.

You do this using the bind() method (in your service provider for example)

$app->bind('JobInterface', 'Job'); // Job being the class you want to be used

I highly recommend you watch the video here where Taylor Otwell, the creator of Laravel, explains this and some other things.

Galarza answered 3/1, 2015 at 23:2 Comment(3)
Useful video and explains key concepts. However it's still unclear to me as the ValidableInterface is only implemented by an abstract classStuckup
Then you specify the class that extends the abstract class (and therefore implements the interface)Galarza
After adding this into bindings.php then you need to run composer update commandLatinalatinate
J
1

First you need to bind using

/app/Providers/AppServiceProvider.php

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider {

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

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
        $this->app->bind('JobInterface', 'Job');

    }

}

Once you complete this change

Run composer update

Jolt answered 30/6, 2015 at 9:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.