79

I know that this question was asked so many times, but none of answers helped me.

I'm getting exception in Laravel 5

BindingResolutionException in Container.php line 785:
Target [App\Contracts\CustomModelInterface] is not instantiable.

What I've done without success:

  • Register App\Providers\AppRepositoryProvider in app.php providers
  • php artisan clear-compiled
  • Everything works if I replace interfaces on repositories in MyService, but I feel that it's wrong (should it be handled by IoC container?).

Structure:

app
  - Contracts
    - CustomModelInterface.php
  - Models
    - CustomModel.php
  - Repositories
    - CustomModelRepository.php
  - Providers
    - AppRepositoryProvider.php
  - Services
    - MyService.php

App\Contracts\CustomModelInterface.php

<?php namespace App\Contracts;

interface CustomModelInterface {
    public function get();
}

App\Repositories\CustomModelRepository.php

<?php namespace App\Repositories;

use App\Contracts\CustomModelInterface;
use App\Models\CustomModel;

class CustomModelRepository implements CustomModelInterface {

    private $Model;

    public function __construct(CustomModel $model) {
        $this->Model = $model;
    }

    public function get() {
        return 'result';
    }
}

App\Services\MyService.php (Keep business logic / layer between controller and repositories)

<?php namespace App\Services;

use App\Contracts\CustomModelInterface;

class MyService {

    private $Model;

    public function __construct(CustomModelInterface $customModel) {
        $this->Model= $customModel;
    }

    public function getAll() {
        return $this->Model->get();
    }
}

App\Providers\AppRepositoryProvider.php

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppRepositoryProvider extends ServiceProvider {

    public function boot() {}

    public function register() {
        $models = array(
            'CustomModel'
        );

        foreach ($models as $idx => $model) {
            $this->app->bind("App\Contracts\{$model}Interface", "App\Repositories\{$model}Repository");
        }
    }
}

My controller looks like:

<?php namespace App\Http\Controllers;

use App\Services\MyService;

class SuperController extends Controller {

    private $My;

    public function __construct(MyService $myService) {
        $this->My = $myService;
    }

    public function getDetails() {
        return $this->My->getAll();
    }
}

composer.json

"autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/",
            "App\\Models\\": "app/Models/",
            "App\\Contracts\\": "app/Contracts/",
            "App\\Repositories\\": "app/Repositories/"
        }
    },
halfer
  • 19,824
  • 17
  • 99
  • 186
Andrew Kulakov
  • 2,064
  • 1
  • 16
  • 18
  • 1
    Today I found this queston because I got the same error message. In my case, in my ServiceProvider, I had the property `$defer = true;` This leads to the same error. If you encounter the same issue, just remove the property. – Bart McLeod Apr 12 '16 at 07:18

15 Answers15

58

Thank you everyone, but problem was in my AppRepositoryProvider. As it's binding exception, then obviously the problem was with binding :)

Correct file is:

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppRepositoryProvider extends ServiceProvider {

    public function boot() {}

    public function register() {
        $models = array(
            'CustomModel',
            'CustomModel2',
            'CustomModel3'
        );

        foreach ($models as $model) {
            $this->app->bind("App\Contracts\\{$model}Interface", "App\Repositories\\{$model}Repository");
        }
    }
}

Note, that I'm using "App\Contracts\\{$model}Interface" (not escaping "{" symbol) and it generate correct string App\Contracts\CustomModelInterface instead of App\Contracts\{$model}Interface (with unexpected escaping).

Andrew Kulakov
  • 2,064
  • 1
  • 16
  • 18
  • 1
    If I am not mistaken, you have just jumped over `interface` now, because now after the binding you have used, each time you call `interface` an object of `repository` will be resolved... and not the interface, you haven't used the `SoC` design pattern the way it should be... Your `interface` files are now useless. Correct me if I am wrong. – Hamza Ouaghad Jul 15 '15 at 17:15
  • Can you explain why you use `App\Contracts\\{$model}Interface` and not use `App\Contracts\{$model}Interface `, what does the double backslash mean? – tdycss Feb 07 '20 at 17:13
  • @tdycss the first backslash is part of the namespace, the second for escaping the `{` - without the escape, you end up with the {} in the resulting namespace, which doesn't exist in this case. see also the note under the code sample in the answer. hope that helps (: – Sandra Jun 09 '21 at 11:29
58

Every time I create a new repository/contract pair I make sure I do the following:

  1. check the classes used in the service provider (copy/paste the namespaces)
  2. register a new binding in config/app.php
  3. php artisan optimize

Many hours of useless debugging led me to this short checklist.

halfer
  • 19,824
  • 17
  • 99
  • 186
Vlad Visinescu
  • 737
  • 5
  • 9
17

For me, I forgot to bind in app->providers->RepositoryServiceProvider the repository like this in the register method

public function register()
{
    $this->app->bind(
        \App\Play\Contracts\PatientRepository::class,
        \App\Play\Modules\PatientModule::class
    );
}

Make sure your RepositoryServiceProvider is registered in AppServiceProvider.

public function register()
{   
    $this->app->register(RepositoryServiceProvider::class);
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Beulah Ana
  • 360
  • 2
  • 14
13

I got past this error running:

php artisan config:clear
php artisan clear-compiled
php artisan optimize
php artisan config:cache

Related to:

Target is not instantiable. Laravel 5 - App binding service provider

Connor Leech
  • 18,052
  • 30
  • 105
  • 150
6

The problem is solved by adding your repository in app/providers/AppServiceProvider like the example below.

public function register()
{
    $this->app->singleton(UserRepository::class, EloquentUser::class);
 }

Dont forget the name space

use Test\Repositories\EloquentUser;
use Test\Repositories\UserRepository;

It worked for me

jibril90
  • 95
  • 1
  • 1
3

On App\Services\MyService.php you are passing that interface with dependency injection which tries to instantiate that -

public function __construct(CustomModelInterface $customModel) {
    $this->Model= $customModel;
}

which is wrong.

Try implement that in that class - class MyService implements CustomModelInterface { and use the function of that interface like -

$this->get();

Or you are using it - class CustomModelRepository implements CustomModelInterface {

So if you do -

public function __construct(CustomModelRepository $customModel) {
    $this->Model= $customModel;
}

then also you can access the interface methods.

Sougata Bose
  • 31,517
  • 8
  • 49
  • 87
  • thank you for quick response. I can't use class MyService implements CustomModelInterface as MyService is just a service that works with multiple repositories. Regards public function __construct(CustomModelRepository $customModel) { $this->Model= $customModel; } - it's what I was trying to do at first, but I feel like it's wrong... – Andrew Kulakov Apr 17 '15 at 04:13
  • Because you do not take the benefit of the interface. If he has to pass the real implementation of the class, you will have to change the class parameter in case you want to supply another kind of `CustomModel` – Kaymaz May 29 '17 at 12:57
  • @Sougata Bose, Seems you can help me. Look at this : https://stackoverflow.com/questions/45956810/how-can-i-solve-target-app-repositories-newsrepository-is-not-instantiable-whi – moses toh Aug 30 '17 at 10:00
2

I've just experienced an issue similar to this and the cause of my error was that I had set $defer to true in the service provider class but I had not implemented the required provides() method.

If you have deferred the creation of your class until it is need rather than it being loaded eagerly, then you need to also implement the provides method which should simply return an array of the classes that the provider provides. In the case of an interface, I believe it should be the name of the interface rather than the concrete class.

E.g.

public method provides(): array
{
    return [
        MyInterface::class,
    ];
}

Current documentation: https://laravel.com/docs/5.5/providers#deferred-providers

I hope this helps somebody else.

Kenny Body
  • 1,059
  • 8
  • 5
2

Don't worry guys. I have a solution to your problem.

I have an example for you.

Step1: php artisan make:repository Repository/Post //By adding this command you can create a repository and eloquent files

Step2: After adding that file you have to add/use this repository in the controller in which you want to use.

for eg: use App\Repositories\Contracts\PostRepository;

Step3: After adding that repo in your controller if you will run the app you will get an error like " Interface is not instantiable". It comes because you have created a repo and used in a controller, but laravel don't know where this repository is register and bind with which eloquent. So that it throws an error.

Step4: To solve this error you have to bind your repo with your eloquent in AppServiceProvider. E.g:

AppServiceProvider.php file

<?php
namespace App\Providers;

// **Make sure that your repo file path and eloquent path must be correct.**

use App\Repositories\Contracts\PostRepository;         // **Use your repository here**

use App\Repositories\Eloquent\EloquentPostRepository;  **// Use your eloquent here**

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider {
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register() {

**// And bind your repository and eloquent here. **

        $this->app->bind(PostRepository::class, EloquentPostRepository::class);
    }
}

Step5: After binding repo and eloquent you can use all method of repo in your controller. Enjoy.....

Please let me know if you have any query.

JackPoint
  • 4,031
  • 1
  • 30
  • 42
Umang Soni
  • 521
  • 5
  • 9
2

execute this command :

composer dump-autoload

this command will remap your laravel autoload classes together with all other vendor's i had same issue before and this did the trick you can use it together with "-o" param for optimization .

Softmixt
  • 1,658
  • 20
  • 20
1

Note that this can also be caused by the _constructor on the class being declared private, or otherwise being blocked... If it cant call the constructor, the binding will fail

Lea de Groot
  • 309
  • 4
  • 12
  • This solved my problem using Laravel 7 ! I accidentally declared `protected function _constructor()` – windsor May 12 '21 at 12:26
0

I think the problem here is that you don't bind App\Contracts\CustomModelInterface to anything so Laravel tries to create instance of interface.

In App\Providers\AppRepositoryProvider.php you have only:

$models = array(
            'Model'
        );

but you should have in this array CustomModel also, so it should look like this:

$models = array(
            'Model',
            'CustomModel',
        );
Marcin Nabiałek
  • 109,655
  • 42
  • 258
  • 291
  • Sorry, it was my typo in a question. You're right that instead of Model there should be CustomModel. I've updated my question to eliminate confusion. – Andrew Kulakov Apr 17 '15 at 07:24
  • @Marcin Nabiałek, Seems you can help me. Look at this : https://stackoverflow.com/questions/45956810/how-can-i-solve-target-app-repositories-newsrepository-is-not-instantiable-whi – moses toh Aug 30 '17 at 09:59
0

The last thing you do is to use the interface you bound to the repository.

Set it up and try running your laravel app to make sure you get no errors.

In my case I had a mismatch between my repository and interface.

interface UserRepositoryInterface{
  public function get($userId); 
}

class UserRepository implements UserRepositoryInterface{
  public function get(int $userId);
}

As you can see the interface get method does not include a type hint but the UserRepository class' get method has a type hint.

You won't get this error if you immediately start to use your Interface Binding.

halfer
  • 19,824
  • 17
  • 99
  • 186
Winnipass
  • 904
  • 11
  • 22
0

register a new binding in config/app.php

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 30 '22 at 09:36
0

In my case I forgot use App\Repositories\UserRepository in App\Providers\AppRepositoryProvider.php

intelephense wasn't complaining and the error-message did not give me any clue, but somehow I found out that it's missing and adding this line did the trick

Witold
  • 875
  • 5
  • 5
0

I had this error, and found out that I should restart the queue because it runs in the job:

php artisan queue:restart
parastoo
  • 2,211
  • 2
  • 21
  • 38