O padrão arquitetural Porto possui algumas camadas para tratar cada parte da aplicação. Nesse post vamos conhecer um pouco mais sobre cada uma dessas camadas e também sobre os componentes que podem compor a camada de containers.
Curso PHP - Orientação a Objetos - Parte 1
Conhecer o cursoCamadas do padrão Porto
O padrão arquitetural Porto é composto por 2 camadas principais Ship (navio) e Containers. Conforme ilustra o diagrama abaixo:
Existe também uma terceira camada mais conceitual chamada Sea (oceano), que podemos considerar como sendo os recursos de baixo nível que usamos na aplicação, como frameworks e bibliotecas, conforme mostrado acima.
Camada Ship
A camada Ship (navio) é a camada intermediária da nossa aplicação. Ela faz a ligação entre o código de baixo nível da camada Sea (oceano) e a camada de alto nível Containers.
Na parte de interação com o baixo nível que são os frameworks, bibliotecas e outras APIs de baixo nível da linguagem. A camada de Ship possui recursos, como bootstrap necessário para a aplicação, arquivos de configuração, registro de serviços e outros detalhes específicos.
Ela abriga também classes genéricas que são usadas dentro dos containers, como exceções, middlewares, classes de integração com serviços específicos, configurações compartilhadas e outros.
A camada de Ship ainda conta com classes de base. Essas classes podem ser estendidas dentro da camada Containers e permitem compartilhar código entre os diversos containers da aplicação.
Camada de containers
A camada de containers possui o código de alto nível da aplicação. Ela interage com a camada de nível intermediário (Ship).
Ela é responsável pela implementação da regra de negócio da aplicação. A ideia é que cada container contenha uma parte da regra de negócio. Ele deve receber a requisição e responder de acordo com cada UI (User Interface), que pode ser uma API, aplicação clássica web ou outra interface.
O ideal é que cada container esteja ligado a somente uma entidade/model da aplicação, mas nada impede que ele possua mais de um, porém quanto maior a quantidade de models, maior a complexidade do container, algo que o padrão estrutural tenta ao máximo evitar. Quanto mais simples os containers, maior a possibilidade de reutilizá-lo.
Componentes dos containers no padrão arquitetural Porto
Os containers são formados por componentes, cada um com sua responsabilidade. Eles podem ser componentes obrigatórios e opcionais.
O diagrama abaixo mostra como os componentes interagem dentro de um container:
Os componentes pontilhados são opcionais enquanto os com linha contínua são obrigatórios. Note que temos os mesmos componentes do padrão MVC, veremos abaixo a responsabilidade deles no Porto.
Responsabilidade dos componentes no padrão arquitetural porto
Responsabilidade dos principais componentes:
- Route - É o componente responsável por definir para cada caminho acessado qual será o controller responsável;
- Controller - Recebe os dados da requisição, realiza a validação e autorização (em classe separada), envia para processamento em uma action e devolve a resposta apropriada;
- Request - É o componente que obtém os dados de input da requisição. Pode também validar os dados e fazer autorização a partir deles. Deve sempre ser chamada a partir do controller;
- Action - É responsável por receber os dados do controller, processar e devolver a ele. Ela está diretamente ligada a uma regra de negócio específica, se estivermos usando diagrama de caso de uso, podemos dizer que uma action é responsável por um caso de uso específico;
- Task - Componente onde podemos colocar pequenas regras de negócio e que serão chamadas por diferentes actions do mesmo container ou de outros para evitar duplicidade;
- Model - Usado para representar a estrutura no banco de dados. Ele não deve conter regras de negócio, apenas elementos referente ao mapeamento das tabelas e relacionamentos do banco de dados;
- View - Elemento usado para separar o HTML da lógica da aplicação. Usada somente para UI (User Interface) web;
- Transformers - Responsável por preparar os dados de saída quando trabalhamos com retornos para API. Sua principal vantagem é desacoplar o modo como os dados são retornados pelos modelos, permitindo a API retorna-los conforme sua necessidade;
- Exceptions - Classes de exceções personalizadas, usadas para especificar as exceções que acontecem dentro do container;
- Sub-Actions - Possui basicamente a mesma função das actions, porém é usada para eliminar duplicação de código. Ao invés repetir o mesmo código em duas Actions, usamos uma sub-action.
Existe também os componentes opcionais que podem ser usados conforme a necessidade do projeto.
Estrutura de pastas de container no padrão Porto
Abaixo é possível ver a estrutura de pastas de um container usando os principais componentes que conhecemos:
Container
├── Actions
├── Tasks
├── Models
├── Exceptions
├── Tests
│ ├── Unit
│ └── Traits
└── UI
├── API
│ ├── Routes
│ ├── Controllers
│ ├── Requests
│ ├── Transformers
│ └── Tests
│ └── Functional
├── WEB
│ ├── Routes
│ ├── Controllers
│ ├── Requests
│ ├── Views
│ └── Tests
│ └── Acceptance
└── CLI
├── Routes
├── Commands
└── Tests
└── Functional
Seções de containers
Os containers podem ser agrupados em seções. O principal objetivo delas é separar os containers de acordo com o contexto.
Cada seção de containers pode representar uma parte do seu sistema, o arquiteto tem a liberdade de escolher como criar as sessões e quais containers estarão dentro dela de acordo com sua aplicação.
Considerações finais
O padrão arquitetural Porto faz uso de vários conceitos que já são utilizados normalmente em aplicações back-end, o que facilita aos desenvolvedores compreenderem o que cada componente faz e também garante algumas características já comprovadas ao utilizar esses conceitos.
Você pode ler a documentação completa sobre o padrão Porto no seu repositório do Github.