Reputation: 163
Let's say I have two repositories (UserRepository, RoleRepository) that implements a contract (UserRepositoryInterface, RoleRepositoryInterface).
What I wanted to do is to inject RoleRepository into UserRepository's constructor method and I've been trying to make this work but I'm getting this error:
Target [App\Contracts\UserRepositoryInterface] is not instantiable while building [App\Http\Controllers\UserController].
Here's what I got so far,
composer.json
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.2.*",
"tymon/jwt-auth": "^0.5.9",
"zizaco/entrust": "dev-laravel-5"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "~4.0",
"symfony/css-selector": "2.8.*|3.0.*",
"symfony/dom-crawler": "2.8.*|3.0.*"
},
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/",
"App\\Models\\": "app/Models/",
"App\\Contracts\\": "app/Contracts/",
"App\\Repositories\\": "app/Repositories/"
}
},
"autoload-dev": {
"classmap": [
"tests/TestCase.php",
"tests/MockData.php"
]
}
config/app.php
'providers' => [
/*
* Laravel Framework Service Providers...
*/
...
/**
* Third-party Service Providers
*/
...
/*
* Application Service Providers...
*/
...
/**
* Custom Service Providers...
*/
App\Providers\RepositoryServiceProvider::class,
app/Providers/RepositoryServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$models = [
'Role',
'User',
];
foreach ($models as $model) {
$this->app->bind(
"App\Contracts\\{$model}Interface",
"App\Repositories\\{$model}Repository"
);
}
}
}
app/Controllers/UserController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Contracts\UserRepositoryInterface as UserRepository;
class UserController extends Controller
{
/**
* @var UserRepository
*/
private $repo;
/**
* Class constructor
*
* @param UserRepository $repo
*/
public function __construct(
UserRepository $repo
) {
$this->repo = $repo;
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function store(Request $request)
{
$data = $request->all();
$user = $this->repo->store($data);
return response()->json($user, 201);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
*
* @return \Illuminate\Http\JsonResponse
*/
public function update(Request $request, $id)
{
$data = $request->all();
$user = $this->repo->store($data, $id);
return response()->json($data, 200);
}
app/Contracts/RoleRepositoryInterface.php
<?php
namespace App\Contracts;
interface RoleRepositoryInterface
{
/**
* Attach role to user
*
* @param static $user
* @param string $roleName
*
* @return static
*/
public function role($user, $roleName);
}
app/Contracts/UserRepositoryInterface.php
<?php
namespace App\Contracts;
interface UserRepositoryInterface
{
/**
* Create new or update an existing user
*
* @param array $data
* @param int $id
*
* @return bool|int|array
*/
public function store(array $data, $id = null);
}
app/Repositories/RoleRepository.php
<?php
namespace App\Repositories;
use InvalidArgumentException;
use App\Contracts\RoleRepositoryInterface;
use App\Models\Role;
class RoleRepository extends Role implements RoleRepositoryInterface
{
/**
* Attach a role to user
*
* @param static $user
* @param string $roleName
*
* @return static
*
* @throws \InvalidArgumentException
*/
public function attachRole($user, $roleName)
{
if (!$user instanceof App\Models\User::class) {
throw new InvalidArgumentException("{$user} must be an instance of App\Models\User");
}
// find role
$role = $this->where('name', $roleName)->first();
// attach role to user
$user->attachRole($role);
return $user;
}
}
app/Repositories/UserRepository.php
<?php
namespace App\Repositories;
use App\Contracts\RoleRepositoryInterface as RoleRepository;
use App\Contracts\UserRepositoryInterface;
use App\Models\User;
class UserRepository extends User implements UserRepositoryInterface
{
/**
* @var RoleRepository
*/
private $roleRepo;
/**
* Class constructor
*
* @param RoleRepository $roleRepo
*/
public function __construct(RoleRepository $roleRepo)
{
$this->roleRepo = $roleRepo;
}
/**
* Create new or update an existing user
*
* @param array $data
* @param int $id
*
* @return bool|int|static
*/
public function store(array $data, $id = null)
{
if (is_null($id)) {
$user = $this->create($data);
$userWithRole = $this->roleRepo->attachRole($user, $data['role']);
return $user;
} else {
return $this->where('id', $id)
->update($data);
}
}
}
Any answers is greatly appreciated...
Upvotes: 4
Views: 4869
Reputation: 1229
I think you have an error in your code, specifically in the RepositoryServiceProvider
. It should be:
foreach ($models as $model) {
$this->app->bind(
"App\Contracts\\{$model}RepositoryInterface",
"App\Repositories\\{$model}Repository"
);
}
Note: the error is in the concatenation, you got "App\Contracts\\{$model}Interface"
, but it should be "App\Contracts\\{$model}RepositoryInterface"
Upvotes: 1