Tipos de Controllers no Magento 2

Contextualizando

O que é um controlador?

Um controlador faz parte da camada de controle do padrão de arquitetura de software MVC (Model-Controller-View).

Um controlador é responsável por intermediar as requisições enviadas pela camada de visualização (View) com as respostas fornecidas pela camada de modelo (Model), processando os dados que o usuário informou e repassando para outras camadas.

Código

Controllers da loja devem seguir a estrutura de pastas \{Vendor}\{Module}\Controller\{ControllerDirectory}\{ControllerName} e implementar a interface \Magento\Framework\App\ActionInterface, que obriga a classe a implementar o método execute().

Caso esteja utilizando uma versão anterior a 2.4.0 do magento, a interface \Magento\Framework\App\ActionInterface não é estará disponível, então deverá estender a classe \Magento\Framework\App\Action\Action e ajustar o construtor com suas heranças.

Json

As classes Controllers (controladores) podem retornar objetos Json com o tipo mime na resposta.

<?php

namespace {Vendor}\{Module}\Controller\{ControllerDirectory};

use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\Controller\Result\Json;

class {ControllerName} implements ActionInterface
{
    protected JsonFactory $jsonResultFactory;

    public function __construct(
        JsonFactory $jsonResultFactory
    ) {
        $this->jsonResultFactory = $jsonResultFactory;
    }

    public function execute(): Json
    {
        $data = [
            '{param}' => '{value}',
            'message' => __('{Message to return}'),
            'error' => false
        ];

        $jsonResult = $this->jsonResultFactory->create();
        $jsonResult->setData($data);

        return $jsonResult;
    }
}

Raw

As classes Controllers (controladores) podem ter retorno do tipo string ou conteúdos binários.

<?php

namespace {Vendor}\{Module}\Controller\{ControllerDirectory};

use Magento\Framework\Controller\Result\RawFactory;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\Controller\Result\Raw;

class {ControllerName} implements ActionInterface
{
    protected RawFactory $rawResultFactory;

    public function __construct(
        RawFactory $rawResultFactory
    ) {
        $this->rawResultFactory = $rawResultFactory;
    }

    public function execute(): Raw
    {
        $rawResult = $this->rawResultFactory->create();
        $rawResult->setContents('{Custom message}');

        return $rawResult;
    }
}

Redirect

As classes Controllers (controladores) podem ter uma string com a rota de redirecionamento para outra págna como retorno.

<?php

namespace {Vendor}\{Module}\Controller\{ControllerDirectory};

use Magento\Framework\Controller\Result\RedirectFactory;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\Controller\Result\Redirect;

class {ControllerName} implements ActionInterface
{
    protected RedirectFactory $redirectResultFactory;

    public function __construct(
        RedirectFactory $redirectResultFactory
    ) {
        $this->redirectResultFactory = $redirectResultFactory;
    }

    public function execute(): Redirect
    {
        $redirectResult = $this->redirectResultFactory->create();
        $redirectResult->setPath('{router_name}/{controller_directory}/{className}')
            ->setHttpResponseCode(301);

        return $redirectResult;
    }
}

Forward

As classes Controllers (controladores) podem ter retorno com um encaminhamento interno para outro controlador sem que o usuário faça uma segunda solicitação.

<?php

namespace {Vendor}\{Module}\Controller\{ControllerDirectory};

use Magento\Framework\Controller\Result\ForwardFactory;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\Controller\Result\Forward;

class {ControllerName} implements ActionInterface
{
    protected ForwardFactory $forwardResultFactory;

    public function __construct(
        ForwardFactory $forwardResultFactory
    ) {
        $this->forwardResultFactory = $forwardResultFactory;
    }

    public function execute(): Forward
    {
        $forwardResult = $this->forwardResultFactory->create();
        $forwardResult->setModule('{module_name}')
            ->setController('{controller_directory}')
            ->forward('{controller_name}')
            ->setParams(['{param}' => '{value}']);

        return $forwardResult;
    }
}

A convenção é que no método setModule() seja definido o nome do diretório do módulo, o setController() deve ser o nome do diretório dentro do diretório Controller do módulo e o forward() é o nome da classe que irá ser renderizada através do controller forward.
É possível passar parâmetros através de um array. Caso o nome do módulo não seja seja fornecido, o Magento irá assumir que será o módulo presente no controller do forward.

Page

As classes Controllers (controladores) podem ter retorno em forma de HTML com um arquivo layout vinculado ao controlador que renderizará a página.

<?php

namespace {Vendor}\{Module}\Controller\{ControllerDirectory};

use Magento\Framework\View\Result\PageFactory;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\View\Result\Page;

class {ControllerName} implements ActionInterface
{
    protected PageFactory $resultPageFactory;

    public function __construct(
        PageFactory $resultPageFactory
    ) {
        $this->resultPageFactory = $resultPageFactory;
    }

    public function execute(): Page
    {
        return $this->resultPageFactory->create();
    }
}

Layout

As classes Controllers (controladores) podem ter retorno em forma de HTML e pode ser usado como o Page. Além disso o Layout também podem renderizar o HTML de blocos específicos.

<?php

namespace {Vendor}\{Module}\Controller\{ControllerDirectory};

use Magento\Framework\View\Result\LayoutFactory;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\View\Result\Layout;

class {ControllerName} implements ActionInterface
{
    protected LayoutFactory $resultLayoutFactory;

    public function __construct(
        LayoutFactory $resultLayoutFactory
    ) {
        $this->resultLayoutFactory = $resultLayoutFactory;
    }

    public function execute(): Layout
    {
        return $this->resultLayoutFactory->create()
            ->getLayout()
            ->getBlock('{block.name}')
            ->toHtml();
    }
}

Admin

Controllers do admin devem seguir a estrutura de pastas \{Vendor}\{Module}\Controller\Adminhtml\{ControllerDirectory}\{ControllerName} e estender a classe abstrata \Magento\Backend\App\AbstractAction, que obriga a classe a implementar o método execute().

<?php

namespace {Vendor}\{Module}\Controller\Adminhtml\{ControllerDirectory};

use Magento\Framework\View\Result\PageFactory;
use Magento\Backend\App\AbstractAction;
use Magento\Backend\App\Action\Context;
use Magento\Framework\View\Result\Page;

class {ControllerName} extends AbstractAction
{
    protected PageFactory $resultPageFactory;

    public function __construct(
        Context $context,
        PageFactory $resultPageFactory
    ) {
        parent::__construct($context);
        $this->resultPageFactory = $resultPageFactory;
    }

    public function execute(): Page
    {
        return $this->resultPageFactory->create();
    }
}

O exemplo mostra como declarar um controller do tipo Page na área administrativa no Magento, mas pode ser utilizado qualquer um dos tipos de controllers.

Finalizando

Valores entre chaves ({test}) devem ser alterados na implementação do código.

Habilitando as alterações

Execute o comando PHP para gerar a configuração das injeções de dependência e todas as classes ausentes que precisam ser geradas (proxys, interceptors, etc).

php bin/magento setup:di:compile

Diretórios e Arquivos

Segue a a lista de diretórios e arquivos que devem ser criados.

- app/
  - code/
    - {Vendor}/
        - {Module}/
          - Controller/
            - {ControllerDirectory}/
              - {ControllerName}.php
          - etc/
            - module.xml
          - registration.php
          - composer.json

18