7

This is related to this question How to register a namespace in laravel 4 but I believe I got that worked out and namespaces are working now.

There is a new problem I've run into. I believe the error is coming from trying to type hint in the controller constructor and has to do with using namespaces and using ioc.

BindingResolutionException: Target [App\Models\Interfaces\PostRepositoryInterface] is not instantiable.

The method below worked perfectly until I tried to introduce namespaces. I can remove all the namespaces and put the interface and repositories in the same directory but would like to know how to make namespaces work with this method of using the ioc.

Here are the relevant files.

routes.php

Route::resource('posts', 'PostsController');

PostController.php

<?php
use App\Models\Interfaces\PostRepositoryInterface;
class PostsController extends BaseController {

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

}

PostRepositoryInterface.php

<?php namespace App\Models\Interfaces;
interface PostRepositoryInterface {
    public function all();
    public function find($id);
    public function store($data);
}

EloquentPostRepository.php

<?php namespace App\Models\Repositories;
use App\Models\Interfaces\PostRepositoryInterface;
class EloquentPostRepository implements PostRepositoryInterface {

    public function all()
    {
        return Post::all();
            //after above edit it works to this point
            //error: App\Models\Repositories\Post not found
            //because Post is not in this namespace
    }

    public function find($id)
    {
        return Post::find($id);
    }

    public function store($data)
    {
        return Post::save($data);
    }
}

And you can see composer dump-autoload did it's job.

composer/autoload_classmap.php

return array(
    'App\\Models\\Interfaces\\PostRepositoryInterface' => $baseDir . '/app/models/interfaces/PostRepositoryInterface.php',
    'App\\Models\\Repositories\\EloquentPostRepository' => $baseDir . '/app/models/repositories/EloquentPostRepository.php',

    ....
    )

Any ideas where or what I need to change to make this work with namepaces like it does without them?

Thanks

Community
  • 1
  • 1
isimmons
  • 2,016
  • 2
  • 20
  • 32
  • I've gotten past that first error. I didn't know how App::bind() works but passing in the entire namepace as a string works. I'll update that part of the code. Now the problem is in EloquentPostRepository since it is namespaced, when I try to call Post::all() it puts 'Post' in the 'Repositories' namespace. Need to figure out how to call a class outside of the namespace. – isimmons Mar 06 '13 at 03:55

2 Answers2

37

I know this question has already been answered but I'd like to remind future readers that another common cause of this "target interface is not instantiable" error is to have forgotten to register a service provider in app/config/app.php.

This only applies if you're extending the ServiceProvider class, not if you're using App::bind().

I've made that mistake one too many times not to post something about it. So before you go down the lengthy path outlined above, make sure to register those providers!

patricksayshi
  • 1,395
  • 3
  • 13
  • 18
  • Good point. At the time of this question I didn't know about service providers. So good to let people know it's another case for this error. – isimmons Sep 27 '13 at 01:59
  • I was getting this error when for the class I made constructor private. Changing to public solved the problem – Dariux Nov 14 '14 at 07:26
  • 1
    another problem (the one I ran into) was using `/` instead of `\` in my namespaces. while a very simple mistake, it was a PITA to debug – Andrew Brown Jan 19 '15 at 21:10
  • I think it's worth saying that this error can happen if you do a typo in the class name. This happened to me using App::bind(). So, instead of a `Class 'Classname' not found`, it will also give you a `Target [interfacename] is not instantiable.` – Tiago Nov 11 '15 at 12:58
  • Another note: If you *do* already have a service provider registered and you're *still* getting this error, remember to `php artisan config:clear` to clear your cache. (facepalm) – Drake Parker Dec 10 '15 at 20:47
13

Ok, the short answer: Use the complete namespace in App::bind() to fix the first error. Then in EloquentPostRepository.php because it has a declared namespace it tries to treat any other external class calls as if they are in the same namespace. Adding a simple 'use Post;' lets PHP know that 'Post' is not in the same namespace (App\Models\Repositories). I assume this is because once a namespace is used, other classes by default have a namespace of whatever the class name is. I thought it would be easiest to just re-post all of the code corrected and working.

routes.php

<?php

App::bind('App\Models\Interfaces\PostRepositoryInterface',  'App\Models\Repositories\EloquentPostRepository');

Route::resource('posts', 'PostsController');

PostController.php

<?php
use App\Models\Interfaces\PostRepositoryInterface;

class PostsController extends BaseController {

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

EloquentPostRepository.php

<?php namespace App\Models\Repositories;
use App\Models\Interfaces\PostRepositoryInterface;
use Post;
class EloquentPostRepository implements PostRepositoryInterface {

    public function all()
    {
        return Post::all();
    }

    public function find($id)
    {
        return Post::find($id);
    }

    public function store($data)
    {
        return Post::save($data);
    }
}

PostRepositoryInterface.php

<?php namespace App\Models\Interfaces;
interface PostRepositoryInterface {
    public function all();
    public function find($id);
    public function store($data);
}

Post.php Nothing relevant here other than showing it has no declared namespace

<?php
class Post extends BaseModel {

    public static $rules = [
        'title' => 'required',
        'body' => 'required',
        'author_id' => 'required|numeric'
    ];

    public static $factory = [
        'title' => 'string',
        'body' => 'text'
    ];

    public function user()
    {
        return $this->belongsTo('User', 'author_id');
    }

}
isimmons
  • 2,016
  • 2
  • 20
  • 32
  • 2
    you don't need to add the implementation (`EloquentPostRepository`) in **PostController.php**. this way you keep the advantage of only having to change the implementation in one place, in the bindings of **routes.php**. – Simon Wicki Oct 10 '13 at 12:19
  • Good catch. Not sure why I had that there. I removed it. – isimmons Oct 10 '13 at 14:59