PHP MVCDOCUMENTAÇÃO
v2.0.0

Controllers

Responsabilidades do controller base e utilitários reais de resposta.

Classe base

Controllers Web da aplicação herdam de Framework\Http\Controller (no projeto, via App\Http\Controllers\Web\BaseController). O Router instancia a classe e chama a action pública após executar middleware; a classe base cria Request em $this->request. O exemplo seguinte é um método real de AuthController, sem depender de um repositório ilustrativo.

class AuthController extends BaseController
{
public function login(): void
{
    $request = new LoginRequest();
    $data = $this->validateRequest($request, 'auth/login', ['email']);

    $remember = isset($_POST['remember']) && $_POST['remember'] === '1';
    $result = $this->authService->login($data['email'], $data['password'], $remember);

    if (!$result['success']) {
        Session::flash('error', $result['message']);
        Session::flashInput(['email' => $data['email']]);
        $this->redirect('auth/login');
    }

    $this->redirect('dashboard');
}
}

Métodos disponíveis aos filhos

  • view($view, $data = [], $layout = null); viewOnly($view, $data = []).
  • redirect($url), back(), redirectWith($url,$type,$message).
  • json($data,$status=200), jsonSuccess($message='OK',$data=[],$status=200), jsonError($message,$status=400,$data=[]).
  • flash($type,$message); helpers de autenticação auth(), user(), userId(), userRole().
  • checkMethod(), validate(), validateRequest(), abort(), abortIf(), abortUnless().

FormRequest e autorização

O Router identifica parâmetros de action tipados com um FormRequest e repassa os parâmetros nomeados da rota ao instanciá-lo. Consulte Requests e FormRequest.

A classe base não devolve objetos Response: seus utilitários de saída escrevem headers/corpo e encerram a execução quando aplicável. Veja Respostas HTTP e JSON.

Papel do Controller no MVC

O Router instancia a classe e chama uma action pública após identificar a rota e concluir os middlewares. O Controller recebe um Request no construtor base; ele interpreta a entrada, coordena as próximas camadas e escolhe a resposta. Não é o local para concentrar SQL, regras reutilizáveis ou templates.

Request HTTP
  → Router encontra método/caminho
  → Middleware autoriza ou interrompe
  → Controller action
  → Service / Repository / Model
  → View ou JSON / redirect
  → resposta HTTP

As rotas reais de autenticação estão em routes/web.php. Para ver o ponto de entrada e a ordem de despacho, consulte Ciclo da requisição e Roteamento.

Básico · renderizar ou redirecionar

Cenário: visitante abre a raiz do site. A implementação real verifica a autenticação e escolhe entre encaminhar ao dashboard ou renderizar a página pública. A action retorna void porque os helpers emitem a saída.

class HomeController extends BaseController
{
public function index(): void
{
    $this->auth()
        ? $this->redirect('dashboard')
        : $this->view('home.index', ['title' => 'Início'], 'home');
}
}

O `auth()` é um helper protegido que consulta o estado web. `view()` recebe o nome por dot notation, os dados e o layout; `redirect()` é terminal. Esta é a action real de App\Http\Controllers\Web\HomeController.

Intermediário · validar, delegar e redirecionar (trecho real)

Cenário: POST /auth/login. O grupo /auth e o middleware CSRF/rate-limit já protegem a rota. O FormRequest aplica regras e normalização; `validateRequest()` guarda somente os campos seguros pedidos se houver erro e interrompe por redirect. O Service tenta autenticar; o Controller traduz o resultado para flash + navegação.

class AuthController extends BaseController
{
public function login(): void
{
    $request = new LoginRequest();
    $data = $this->validateRequest($request, 'auth/login', ['email']);

    $remember = isset($_POST['remember']) && $_POST['remember'] === '1';
    $result = $this->authService->login($data['email'], $data['password'], $remember);

    if (!$result['success']) {
        Session::flash('error', $result['message']);
        Session::flashInput(['email' => $data['email']]);
        $this->redirect('auth/login');
    }

    $this->redirect('dashboard');
}
}

Esse recorte corresponde a App\Http\Controllers\Web\AuthController::login(). A senha não é repassada como old input. O resultado do Service é um array de domínio, não uma resposta HTTP; escolher redirect/JSON é responsabilidade do Controller.

Completo · action de API já registrada

Em GET /api/v1/users/{id}, ApiAuthMiddleware autentica o token antes da action. A implementação real consulta UserRepository, converte o objeto em UserResource e responde pelo envelope padronizado da API.

class UserApiController extends ApiController
{
public function show(int $id): void
{
    $user = $this->users->findById($id);

    if (!$user) {
        $this->error('Usuário não encontrado.', [], 404);
    }

    $this->success(UserResource::make($user));
}
}

O `int $id` vem do placeholder nomeado `{id}`. `error()` e `success()` encerram o fluxo, por isso a execução não continua após eles. Veja contratos de resposta e rotas da API.

Consulte a referência detalhada, com assinatura, parâmetros, retorno, efeitos e exemplos, em Métodos herdados do Controller. Para campos HTTP, use $this->request e a página de Requests.

Métodos herdados do Controller: referência prática

As assinaturas abaixo são métodos de instância protegidos, disponíveis em subclasses. view* emite HTML; redirects e helpers JSON encerram o fluxo; validação Web pode redirecionar. Para endpoints JSON, prefira os contratos de API e respostas HTTP.

Renderização e navegação

view(string $view, array $data = [], string|false|null $layout = null): void

Resolve e renderiza a view com as variáveis de $data. false ou string vazia desliga o layout; null usa $this->defaultLayout (por padrão, string vazia/sem layout; a subclasse pode sobrescrever a propriedade e a aplicação pode definir DEFAULT_LAYOUT). Tokens CSRF compatíveis são injetados no HTML. Use para resposta HTML de uma action.

$this->view('users.show', ['user' => $user], 'main');

A view precisa existir sob resources/views; valores interpolados continuam exigindo escaping contextual.

viewOnly(string $view, array $data = []): void

Atalho para renderizar sem layout. Retorno void; a saída vai diretamente ao corpo HTTP.

$this->viewOnly('emails.preview', ['message' => $message]);
redirect(string $url): never e back(): never

redirect() envia um destino local seguro ou permitido e termina a requisição; back() usa o Referer validado e cai no destino padrão se ele for ausente/inseguro. Caminhos relativos sem barra inicial, como dashboard, não são aceitos como rota e podem cair em APP_URL; use /dashboard quando a intenção for esse caminho.

$this->redirect('/dashboard');
$this->back();

Use depois de uma operação Web; não é um mecanismo de resposta JSON.

redirectWith(string $url, string $type, string $message): never

Grava a mensagem na sessão pela chave $type e redireciona. Os argumentos são destino, chave (por exemplo, success/error) e texto.

$this->redirectWith('/users', 'success', 'Usuário criado.');

A view seguinte deve consumir o flash; não grave segredos ou tokens na mensagem.

Respostas JSON

json(mixed $data, int $status = 200): never

Define tipo JSON, serializa o payload e encerra. A codificação inválida resulta em erro 500.

$this->json(['id' => $id], 201);
jsonSuccess(string $message = 'OK', array $data = [], int $status = 200): never

Emite success=true, message e os campos de $data. Como usa array_merge, chaves coincidentes em $data podem substituir os valores padrão; evite colisões.

$this->jsonSuccess('Criado', ['user' => $user], 201);
jsonError(string $message, int $status = 400, array $data = []): never

Emite success=false, mensagem e campos extras com o status HTTP fornecido.

$this->jsonError('Entrada inválida', 422, ['errors' => $errors]);

Não troque a ordem: o segundo argumento é o status, o terceiro é o array extra.

Sessão, identidade e método

flash(string $type, string $message): void

Armazena uma mensagem de sessão para leitura posterior. O getter de flash remove a chave quando lida; mensagens nunca consumidas não devem ser tratadas como expiração automática.

$this->flash('success', 'Alterações salvas.');
auth(): bool, user(): ?object, userId(): int, userRole(): string

Consultam a identidade de sessão atual: autenticação, usuário carregado e identificadores/role. userId() usa zero quando não há usuário; userRole() usa o fallback da implementação. São getters, não guards: proteja rotas com middleware/guards e verifique auth() antes de confiar nos dados.

if (!$this->auth()) {
    $this->redirect('/auth/login');
}
$userId = $this->userId();
checkMethod(string|array $types, string $message = 'Requisição inválida.', int $status = 400): void

Continua quando o método/tipo solicitado corresponde ao da requisição; aceita os tipos implementados ajax, json, get, post, put, patch e delete. Caso contrário, responde em JSON com a mensagem/status informados. Um tipo desconhecido lança InvalidArgumentException e pode virar 500 no dispatch.

$this->checkMethod('post', 'Envie um formulário POST.', 405);

Validação Web e encerramento por erro

validate(array $data, array $rules, string $redirectBack = ''): array

Valida os dados e devolve o próprio array de entrada se válido; não filtra para apenas campos validados. Em falha, grava erros e todo o input como old input e redireciona. Não passe senhas, tokens ou arquivos se não quiser persistir esses valores na sessão; prefira FormRequest com allowlist de campos a repassar.

$data = $this->validate($this->request->all(), [
    'email' => 'required|email',
], '/users/create');
validateRequest(object $request, string $redirectBack = '', ?array $flashOnly = null): array

Recebe uma instância FormRequest pronta e retorna validated() no sucesso. Na falha, grava o primeiro erro e redireciona; null repassa todo input, um array limita os campos e [] não repassa nenhum. Para API, use o caminho JSON do ApiController/FormRequest em vez do redirect Web.

$form = new \App\Http\Requests\Auth\LoginRequest();
$data = $this->validateRequest($form, '/auth/login', ['email']);
abort(int $code, string $message = ''): never, abortIf(mixed $condition, int $code, string $message = ''): void, abortUnless(mixed $condition, int $code, string $message = ''): void: lançam RuntimeException contendo o código solicitado. Atenção: no dispatch atual, o Router captura qualquer Throwable da action/middleware e emite 500; não use abort(404) para prometer 404 neste caminho. Uma verificação abortIf(!$user, 404, ...) também produz 500 no estado atual. Corrigir o mapeamento exige mudança no framework, vedada nesta tarefa.

Construtores personalizados de Controller devem chamar parent::__construct() antes de usar $this->request; a inicialização da propriedade não é injeção automática. O exemplo intermediário desta página segue esse contrato.