Подтвердить что ты не робот

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/"
        }
    },
4b9b3361

Ответ 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);
}

надеюсь, что это поможет кому-то.