Skip to content

Latest commit

 

History

History
575 lines (390 loc) · 13.5 KB

README.md

File metadata and controls

575 lines (390 loc) · 13.5 KB

MapaCultural - Nova Arquitetura

Essa é a nova documentação do MapaCultural, voltada para desenvolvedores e/ou entusiastas do código.

Acesso Rápido

Instalação dos Pacotes
Controller
Repository
Command
Data Fixtures
Testes
Console

Getting Started

Instalação dos pacotes

Para instalar as dependências e atualizar o autoload, entre no container da aplicação e execute:

composer.phar install

Controller

Os Controllers em conjunto com as Routes permitem criar endpoints para diversas finalidades.

Como criar um novo controller

1 - Controller

Crie uma nova classe em /app/Controller/Api/, por exemplo, EventApiController.php:

<?php

declare(strict_types=1);

namespace App\Controller\Api;

class EventApiController
{
    
}

2 - Método/Action

Crie seu(s) método(s) com a lógica de resposta.

Para gerar respostas em json, estamos utilizando a implementação da JsonResponse fornecida pelo pacote do Symfony:

<?php

declare(strict_types=1);

namespace App\Controller\Api;

use Symfony\Component\HttpFoundation\JsonResponse;

class EventApiController
{
    public function getList(): JsonResponse
    {
        $events = [
            ['id' => 1, 'name' => 'Palestra'],
            ['id' => 2, 'name' => 'Curso'],
        ];   
    
        return new JsonResponse($events);
    }
}

3 - Rotas

Acesse o arquivo /app/routes/api.php e adicione sua rota, informando o path, o verbo HTTP, e apontando pro seu controller e método

use App\Controller\Api\EventApiController;
use Symfony\Component\HttpFoundation\Request;

$routes = [
    //... other routes
    '/api/v2/events' => [
        Request::METHOD_GET => [EventApiController::class, 'getList']
    ],
];

Se preferir pode criar um arquivo no diretório /app/routes/api/ e isolar suas novas rotas nesse arquivo, basta fazer isso:

// /app/routes/api/event.php

use App\Controller\Api\EventApiController;
use Symfony\Component\HttpFoundation\Request;

return [
    '/api/v2/events' => [
        Request::METHOD_GET => [EventApiController::class, 'getList'],
        Request::METHOD_POST => [EventApiController::class, 'create'],
    ],
];

Esse seu novo arquivo será reconhecimento automagicamente dentro da aplicação.

4 - Pronto

Feito isso, seu endpoint deverá estar disponivel em: http://localhost/api/v2/events

E deve estar retornando algo como:

[
  {
    "id": 1,
    "name": "Palestra"
  },
  {
    "id": 2,
    "name": "Curso"
  }
]

Validation

A camada de validação é responsável por validar as entradas e saídas de dados

Documentação do Validator: https://symfony.com/doc/current/components/validator.html

Para organizar e validar esses dados nós utilizaremos o componente de validação atrelados a um DTO, cada propriedade terá suas regras e grupos

Como criar um novo DTO

1 - Data Transfer Object (DTO)

Crie uma nova classe em /app/DTO/, por exemplo, SealDTO.php:

<?php

declare(strict_types=1);

namespace App\DTO;

final class SealDTO
{
    ...   
}

2 - Propriedades

Para cada propriedade do DTO, descreva as regras de validação e os grupos

Lista completa de regras do componente

<?php

declare(strict_types=1);

namespace App\DTO;

use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Sequentially;
use Symfony\Component\Validator\Constraints\Type;

final class SealDTO
{
    #[Sequentially([new NotBlank(), new Type('string')], groups: ['post'])]
    #[Type('string', groups: ['patch'])]
    public mixed $name;

    [...]   
}

3 - Validando

Como mostrado no código acima a propriedade tem uma regra de validação e um grupo, esse grupo é importante para discernir o contexto de quais regras devem ser utilizadas

Por exemplo, no código acima temos uma regra em especial para o post, a propriedade name é requerida.

Agora como esse DTO será usado para validar algo?!

Após a requisição ser enviada, o corpo será transformado de array para SealDTO, então iremos passar o objeto e o grupo para o validator, caso tenha alguma violação ela será retornada

[...]

$seal = $this->serializer->denormalize($data, SealDto::class);

$validation = Validation::createValidatorBuilder()->enableAttributeMapping()->getValidator();

$violations = $validation->validate($seal, groups: ['patch']);

if (0 < count($violations)) {
    throw new ValidatorException(violations: $violations);
}

[...] 

O código acima normalmente estará no Controller ou Request

O objeto dessa validação é validar dados e não regra de négocio


Repository

A camada responsável pela comunicação entre nosso código e o banco de dados.

Como criar um novo repository

Siga o passo a passo a seguir:

Passo 1 - Crie sua classe no /app/src/Repository e extenda a classe abstrata AbstractRepository

<?php

declare(strict_types=1);

namespace App\Repository;

class MyRepository extends AbstractRepository
{
}

Passo 2 - Defina a Entity principal que esse repositório irá gerenciar

use Doctrine\Persistence\ObjectRepository;
use App\Entity\MyEntity;
...

private ObjectRepository $repository;

public function __construct()
{
    parent::__construct();
    
    $this->repository = $this->entityManager->getRepository(MyEntity::class);
}

caso a sua entidade não esteja mapeada nessa parte da aplicação (V8), você precisará de um entityManager diferente, observer a seguir:

use Doctrine\Persistence\ObjectRepository;
use MapasCulturais\Entities\MyEntity;
...

private ObjectRepository $repository;

public function __construct()
{
    parent::__construct();
    
    $this->repository = $this->mapaCulturalEntityManager->getRepository(MyEntity::class);
}

Migrations

Migrations são a forma (correta) de fazer um versionamento do banco de dados, nesta parte da aplicação isso é fornecido pela biblioteca doctrine/migrations mas no core do MapaCultural isso ainda é feito por uma decisão técnica interna chamada db-updates.php

Como criar uma nova migration

Passo 1 - Criar uma nova classe no diretório /app/migrations

<?php

declare(strict_types=1);

namespace App\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20241231235959 extends AbstractMigration
{
    public function up(Schema $schema): void
    {
        //$this->addSql('CREATE TABLE ...');
    }
    
    public function down(Schema $schema): void
    {
        //$this->addSql('DROP TABLE ...');
    }
}

Note que o nome da classe deve informar o momento de sua criação, para que seja mantida uma sequencia temporal da evolução do esquema do banco de dados.

Documentação oficial das migrations do Doctrine: https://www.doctrine-project.org/projects/doctrine-migrations/en/3.8/reference/generating-migrations.html

Command

Comandos são entradas via CLI (linha de comando) que permitem automatizar alguns processos, como rodar testes, veririfcar estilo de código, e debugar rotas

Como criar um novo console command

Passo 1 - Criar uma nova classe em app/src/Command/:

<?php

namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class MyCommand extends Command
{
    protected static string $defaultName = 'app:my-command';
    
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $output->writeln('Hello World!');
        
        return Command::SUCCESS;  
    }
} 

Passo 2 - Testar seu comando no CLI

Entre no container da aplicação PHP e execute isso

php app/bin/console app:my-command

Você deverá ver na tela o texto Hello World!

Passo 3 - Documentação do pacote

Para criar e gerenciar os nosso commands estamos utilizando o pacote symfony/console, para ver sua documentação acesse:

Saiba mais em https://symfony.com/doc/current/console.html

Para ver outros console commands da aplicação acesse a seção Console Commands


Data Fixtures

Data Fixtures são dados falsos, normalmente criados para testar a aplicação, algumas vezes são chamados de "Seeders".

Como criar uma DataFixture para uma Entidade

Passo 1 - Criar uma nova classe em app/src/DataFixtures/:

<?php

namespace App\DataFixtures;

use Doctrine\Persistence\ObjectManager;
use MapasCulturais\Entities\Agent;

class AgentFixtures extends Fixture
{
    public function load(ObjectManager $manager): void
    {
        $agent = new Agent();
        $agent->name = 'Agente Teste da Silva';
        
        $manager->persist($agent);
        $manager->flush();
    }
} 

Passo 2 - Executar sua fixture no CLI

Entre no container da aplicação PHP e execute isso

php app/bin/console app:fixtures

Pronto, você deverá ter um novo Agente criado de acordo com a sua Fixture.

Saiba mais sobre DataFixtures em https://www.doctrine-project.org/projects/doctrine-data-fixtures/en/1.7/index.html


Testes

Estamos utilizando o PHPUnit para criar e gerenciar os testes automatizados, focando principalmente nos testes funcionais, ao invés dos testes unitários.

Documentação do PHPUnit: https://phpunit.de/index.html

Como criar um novo teste

Criar um novo teste

Para criar um no cenário de teste funcional, basta adicionar sua nova classe no diretório /app/tests/functional/, com o seguinte código:

<?php

namespace App\Tests\Functional;

class MeuTest extends AbstractTestCase
{
    
}

Adicione dentro da classe os cenários que você precisa garantir que funcionem, caso precise imprimir algo na tela para "debugar", utilize o método dump() fornecido pela classe AbstractTestCase:

public function testIfOneIsOne(): void
{
    $list = ['Mar', 'Minino'];
    
    $this->dump($list); // equivalente ao print_r
    
    $this->assertEquals(
        'MarMinino',
        implode('', $list)
    );
}

Para executar os testes veja a seção Console Commands


DI (Injeção de dependência)

Com a injeção de dependência diminuímos o acoplamento das nossas classes. E a razão para isso ser tão importante está no princípio da inversão de dependência em que o código deve depender de abstrações e não de implementações concretas.

Documentação PHP-DI: https://php-di.org

Todo o código se encontra no diretório /app/config, no arquivo di.php.

Console Commands

CACHE CLEAR

Limpar cache

Para executar o comando de limpar cache basta entrar no container da aplicação e executar o seguinte comando:

php app/bin/console cache:clear
COMMAND SQL

Executar código SQL

Para executar um comando SQL basta entrar no container da aplicação e executar o seguinte comando:

php app/bin/console database:sql {sql}

O argumento chamado de sql é requerido e é o comando a ser executar no banco de dados.

TESTS

Testes Automatizados

Para executar os testes, entre no container da aplicação e execute o seguinte comando:

php app/bin/console tests:backend {path}

O path é opcional, o padrão é "app/tests"

STYLE CODE

Style Code

Para executar o PHP-CS-FIXER basta entrar no container da aplicação e executar

php app/bin/console app:code-style
DATA FIXTURES

Fixtures

📝 Fixtures são dados falsos com a finalidade de testes.

Configuração do ambiente

Antes de executar os fixtures, é necessário criar um arquivo .env dentro da pasta app (/app/.env). Este arquivo deve conter a configuração de ambiente necessária. Um arquivo de exemplo chamado .env.example foi fornecido para facilitar esse processo.

  1. Copie o arquivo .env.example para .env:

    cp .env.example .env
  2. Abra o arquivo .env e configure as variáveis de ambiente. Para fins de desenvolvimento, você pode definir a variável APP_ENV como local:

    APP_ENV=local

Executando os Fixtures

Para executar o conjunto de fixtures basta entrar no container da aplicação e executar

php app/bin/console app:fixtures

Observação: Se o arquivo .env não for encontrado, você verá a seguinte mensagem de erro:

Please create a .env file in the root directory (/app/.env)
DEBUG ROUTES

Debug router

Para listas as routas basta entrar no container da aplicação e executar

php app/bin/console debug:router

Podemos usar as flags --show-actions e --show-controllers

DOCTRINE

Doctrine

Para listas todos os comandos disponiveis para gerenciamento do banco de dados através do doctrine basta entrar no container da aplicação e executar

php app/bin/doctrine