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
Para instalar as dependências e atualizar o autoload, entre no container da aplicação e execute:
composer.phar install
Os Controllers
em conjunto com as Routes
permitem criar endpoints para diversas finalidades.
Como criar um novo controller
Crie uma nova classe em /app/Controller/Api/
, por exemplo, EventApiController.php
:
<?php
declare(strict_types=1);
namespace App\Controller\Api;
class EventApiController
{
}
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);
}
}
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.
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"
}
]
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
Crie uma nova classe em /app/DTO/
, por exemplo, SealDTO.php
:
<?php
declare(strict_types=1);
namespace App\DTO;
final class SealDTO
{
...
}
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;
[...]
}
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
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:
<?php
declare(strict_types=1);
namespace App\Repository;
class MyRepository extends AbstractRepository
{
}
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 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
<?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
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
<?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;
}
}
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!
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 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
<?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();
}
}
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
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
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
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
.
CACHE CLEAR
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
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
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
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 são dados falsos com a finalidade de testes.
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.
-
Copie o arquivo
.env.example
para.env
:cp .env.example .env
-
Abra o arquivo
.env
e configure as variáveis de ambiente. Para fins de desenvolvimento, você pode definir a variávelAPP_ENV
comolocal
:APP_ENV=local
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
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