Laravel 5: la interfaz no es instanciable

6 minutos de lectura

avatar de usuario
Andrés Kulakov

Sé que esta pregunta se hizo tantas veces, pero ninguna de las respuestas me ayudó.

Estoy recibiendo una excepción en Laravel 5

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

Lo que he hecho sin éxito:

  • Registro App\Providers\AppRepositoryProvider en app.php proveedores
  • php artisan clear-compiled
  • Todo funciona si reemplazo las interfaces en los repositorios en MyService, pero siento que está mal (¿debería ser manejado por el contenedor IoC?).

Estructura:

app
  - Contracts
    - CustomModelInterface.php
  - Models
    - CustomModel.php
  - Repositories
    - CustomModelRepository.php
  - Providers
    - AppRepositoryProvider.php
  - Services
    - MyService.php

Aplicación\Contratos\CustomModelInterface.php

<?php namespace App\Contracts;

interface CustomModelInterface {
    public function get();
}

Aplicación\Repositorios\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 (Mantener la lógica comercial/capa entre el controlador y los repositorios)

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

Mi controlador se parece a:

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

compositor.json

"autoload": {
        "classmap": [
            "database"
        ],
        "psr-4": {
            "App\\": "app/",
            "App\\Models\\": "app/Models/",
            "App\\Contracts\\": "app/Contracts/",
            "App\\Repositories\\": "app/Repositories/"
        }
    },

  • Hoy encontré esta pregunta porque recibí el mismo mensaje de error. En mi caso, en mi ServiceProvider, tenía la propiedad $defer = true; Esto conduce al mismo error. Si encuentra el mismo problema, simplemente elimine la propiedad.

    – Bart McLeod

    12 de abril de 2016 a las 7:18


avatar de usuario
Vlad Visinescu

Cada vez que creo un nuevo par de repositorio/contrato, me aseguro de hacer lo siguiente:

  1. comprobar las clases utilizadas en el proveedor de servicios (copiar/pegar los espacios de nombres)
  2. registrar un nuevo enlace en config/app.php
  3. optimización artesanal de php

Muchas horas de depuración inútil me llevaron a esta breve lista de verificación.

  • Olvidé el #2, me salvó

    – Fasna

    31 de octubre de 2017 a las 10:29

  • ¡A mí también me faltaba el número 2! Actualicé de Laravel 4 a 5 y necesitaba registrar explícitamente mis proveedores personalizados en config/app.php junto con los proveedores de servicios predeterminados.

    –Rick Gladwin

    3 de junio de 2019 a las 2:16

  • Tuve que ejecutar php artesanal config:cache

    – Máx.

    22 de diciembre de 2020 a las 14:44

avatar de usuario
Andrés Kulakov

Gracias a todos, pero el problema estaba en mi AppRepositoryProvider. Como es una excepción vinculante, obviamente el problema fue con el enlace 🙂

El archivo correcto es:

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

Tenga en cuenta que estoy usando "App\Contracts\\{$model}Interface" (sin escapar del símbolo “{“) y genera la cadena correcta App\Contracts\CustomModelInterface en vez de App\Contracts\{$model}Interface (con escape inesperado).

  • Si no me equivoco, acabas de saltar interface ahora, porque ahora después de la vinculación que ha utilizado, cada vez que llama interface un objeto de repository se resolverá… y no la interfaz, no has usado el SoC patrón de diseño de la forma en que debe ser… Su interface Los archivos ahora son inútiles. Corrígeme si estoy equivocado.

    – Hamza Uaghad

    15 de julio de 2015 a las 17:15

  • ¿Puedes explicar por qué usas App\Contracts\\{$model}Interface y no usar App\Contracts\{$model}Interface ¿qué significa la doble barra invertida?

    – tdycss

    7 de febrero de 2020 a las 17:13

  • @tdycss la primera barra invertida es parte del espacio de nombres, la segunda para escapar del { – sin el escape, terminas con el {} en el espacio de nombres resultante, que no existe en este caso. consulte también la nota debajo del ejemplo de código en la respuesta. Espero que ayude (:

    – Sandra

    9 de junio de 2021 a las 11:29

avatar de usuario
Beulah Ana

Para mí, olvidé enlazar app->providers->RepositoryServiceProvider
el repositorio así en el método de registro

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

Asegúrese de que su RepositoryServiceProvider está registrado en AppServiceProvider.

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

  • Este fue mi error. ¡Gracias!

    – Carlos

    20 de septiembre de 2018 a las 16:08


  • ¡Suena bien! Gracias

    – LuizEduardoMPF

    3 mayo 2019 a las 13:32

  • Por alguna razón, esto solucionó mi problema a pesar de que había agregado el archivo a config/app.php. Registré el proveedor en register(), ejecuté config:cache, eliminé la línea en register() y las cachés subsiguientes tuvieron éxito.

    – Máx.

    4 de febrero de 2021 a las 14:52

Superé este error al ejecutar:

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

Relacionado con:

Target no es instanciable. Laravel 5: proveedor de servicios de enlace de aplicaciones

El problema se resuelve agregando su repositorio en app/providers/AppServiceProvider como en el ejemplo a continuación.

public function register()
{
    $this->app->singleton(UserRepository::class, EloquentUser::class);
 }

No olvides el espacio de nombres

use Test\Repositories\EloquentUser;
use Test\Repositories\UserRepository;

funcionó para mí

avatar de usuario
Sougata Bosé

En App\Services\MyService.php está pasando esa interfaz con inyección de dependencia que intenta instanciar eso:

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

Cuál está mal.

Intenta implementar eso en esa clase – class MyService implements CustomModelInterface { y use la función de esa interfaz como –

$this->get();

O lo estás usando – class CustomModelRepository implements CustomModelInterface {

Así que si lo haces –

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

entonces también puede acceder a los métodos de la interfaz.

Acabo de experimentar un problema similar a este y la causa de mi error fue que había configurado $defer a true en la clase de proveedor de servicios pero no había implementado el requerido provides() método.

Si ha aplazado la creación de su clase hasta que sea necesaria en lugar de cargarla con entusiasmo, entonces también debe implementar el provides método que simplemente debería devolver una matriz de las clases que proporciona el proveedor. En el caso de una interfaz, creo que debería ser el nombre de la interfaz en lugar de la clase concreta.

P.ej

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

Documentación actual: https://laravel.com/docs/5.5/providers#deferred-providers

Espero que esto ayude a alguien más.

  • Correcto. Además, no olvide ejecutar “compositor dump-autoload” después.

    – Ali Bakhshandeh

    9 dic 2021 a las 21:42

¿Ha sido útil esta solución?