Introdução

O intuito deste primeiro primeiro capítulo é preparar o desenvolvedor para a jornada que se inicia.

Considera-se como requisitos, que o desenvolvedor possua conhecimento ao menos intermediário de PHP, de orientação a objetos e de Git e SQL (PostgresSQL).

O desenvolvedor deve possuir o docker e o docker-compose funcionando em seu computador, de preferência em ambiente Linux ou MacOS.

Tecnologias Envolvidas

No backend, o Mapas Culturais é desenvolvido em PHP utilizando o Slim v2 como microframework e o Doctrine como ORM, entre outras bibliotecas como o Respect\Validation.

No frontend, são utilizados o AngularJS, X-editable e leaflet, entre outras bibliotecas.

Entidades Principais, Auxiliares e Diagrama de Relacionamento de Entidade

A plataforma inteira é desenvolvida em torno de seis entidades principais, a saber:

Cada uma das entidades principais conta com uma entidade auxiliar para salvamento de metadados (AgentMeta, SpaceMeta, EventMeta, ProjectMeta, OpportunityMeta e RegistrationMeta).

E, também, conta com as entidades secundárias, que auxiliam no desenvolvimento das funcionalidades, como as mais importantes, listadas abaixo:

Diagrama de Relacionamento de Entidade

Subindo Ambiente de Desenvolvimento

Após clonar o repositório do Mapas Culturais, entre, pela linha de comando na pasta dev-scripts, e execute o script start-dev.sh.

Este script utiliza o Docker Compose para iniciar o ambiente utilizando o Dockerfile de desenvolvimento, que é baseado no php7.2-cli e se utiliza do built-in web server do PHP. Assim, possibilitando a utilização do PsySH no desenvolvimento.

dev-scripts]$ ./start-dev.sh
Creating dev-scripts_mapas_run ... done

aguardando o banco de dados subir corretamente...
conectado com sucesso ao banco pgsql:host=db;port=5432;dbname=mapas;user=mapas;

.
.
.
.

PHP 7.2.34 Development Server started at Wed Aug 25 00:30:56 2021
Listening on http://0.0.0.0:80
Document root is /var/www/html

Após a inicialização, a aplicação constará rodando e ouvindo a porta 80 de seu computador. Acesse http://localhost/ em seu navegador.

Script shell.sh e breakpoint com eval(\psy\sh())

E, também, na pasta dev-scripts, há o script shell.sh que inicializa um console para debug interativo da aplicação, contendo algumas funções auxiliares para facilitar o debug da aplicação, como a função login. Para executar este script é necessário que a aplicação já esteja rodando com o script start-dev.sh.

dev-scripts]$ ./shell.sh

================================
VARIÁVEIS DISPONÍVEIS: 
  $app, $em
  
para logar: login(id do usuário);

para criar uma ApiQuery: api($entity, $params); (exemplo: api('agent', ['@select' => 'id,name']))

para adicionar uma role a um usuário: role::add($user_id, 'roleName', $subsite_id = null); (exemplo role::add(1, 'saasSuperAdmin'))
para remover uma role a um usuário: role::remove($user_id, 'roleName', $subsite_id = null); (exemplo role::remove(1, 'saasSuperAdmin'))


Psy Shell v0.10.7 (PHP 7.2.34 — cli) by Justin Hileman
New version is available (current: v0.10.7, latest: v0.10.8)
From protected/tools/psysh.php:169:
    167: ";
    168: 
  > 169: eval(\psy\sh());
>>>

É possível definir breakpoints em qualquer ponto do código, pausando a execução e abrindo o console de debug na linha de comando. Basta adicionar o código eval(\psy\sh()); no ponto desejado do código.

No exemplo abaixo, o código foi colocado na linha 32 do Site Controller:

=========================================================================
(GET) / - timestamp: 2021-08-25 04:00:46.738476
Psy Shell v0.10.7 (PHP 7.2.34 — cli-server) by Justin Hileman
From protected/application/lib/MapasCulturais/Controllers/Site.php:32:
    30:      */
    31:     function GET_index(){
  > 32:         eval(\psy\sh());
    33:         $this->render('index');
    34:     }
>>> 

Para sair do console e continuar a execução do script, utilize o comando exit ou pressione Ctrl+d.

Recomenda-se ler a documentação do PsySH, especialmente a parte que descreve os comandos. Abaixo, alguns comandos úteis:

  • ls e ls -l: Lista as variáveis acessíveis no escopo;

  • trace: Exibe o stack até o ponto do código;

  • doc {target}: Exibe a documentação do {target}, onde {target} pode ser uma função, classe ou objeto;

  • help ou ?: Exibe a lista dos comandos disponíveis.

Pode-se inspecionar uma variável digitando o nome dela, por exemplo, o $app->plugins, um array com as instâncias dos plugins ativos no ambiente:

>>> $app->plugins
=> [
     "EvaluationMethodTechnical" => EvaluationMethodTechnical\Plugin {#248},
     "EvaluationMethodSimple" => EvaluationMethodSimple\Plugin {#250},
     "EvaluationMethodDocumentary" => EvaluationMethodDocumentary\Plugin {#252},
     "MultipleLocalAuth" => MultipleLocalAuth\Plugin {#257},
     "AldirBlanc" => AldirBlanc\Plugin {#265},
     "AldirBlancDataprev" => AldirBlancDataprev\Plugin {#267},
   ]

Ciclo de Vida da Aplicação

Todas as requisições se iniciam no arquivo src/index.php, arquivo responsável por fazer o Bootstrap da aplicação.

O Bootstrap define uma série de constantes, inicializa o autoloader de classes, lê o arquivo de configuração, instancia e inicializa o objeto da aplicação e executa aplicação.

Durante a inicialização da aplicação são executadas as seguintes operações, nesta ordem:

  1. Inicialização da sessão;

  2. Inicialização dos caches da aplicação;

  3. Registro do autoloader de classes de plugins e temas;

  4. Inicialização do Doctrine;

  5. Instanciação do tema;

  6. Instanciação do Slim;

  7. Inicialização dos plugins;

  8. Inicialização dos módulos;

  9. Inicialização do logger;

  10. Inicialização do storage driver;

  11. Inclusão dos middlewares;

  12. Inicialização do gerenciador de rotas;

  13. Registro de:

    • Metadados e tipos de entidade;

    • Controladores;

    • Roles;

    • Grupos de arquivos;

    • Tamanhos de imagens;

    • Grupos de metalist;

    • Taxonomias;

    • Execução dos registros dos módulos e plugins.

  14. Inicialização do autenticador;

  15. Inicialização do tema.

Após a inicialização, a requisição é encaminhada para o gerenciador de rotas que decidirá para qual controller e action a requisição seguirá.

Uma vez no controlador, este poderá renderizar uma visão utilizando o método $this->render('template-name');; poderá retornar um JSON utilizando o método $this->json(['data' => 'value']);; um JSON de erro utilizando o método $this->errorJson(['errorData' => 'value'], 400);; um 404 utilizando $app->pass(); uma permissão negada utilizando throw new \MapasCulturais\Exceptions\PermissionDenied; etc.

Visão Geral dos Hooks

Hooking (enganchar em inglês) é a forma que o Mapas Culturais oferece ao desenvolvedor para que ele possa alterar ou estender o comportamento padrão da aplicação, sem que para isso, ele precise modificar seu código.

Há hooks espalhados por toda a aplicação e estes estão divididos basicamente em dois grandes grupos: os hooks de template (template hooks), que como o nome diz são definidos nos arquivos de template dos temas, plugins ou módulos, e os hooks da aplicação, que são definidos no core da aplicação.

Template Hooks

Os template hooks são definidos chamando o método applyTemplateHook do tema, que recebe dois parâmetros para nomear o hook, $name e $sufix, além dos argumentos que serão passados para o callback enganchado. Os hooks definidos por este método receberão o nome template(controllerId.actionName.nome-do-hook):sufix. Costuma-se utilizar quatro sufixos para cada nome de hook: before, begin, end e after, como no exemplo abaixo, possibilitando que sejam incluídos código antes, no início, no fim ou depois da div:

<?php $this->applyTemplateHook('minha-div', 'before') ?>
<div id='minha-div'>
   <?php $this->applyTemplateHook('minha-div', 'begin') ?>
   <!-- aqui vai o conteúdo da div -->
   <?php $this->applyTemplateHook('minha-div', 'end') ?>
</div>
<?php $this->applyTemplateHook('minha-div', 'after') ?>

Hooks da Aplicação

Os hooks da aplicação são os que estão espalhados nas classes do core do Mapas Culturais. Estes são definidos utilizando os métodos applyHook ou applyHookBoundTo da aplicação (classe MapasCulturais\App).

Habilitando logs de hook

Para habilitar o log dos hooks chamados na requisição, utilize a chave de configuração app.log.hook da seguinte maneira:

  • true: Para habilitar o log de todos os hooks;

  • 'agent': Habilita o log de todos os hooks que tenham a palavra agent;

  • '(agent|space).save': Habilita log para os hooks que contenham agent.save ou space.save. a configuração aceita expressões regulares e é case sensitive.

Utilizando os hooks

Costuma-se utilizar os hooks no método _init do tema, módulo ou plugin para adicionar um texto no início da div#minha-div na home da aplicação (controller Site, action GET_index), como no exemplo abaixo:

$app->hook('template(site.index.minha-div):begin', function () {
   echo '<p> Texto inserido no início da div </p>';
});

MagicGetter e MagicSetter

O Mapas Culturais implementa em dois traits os métodos mágicos __get e __set, da maneira exemplificada abaixo:

class MinhaClasse {
   use MagicGetter, MagicSetter;

   protected $_nome;

   function getNome() {
      return $this->_nome;
   }

   function setNome($val) {
      $this->_nome = strtoupper($val);
   }
}

$obj = new MinhaClasse;
$obj->nome = 'teste';

echo $obj->nome; // imprimirá 'TESTE';

Last updated