Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I solve "Target [Interface] is not instantiable" in Laravel 4?

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;
    }
like image 680
noobmaster69 Avatar asked Jan 03 '15 22:01

noobmaster69


1 Answers

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.

like image 116
lukasgeiter Avatar answered Nov 15 '22 09:11

lukasgeiter