web-dev-qa-db-fra.com

Laravel 5 - L'interface n'est pas instanciable

Je sais que cette question a été posée à maintes reprises, mais aucune des réponses ne m'a aidé.

Je reçois une exception dans Laravel 5

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

Ce que j'ai fait sans succès:

  • Enregistrer App\Providers\AppRepositoryProvider dans les fournisseurs app.php
  • php artisan clear-compiled
  • Tout fonctionne si je remplace les interfaces sur les référentiels dans MyService, mais j'estime que c'est faux (faut-il que ce soit géré par un conteneur IoC?).

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 (Conservez la logique/couche métier entre le contrôleur et les référentiels)

<?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");
        }
    }
}

Mon contrôleur ressemble à:

<?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/"
        }
    },
37
Andrew Kulakov

Merci à tous, mais le problème était dans mon AppRepositoryProvider. Comme il s'agit d'une exception de liaison, le problème était évidemment lié à la liaison :)

Le fichier correct est:

<?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");
        }
    }
}

Notez que j'utilise "App\Contracts\\{$model}Interface" (sans échapper le symbole "{") et qu'il génère la chaîne correcte App\Contracts\CustomModelInterface au lieu de App\Contracts\{$model}Interface (avec l'échappement inattendu).

32
Andrew Kulakov

Chaque fois que je crée un nouveau couple référentiel/contrat, je m'assure de procéder comme suit: 

  1. vérifier les classes utilisées dans le fournisseur de services (copier/coller les espaces de noms)
  2. enregistrer une nouvelle liaison dans config/app.php
  3. php artisan optimise

De nombreuses heures de débogage inutile m'ont conduit à cette courte liste de contrôle.

12
Vlad Visinescu

Pour moi, j'ai oublié de lier dans app->providers->RepositoryServiceProvider Le référentiel comme celui-ci dans la méthode register

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

Assurez-vous que votre RepositoryServiceProvider est enregistré dans AppServiceProvider.

public function register()
{   
    $this->app->register(RepositoryServiceProvider::class);
}
4
Beulah Ana

J'ai dépassé cette erreur en cours d'exécution:

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

Relatif à:

La cible n'est pas instanciable. Laravel 5 - Fournisseur de service de liaison des applications

2
Connor Leech

Sur App\Services\MyService.php, vous passez cette interface avec une injection de dépendance qui tente d’instancier cela - 

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

ce qui est faux.

Essayez d'implémenter cela dans cette classe - class MyService implements CustomModelInterface { et utilisez la fonction de cette interface comme - 

$this->get();

Ou vous l'utilisez - class CustomModelRepository implements CustomModelInterface {

Donc si vous le faites - 

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

alors aussi vous pouvez accéder aux méthodes d'interface.

2
Sougata Bose

Je viens de rencontrer un problème similaire à celui-ci et la cause de mon erreur est que j'avais défini $defer sur true dans la classe de fournisseur de service, mais que je n'avais pas mis en œuvre la méthode provides() requise.

Si vous avez différé la création de votre classe jusqu'à ce que vous en ayez besoin plutôt que de la charger rapidement, vous devez également implémenter la méthode provides qui devrait simplement renvoyer un tableau des classes fournies par le fournisseur. Dans le cas d'une interface, je pense que ce devrait être le nom de l'interface plutôt que la classe concrète.

Par exemple.

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

Documentation actuelle: https://laravel.com/docs/5.5/providers#deferred-providers

J'espère que cela aide quelqu'un d'autre.

1
Kenny Body

Ne vous inquiétez pas les gars. J'ai une solution à votre problème.

J'ai un exemple pour vous.

Etape 1: php artisan: make: repository Repository/Post // En ajoutant cette commande, vous pouvez créer un repository et des fichiers éloquents

Étape 2: Après avoir ajouté ce fichier, vous devez ajouter/utiliser ce référentiel dans le contrôleur dans lequel vous souhaitez utiliser.

par exemple: utilisez App\Repositories\Contracts\PostRepository;

Étape 3: Après avoir ajouté ce dépôt dans votre contrôleur, si vous exécutez l'application, vous obtiendrez une erreur du type "L'interface n'est pas instable". Cela vient du fait que vous avez créé un référentiel et utilisé dans un contrôleur, mais Laravel ne sait pas où se trouve ce référentiel, auquel il est lié. Pour que cela jette une erreur.

Étape 4: Pour résoudre cette erreur, vous devez lier votre référentiel avec votre éloquent dans AppServiceProvider . Par exemple: 

Fichier AppServiceProvider.php

<?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);
    }
}

Étape 5: Après avoir lié repo et éloquent, vous pouvez utiliser toutes les méthodes de repo dans votre contrôleur. Prendre plaisir.....

S'il vous plaît laissez-moi savoir si vous avez une requête.

1
Umang Soni

La dernière chose à faire est d'utiliser l'interface que vous avez liée au référentiel. 

Configurez-le et essayez d’exécuter votre application laravel pour vous assurer que vous n’obtenez aucune erreur. 

Dans mon cas, il y avait une incompatibilité entre mon référentiel et l'interface.

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

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

Comme vous pouvez le constater, la méthode get de l'interface n'inclut pas d'indicateur de type, mais la méthode get de la classe UserRepository a un indicateur de type.

Vous n'obtiendrez pas cette erreur si vous commencez immédiatement à utiliser votre liaison d'interface.

0
Adam Winnipass

Je pense que le problème ici est que vous ne liez pas App\Contracts\CustomModelInterface à quoi que ce soit, alors Laravel essaie de créer une instance d'interface.

Dans App\Providers\AppRepositoryProvider.php vous avez seulement:

$models = array(
            'Model'
        );

mais vous devriez aussi avoir dans ce tableau CustomModel, donc ça devrait ressembler à ça:

$models = array(
            'Model',
            'CustomModel',
        );
0
Marcin Nabiałek

Notez que cela peut aussi être causé par le _constructor de la classe déclaré privé ou bloqué d'une autre manière ... S'il ne peut pas appeler le constructeur, la liaison échouera

0
Lea de Groot