Como corrigir o erro “Target class does not exist” no Laravel 8

Laravel 8

O Laravel 8 trás uma série de novos recursos, melhorias em funções já conhecidas e algumas alterações estruturais. Uma destas mudanças foi a remoção do “namespacing” de rota padrão.

Esta mudança é compatível com versões anteriores, o que significa que projetos mais antigos que usavam o Laravel 7.x podem facilmente migrar para o Laravel 8.x, sem alterar nada, porém novos projetos criados no Laravel 8 devem levar isso em consideração.

O problema decorrente desta mudança em seus aplicativos Laravel 8 recém-criados, ao tentar carregar as rotas depara-se com uma exceção como:

Target class [MeuController] does not exist.

O problema não está relacionado necessariamente a um erro de código, mas a um ajuste necessário, ainda mais levando em conta que 99,9% dos tutoriais a respeito Laravel (ao menos até a versão 7) não dependia deste ajuste de namespace padrão para a configuração de rotas.

A Mudança

Até a versão 7 do Laravel, o arquivo RouteServiceProvider.php tinha o seguinte código na configuração da propriedade $namespace:

<?php

    protected $namespace = 'App\Http\Controllers';

...

    public function boot()
    {
        ...
        Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web.php'));

Na leitura deste código: por padrão o Laravel configurava o Service para carregar as rotas em routes/web.php, usando o middleware web e o namespace App\Http\ Controllers. Isso, por sua vez, significa que sempre que você declarar uma rota usando a sintaxe de string, o Laravel irá procurar pela classe controladora, considerando como “raiz” a pasta App\Http\ Controllers. Como no exemplo da configuração de uma rota:

Route::get('artigos', '[email protected]');

Qual mudança ocorreu no Laravel 8? Simples porém impactante, a variável $namespace não é mais configurada por padrão no RouteServiceProvider, e a declaração/configuração do carregamento de rotas alterou para:

Route::middleware('web')
    ->group(base_path('routes/web.php'));

Isto significa que o Laravel está procurando por rotas dentro do seu arquivo web.php, como sempre. Também está aplicando o middleware da web, como sempre. Porém, observe que ele não está mais usando o namespace anterior.

Isso significa que a partir do Laravel 8, quando você declara suas rotas usando a sintaxe de string, o Laravel não vai procurar seu controlador dentro de App\Http\Controllers. E caso você utilize esta sintaxe, o erro de exceção Target class [NomeDoMeuController] does not exist será lançado.

Como corrigir este erro?

Primeiro vamos entender o problema gerado: o Laravel não sabe onde procurar seu controlador, então é necessário “dizer” a ele onde a classe está!

Existem 3 maneiras de fazer isso:

  1. Adicionando o $namespace novamente na configuração para que você possa continuar usando as rotas como fazia no Laravel 7.x e versões anteriores
  2. Usar o namespace completo em seus arquivos de rota ao usar a sintaxe de string
  3. Usar a sintaxe de ação – action syntax(recomendado)

Adicionando a configuração do $namespace

Isso é bastante simples. Acesse o arquivo RoutesServiceProvider.php, primeiramente insira a linha a seguir no início da classe (ou retire o comentário se ela existir assim):

protected $namespace = 'App\Http\Controllers';

Em seguida adicione a chamada ao método namespace para cada configuração de rota na função boot. O resultado deve se parecer com o código a seguir:

    public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace) // <- esta linha deve ser inserida
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->namespace($this->namespace)  // <- esta linha deve ser inserida
                ->group(base_path('routes/web.php'));

Desta maneira voltamos a configurar as rotas do Laravel para que ele considere o App\Http|Controllers a base para sua descoberta.

Usando o namespace completo

Esta alteração envolve alterar todas as suas declarações de rota. Apesar de trabalhoso é simples: prefixe os nomes dos seus controladores com seus namespaces. No exemplo a seguir para uma classe ArtigosController dentro da pasta app/Http/Controllers:

// note como adicionamos o namespace completo antes do nome da classe
Route::get('artigos', 'App\Http\Controllers\[email protected]');

Usando a sintaxe de ação – action syntax

Esta é a alternativa mais recentemente recomendada por ser menos suscetível a erros de digitação e, em minha experiência, oferece melhor suporte ao IDE, pois informamos explicitamente ao código qual classe usar.

Portanto, ao invés de usarmos a sintaxe de string usual, podemos usar a sintaxe de ação em que especificamos a classe e o método a serem usados em uma matriz como parâmetro do método da rota sendo configurado:

// sintaxe de string
Route::get('artigos', 'App\Http\Controllers\[email protected]');

// sintaxe ação. 
use App\Http\Controllers\ArtigosController;

Route::get('artigos', [ArtigosController::class, 'getAll']);

Note que para utilizar a sintaxe de ação é necessário importar a classe no arquivo de rotas, usando use App\Http\Controllers\ArtigosController, isto será necessário para todas as classes de controladores a serem utilizadas.

O atributo das classes PHP, ::class trará o namespace completo, juntamente com o nome da classe, desta maneira o Laravel saberá onde encontrar o controlador e irá executar o método passado na segunda da posição do array, em nosso exemplo o método getAll.

Considerações finais

Agora seu aplicativo deve funcionando corretamente. Caso ainda encontre problemas, sinta-se à vontade para pedir ajuda. Você pode me encontrar no Twitter como @nunomazer.

Se você adicionou o namespace manualmente, especificou-o completo em suas rotas, ou seguiu com a sintaxe de ação, o que você acabou de fazer foi dizer ao Laravel como encontrar seus controladores na estrutura da aplicação.

Mantenha-se atualizado

Não esqueça de me seguir no Twitter e assinar o Canal Mazer.dev no Youtube para receber atualizações de novos artigos, vídeo aulas e cursos gratuitos em desenvolvimento e engenharia de software.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *