Roteamento

Regras de Roteamento Padrão

As regras de roteamento padrão do webman são http://127.0.0.1:8787/{controlador}/{ação}.

O controlador padrão é app\controller\IndexController, e a ação padrão é index.

Por exemplo, ao acessar:

  • http://127.0.0.1:8787 acessará por padrão o método index da classe app\controller\IndexController
  • http://127.0.0.1:8787/foo acessará por padrão o método index da classe app\controller\FooController
  • http://127.0.0.1:8787/foo/test acessará por padrão o método test da classe app\controller\FooController
  • http://127.0.0.1:8787/admin/foo/test acessará por padrão o método test da classe app\admin\controller\FooController (consulte Múltiplas Aplicações)

Além disso, o webman a partir da versão 1.4 suporta um roteamento padrão mais complexo, como por exemplo:

app
├── admin
│   └── v1
│       └── v2
│           └── v3
│               └── controller
│                   └── IndexController.php
└── controller
    ├── v1
    │   └── IndexController.php
    └── v2
        └── v3
            └── IndexController.php

Quando você deseja alterar o roteamento de uma solicitação, você deve editar o arquivo de configuração config/route.php.

Se você quiser desabilitar o roteamento padrão, adicione a seguinte configuração na última linha do arquivo de configuração config/route.php:

Route::disableDefaultRoute();

Roteamento com Closure

Adicione o seguinte código de roteamento no config/route.php

use support\Request;
Route::any('/test', function (Request $request) {
    return response('test');
});

Atenção
Como a função de Closure não pertence a nenhum controlador, por isso $request->app, $request->controller, $request->action estarão todos como strings vazias.

Quando você acessar http://127.0.0.1:8787/test, retornará a string test.

Atenção
O caminho do roteamento deve começar com /, por exemplo:

use support\Request;
// Uso incorreto
Route::any('test', function (Request $request) {
    return response('test');
});

// Uso correto
Route::any('/test', function (Request $request) {
    return response('test');
});

Roteamento de Classe

Adicione o seguinte código de roteamento no config/route.php

Route::any('/testclass', [app\controller\IndexController::class, 'test']);

Quando você acessar http://127.0.0.1:8787/testclass, retornará o valor de retorno do método test da classe app\controller\IndexController.

Parâmetros de Roteamento

Se houver parâmetros na rota, use {key} para correspondência, e o resultado correspondente será passado para os parâmetros do método do controlador correspondente (começando a partir do segundo parâmetro em diante), por exemplo:

// Corresponde a /user/123 /user/abc
Route::any('/user/{id}', [app\controller\UserController::class, 'get']);
namespace app\controller;
use support\Request;

class UserController
{
    public function get(Request $request, $id)
    {
        return response('Recebido o parâmetro '.$id);
    }
}

Mais exemplos:

use support\Request;
// Corresponde a /user/123, não corresponde a /user/abc
Route::any('/user/{id:\d+}', function (Request $request, $id) {
    return response($id);
});

// Corresponde a /user/foobar, não corresponde a /user/foo/bar
Route::any('/user/{name}', function (Request $request, $name) {
   return response($name);
});

// Corresponde a /user, /user/123 e /user/abc   [] indica que é opcional
Route::any('/user[/{name}]', function (Request $request, $name = null) {
   return response($name ?? 'tom');
});

// Corresponde a qualquer solicitação com prefixo /user/
Route::any('/user/[{path:.+}]', function (Request $request) {
    return $request->path();
});

// Corresponde a todas as solicitações options   : seguido por uma expressão regular, indica a regra regex para este parâmetro nomeado
Route::options('[{path:.+}]', function () {
    return response('');
});

Resumo de usos avançados

[] A sintaxe no roteamento do Webman é principalmente usada para lidar com partes opcionais do caminho ou corresponder a rotas dinâmicas, permitindo que você defina estruturas de caminhos e regras de correspondência mais complexas para as rotas.

:questão para especificar expressões regulares

Grupos de Roteamento

Às vezes, as rotas contêm um grande número de prefixos comuns, nesse caso, podemos simplificar a definição usando grupos de roteamento. Por exemplo:

Route::group('/blog', function () {
   Route::any('/create', function (Request $request) {return response('create');});
   Route::any('/edit', function (Request $request) {return response('edit');});
   Route::any('/view/{id}', function (Request $request, $id) {return response("view $id");});
});

Equivalente a

Route::any('/blog/create', function (Request $request) {return response('create');});
Route::any('/blog/edit', function (Request $request) {return response('edit');});
Route::any('/blog/view/{id}', function (Request $request, $id) {return response("view $id");});

Uso aninhado de grupos

Route::group('/blog', function () {
   Route::group('/v1', function () {
      Route::any('/create', function (Request $request) {return response('create');});
      Route::any('/edit', function (Request $request) {return response('edit');});
      Route::any('/view/{id}', function (Request $request, $id) {return response("view $id");});
   });  
});

Middleware de Roteamento

Podemos definir middleware para uma rota ou um grupo de rotas.
Por exemplo:

Route::any('/admin', [app\admin\controller\IndexController::class, 'index'])->middleware([
    app\middleware\MiddlewareA::class,
    app\middleware\MiddlewareB::class,
]);

Route::group('/blog', function () {
   Route::any('/create', function () {return response('create');});
   Route::any('/edit', function () {return response('edit');});
   Route::any('/view/{id}', function ($request, $id) {response("view $id");});
})->middleware([
    app\middleware\MiddlewareA::class,
    app\middleware\MiddlewareB::class,
]);
# Exemplo de uso incorreto (válido para webman-framework >= 1.5.7)
Route::group('/blog', function () {
   Route::group('/v1', function () {
      Route::any('/create', function (Request $request) {return response('create');});
      Route::any('/edit', function (Request $request) {return response('edit');});
      Route::any('/view/{id}', function (Request $request, $id) {return response("view $id");});
   });  
})->middleware([
    app\middleware\MiddlewareA::class,
    app\middleware\MiddlewareB::class,
]);
# Exemplo de uso correto
Route::group('/blog', function () {
   Route::group('/v1', function () {
      Route::any('/create', function (Request $request) {return response('create');});
      Route::any('/edit', function (Request $request) {return response('edit');});
      Route::any('/view/{id}', function (Request $request, $id) {return response("view $id");});
   })->middleware([
        app\middleware\MiddlewareA::class,
        app\middleware\MiddlewareB::class,
    ]);  
});

Roteamento Baseado em Recursos

Route::resource('/test', app\controller\IndexController::class);

// Roteamento de recursos específico
Route::resource('/test', app\controller\IndexController::class, ['index','create']);

// Roteamento de recursos não definidos
// Por exemplo, o acesso a notify pode usar o roteamento de any /test/notify ou /test/notify/{id}, ambos com routeName como test.notify
Route::resource('/test', app\controller\IndexController::class, ['index','create','notify']);
Verbo URI Ação Nome da Rota
GET /test index test.index
GET /test/create create test.create
POST /test store test.store
GET /test/{id} show test.show
GET /test/{id}/edit edit test.edit
PUT /test/{id} update test.update
DELETE /test/{id} destroy test.destroy
PUT /test/{id}/recovery recovery test.recovery

Geração de URL

Atenção
Atualmente, a geração de URL para grupos aninhados de rotas não é suportada.

Por exemplo, a rota:

Route::any('/blog/{id}', [app\controller\BlogController::class, 'view'])->name('blog.view');

Podemos usar o seguinte método para gerar a URL dessa rota.

route('blog.view', ['id' => 100]); // O resultado será /blog/100

Ao usar a URL da rota em uma visão, você pode usar este método, assim qualquer que seja a alteração nas regras de roteamento, a URL será gerada automaticamente, evitando alterações massivas nos arquivos de visão devido a ajustes no endereço das rotas.

Obter Informações da Rota

Através do objeto $request->route, podemos obter informações da rota da solicitação atual, por exemplo:

$route = $request->route; // Equivalente a $route = request()->route;
if ($route) {
    var_export($route->getPath());
    var_export($route->getMethods());
    var_export($route->getName());
    var_export($route->getMiddleware());
    var_export($route->getCallback());
    var_export($route->param());
}

Atenção
Se a solicitação atual não corresponder a nenhuma rota configurada em config/route.php, então $request->route será null, ou seja, quando utilizar o roteamento padrão, $request->route será null.

Tratamento de 404

Quando uma rota não é encontrada, por padrão retorna o código de status 404 e exibe o conteúdo relacionado ao 404.

Se o desenvolvedor quiser intervir no fluxo de negócios quando uma rota não for encontrada, pode usar o método de rota de fallback fornecido pelo webman Route::fallback($callback). Por exemplo, o código abaixo redireciona para a página inicial quando a rota não for encontrada.

Route::fallback(function(){
    return redirect('/');
});

Além disso, quando a rota não existir, retornar um dado em formato json é muito útil quando o webman é usado como uma interface de API.

Route::fallback(function(){
    return json(['code' => 404, 'msg' => '404 não encontrado']);
});

Adicionar Middleware ao 404

Por padrão, solicitações 404 não passam por nenhum middleware. Se você precisar adicionar middleware a solicitações 404, consulte o código abaixo.

Route::fallback(function(){
    return json(['code' => 404, 'msg' => '404 não encontrado']);
})->middleware([
    app\middleware\MiddlewareA::class,
    app\middleware\MiddlewareB::class,
]);

Links relevantes Páginas de erro 404 e 500 personalizadas

Desabilitar Roteamento Padrão

// Desabilita o roteamento padrão do projeto principal, não afeta plugins de aplicação
Route::disableDefaultRoute();
// Desabilita o roteamento da aplicação admin do projeto principal, não afeta plugins de aplicação
Route::disableDefaultRoute('', 'admin');
// Desabilita o roteamento padrão do plugin foo, não afeta o projeto principal
Route::disableDefaultRoute('foo');
// Desabilita o roteamento padrão da aplicação admin do plugin foo, não afeta o projeto principal
Route::disableDefaultRoute('foo', 'admin');
// Desabilita o roteamento padrão do controlador [\app\controller\IndexController::class, 'index']
Route::disableDefaultRoute([\app\controller\IndexController::class, 'index']);

Desabilitar Roteamento Padrão com Anotações

Podemos desabilitar o roteamento padrão para um controlador específico através de anotações, por exemplo:

namespace app\controller;
use support\annotation\DisableDefaultRoute;

#[DisableDefaultRoute]
class IndexController
{
    public function index()
    {
        return 'index';
    }
}

Da mesma forma, também podemos desabilitar o roteamento padrão para um método específico de um controlador como mostrado abaixo:

namespace app\controller;
use support\annotation\DisableDefaultRoute;

class IndexController
{
    #[DisableDefaultRoute]
    public function index()
    {
        return 'index';
    }
}

Interface de Roteamento

// Define roteamento para qualquer método de solicitação $uri
Route::any($uri, $callback);
// Define roteamento para requisições get de $uri
Route::get($uri, $callback);
// Define roteamento para requisições post de $uri
Route::post($uri, $callback);
// Define roteamento para requisições put de $uri
Route::put($uri, $callback);
// Define roteamento para requisições patch de $uri
Route::patch($uri, $callback);
// Define roteamento para requisições delete de $uri
Route::delete($uri, $callback);
// Define roteamento para requisições head de $uri
Route::head($uri, $callback);
// Define roteamento para requisições options de $uri
Route::options($uri, $callback);
// Define roteamentos para múltiplos tipos de requisição
Route::add(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'], $uri, $callback);
// GRUPO de ROTAS
Route::group($path, $callback);
// Roteamento de recursos
Route::resource($path, $callback, [$options]);
// Desabilitar roteamento
Route::disableDefaultRoute($plugin = '');
// Roteamento de fallback, define roteamento padrão
Route::fallback($callback, $plugin = '');
// Obter todas as informações de roteamento
Route::getRoutes();

Se o uri não tiver um roteamento correspondente (incluindo roteamento padrão), e se o roteamento de fallback também não estiver definido, será retornado um 404.

Múltiplos Arquivos de Configuração de Roteamento

Se você quiser usar vários arquivos de configuração de roteamento para gerenciar suas rotas, por exemplo, ao lidar com múltiplas aplicações, onde cada aplicação possui sua própria configuração de roteamento, você pode carregar arquivos de configuração externos através do require.
Por exemplo, no config/route.php:

<?php

// Carregando a configuração de roteamento da aplicação admin
require_once app_path('admin/config/route.php');
// Carregando a configuração de roteamento da aplicação api
require_once app_path('api/config/route.php');