Laravel 5 - Интерфейс не работает
Я знаю, что этот вопрос задавали так много раз, но ни один из ответов не помог мне.
Я получаю исключение в Laravel 5
BindingResolutionException in Container.php line 785:
Target [App\Contracts\CustomModelInterface] is not instantiable.
Что я сделал без успеха:
- Зарегистрировать
App\Providers\AppRepositoryProvider
в app.php
поставщиках
-
php artisan clear-compiled
- Все работает, если я заменяю интерфейсы на репозитории в MyService, но я чувствую, что это неправильно (должен ли он обрабатываться контейнером IoC?).
Буду признателен за любую помощь.
ОБНОВЛЕНИЕ: я решил проблему (см. мой ответ ниже)
Спасибо всем.
Состав:
app
- Contracts
- CustomModelInterface.php
- Models
- CustomModel.php
- Repositories
- CustomModelRepository.php
- Providers
- AppRepositoryProvider.php
- Services
- MyService.php
App\Контракты\CustomModelInterface.php
<?php namespace App\Contracts;
interface CustomModelInterface {
public function get();
}
App\Хранилища\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(Держите бизнес-логику/уровень между контроллером и репозиториями)
<?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");
}
}
}
Мой контроллер выглядит так:
<?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/"
}
},
Ответы
Ответ 1
Спасибо всем, но проблема была в моем AppRepositoryProvider. Поскольку это обязательное исключение, то, очевидно, проблема заключалась в привязке:)
Правильный файл:
<?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");
}
}
}
Обратите внимание, что я использую "App\Contracts\\{$model}Interface"
(не экранируя символ "{" ), и он генерирует правильную строку App\Contracts\CustomModelInterface
вместо App\Contracts\{$model}Interface
(с неожиданным экранированием).
Ответ 2
каждый раз, когда я создаю новую пару репозитория/контракта, я делаю следующее:
- проверить классы, используемые поставщиком услуг (скопировать/вставить пространства имен)
- зарегистрировать новое связывание в config/app.php
- php artisan optimize
Много часов бесполезной отладки привели меня к этому короткому контрольному списку.
Надеюсь, это поможет кому-то. Ура!
Ответ 3
В App\Services\MyService.php
вы передаете этот интерфейс с инъекцией зависимостей, которая пытается создать экземпляр этого файла -
public function __construct(CustomModelInterface $customModel) {
$this->Model= $customModel;
}
что неверно.
Попробуйте реализовать это в этом классе - class MyService implements CustomModelInterface {
и используйте функцию этого интерфейса, например -
$this->get();
Или вы используете его - class CustomModelRepository implements CustomModelInterface {
Итак, если вы это сделаете -
public function __construct(CustomModelRepository $customModel) {
$this->Model= $customModel;
}
то вы также можете получить доступ к методам интерфейса.
Ответ 4
Я думаю, проблема в том, что вы не привязываете App\Contracts\CustomModelInterface
к чему-либо, поэтому Laravel пытается создать экземпляр интерфейса.
В App\Providers\AppRepositoryProvider.php
у вас есть только:
$models = array(
'Model'
);
но вы также должны иметь в этом массиве CustomModel
, поэтому он должен выглядеть так:
$models = array(
'Model',
'CustomModel',
);
Ответ 5
Обратите внимание, что это также может быть вызвано _constructor при объявлении класса приватным или в противном случае блокируется...
Если он не может вызвать конструктор, привязка завершится неудачно.
Ответ 6
Последнее, что вы делаете, это использовать интерфейс, который вы привязали к репозиторию.
Установите его и попробуйте запустить приложение laravel, чтобы убедиться, что у вас нет ошибок.
В моем случае у меня было несоответствие между моим репозиторием и интерфейсом.
inteface UserRepositoryInterface{
public function get($userId);
}
class UserRepository implements UserRepositoryInterface{
public function get(int $userId);
}
Как вы видите, интерфейс get method не включает подсказку типа, но метод getReador класса UserRepository имеет подсказку типа.
Вы не получите эту ошибку, если сразу начнете использовать привязку интерфейса.
Ответ 7
Для меня я забыл связать в app->providers->RepositoryServiceProvider
репозиторий, подобный этому в методе register
public function register()
{
$this->app->bind(\App\Play\Contracts\PatientRepository::class,\App\Play\Modules\PatientModule::class);
}
убедитесь, что ваш RepositoryServiceProvide
r зарегистрирован в AppServiceProvider
.
public function register()
{
$this->app->register(RepositoryServiceProvider::class);
}
надеюсь, что это поможет кому-то.