O framework 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, desta maneira tem gerado certa confusão e o erro “Target class [Controller] does not exist”.
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 pois a estrutura básica de seus componentes é mantida, 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.
Corrigindo o erro Target class XXX does not exist
Até a versão 7 do framework 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', 'ArtigosController@getAll');
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 framework 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 [Controller] does not exist
será lançado.
Controller na mensagem acima será o nome do seu controlador na sua mensagem de erro
Como corrigir este erro?
Primeiro vamos entender o problema gerado: o Laravel não sabe onde procurar seu controlador, então é necessário “informar” a ele onde a classe está.
Existem 3 maneiras de fazer isso:
- 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 - Usar o
namespace
completo em seus arquivos de rota ao usar a sintaxe de string - 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\ArtigosController@getAll');
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\ArtigosController@getAll');
// 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.
Comentários