Conn2Flow
Navegação das docs

SDD

req-049: Refatoração Dinâmica do Módulo Formulários (Forms) com CRUD de Campos e Integração ao html-editor

Este lote de trabalho (BATCH-049) define a reestruturação e modernização do módulo Formulários (gestor/modulos/forms) para torná-lo um componente dinâmico que utiliza o Editor…

Este lote de trabalho (BATCH-049) define a reestruturação e modernização do módulo Formulários (gestor/modulos/forms) para torná-lo um componente dinâmico que utiliza o Editor HTML/CSS/Tailwind (html_editor_componente), similar aos módulos de destaques e galerias. O editor manual de JSON via CodeMirror será substituído por painéis visuais estruturados para metadados e um CRUD visual para os campos do formulário.


1. Ações no Banco de Dados (Database Migration)

1.1 Criar Nova Migração Phinx

  • Nome Sugerido: gestor/db/migrations/20260622110000_add_html_and_css_to_forms_table.php (ou timestamp correspondente).

  • Ação: Criar a migração com a classe AddHtmlAndCssToFormsTable adicionando as colunas de layout/template na tabela forms.

  • Código de Exemplo:

    
    <?php

declare(strict_types=1);

use Phinx\Migration\AbstractMigration;

final class AddHtmlAndCssToFormsTable extends AbstractMigration { public function change(): void { $table = $this->table('forms'); $table->addColumn('html', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true]) ->addColumn('css', 'text', ['null' => true]) ->addColumn('css_compiled', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true]) ->addColumn('html_extra_head', 'text', ['limit' => Phinx\Db\Adapter\MysqlAdapter::TEXT_MEDIUM, 'null' => true]) ->update(); } }


---
## 2. Ações no Core do Gestor e html-editor
### 2.1 Modificar `gestor/bibliotecas/html-editor.php`
- Localizar a função `html_editor_ajax_widgets_list()`.
- Adicionar `'forms' => 'forms'` no array `$mapa`, permitindo que os formulários criados apareçam no popup de inserção de widgets no visual editor:
```diff
    $mapa = [
        'menus'                => 'menus',
        'galleries'            => 'galleries',
        'publisher_highlights' => 'publisher-highlights',
        'publisher_index'      => 'publisher-index',
+       'forms'                => 'forms',
    ];

2.2 Modificar gestor/assets/interface/html-editor-interface.js

  • Adicionar 'forms': true na constante WIDGET_SCRIPT_MODULES (próximo à linha 1538).

  • Adicionar 'forms' à função alvoUsaItemVars() para que o parser detecte o uso de placeholders de repetição no formato [[item#X]]:

    function alvoUsaItemVars() {
        var a = alvoAtual();
        return a === 'publisher-highlights' || a === 'menus' || a === 'galleries' || a === 'publisher-index' || a === 'forms';
    }
  • Adicionar 'forms': 'adminPaginasBackupCampo' ao objeto backupCallbackMap (próximo à linha 758).

2.3 Modificar gestor/assets/interface/html-editor-modules.js

  • Modificar a função publisherVariablesOrSimulation() para suportar a simulação visual do formulário. Quando o alvo for forms, deve simular a renderização repetindo a tag de loop <!-- item < --> ... <!-- item > --> baseada nos campos criados no CRUD do painel administrativo.

  • Exemplo de lógica de simulação para formulários:

    if (alvo === 'forms') {
        const simulacao = $('.publisherVariablesOrSimulation[data-id="simulation"]').hasClass('active');
        if (simulacao) {
            const schemaStr = $('input[name="fields_schema"]').val() || '{}';
            let schema = {};
            try { schema = JSON.parse(schemaStr); } catch (e) { }
            const fields = schema.fields || [];
            const itemRegex = /<!--\s*item\s*<\s*-->([\s\S]*?)<!--\s*item\s*>\s*-->/i;
            const itemMatch = html.match(itemRegex);
            if (itemMatch && fields.length > 0) {
                const itemTemplate = itemMatch[1];
                let replicated = '';
                fields.forEach(field => {
                    let fieldHtml = itemTemplate;
                    fieldHtml = fieldHtml.replace(/\[\[item#label\]\]/g, field.label || '');
                    fieldHtml = fieldHtml.replace(/\[\[item#name\]\]/g, field.name || '');
                    fieldHtml = fieldHtml.replace(/\[\[item#placeholder\]\]/g, field.placeholder || '');
                    fieldHtml = fieldHtml.replace(/\[\[item#type\]\]/g, field.type || 'text');
                    fieldHtml = fieldHtml.replace(/\[\[item#required\]\]/g, field.required ? 'required' : '');
                    // Tratar condicionais de bloco baseadas no tipo de campo
                    if (field.type === 'select') {
                        fieldHtml = fieldHtml.replace(/<!--\s*type-select\s*<\s*-->([\s\S]*?)<!--\s*type-select\s*>\s*-->/gi, '$1');
                        fieldHtml = fieldHtml.replace(/<!--\s*type-textarea\s*<\s*-->([\s\S]*?)<!--\s*type-textarea\s*>\s*-->/gi, '');
                        fieldHtml = fieldHtml.replace(/<!--\s*type-input\s*<\s*-->([\s\S]*?)<!--\s*type-input\s*>\s*-->/gi, '');
                    } else if (field.type === 'textarea') {
                        fieldHtml = fieldHtml.replace(/<!--\s*type-textarea\s*<\s*-->([\s\S]*?)<!--\s*type-textarea\s*>\s*-->/gi, '$1');
                        fieldHtml = fieldHtml.replace(/<!--\s*type-select\s*<\s*-->([\s\S]*?)<!--\s*type-select\s*>\s*-->/gi, '');
                        fieldHtml = fieldHtml.replace(/<!--\s*type-input\s*<\s*-->([\s\S]*?)<!--\s*type-input\s*>\s*-->/gi, '');
                    } else {
                        fieldHtml = fieldHtml.replace(/<!--\s*type-input\s*<\s*-->([\s\S]*?)<!--\s*type-input\s*>\s*-->/gi, '$1');
                        fieldHtml = fieldHtml.replace(/<!--\s*type-select\s*<\s*-->([\s\S]*?)<!--\s*type-select\s*>\s*-->/gi, '');
                        fieldHtml = fieldHtml.replace(/<!--\s*type-textarea\s*<\s*-->([\s\S]*?)<!--\s*type-textarea\s*>\s*-->/gi, '');
                    }
                    replicated += fieldHtml;
                });
                html = html.replace(itemRegex, replicated);
            }
        }
        return html;
    }

3. Ações no Módulo Formulários (Admin Control)

3.1 Modificar gestor/modulos/forms/forms.php

  • Incluir suporte ao html_editor_componente na tela de edição e adição de registros.

  • Ler/Gravar os novos campos de banco html, css, css_compiled e html_extra_head.

  • Incluir a função forms_template_options() para listar os templates com target = 'forms'.

  • Tratar e salvar as configurações estruturadas recebidas via AJAX ou POST do CRUD de campos e metadados no fields_schema.

  • Adicionar o método AJAX forms_ajax_template_load() para carregar dados de template base quando o usuário selecionar no dropdown.

3.2 Modificar gestor/modulos/forms/forms.js

  • Remover as inicializações antigas do CodeMirror JSON.

  • Criar a interface de manipulação do CRUD de campos utilizando Semantic UI / Fomantic UI (inserção de novas linhas, seleção de tipos, botão remover e ordenação drag/drop).

  • Implementar listeners em todas as abas de metadados do formulário (E-mail, redirects, limites).

  • Adicionar lógica no evento submit para estruturar estes dados em um JSON serializado (com a chave fields para os campos do CRUD e demais metadados nas chaves correspondentes) e preencher o input oculto fields_schema antes da gravação final.

3.3 Modificar Templates de Tela

  • Arquivos: gestor/modulos/forms/resources/pt-br/pages/forms-editar/forms-editar.html e forms-adicionar/forms-adicionar.html (e suas versões em inglês /en/).

  • Ação: Implementar abas Semantic UI (menuForms) separando a edição:

    1. Configuração Geral & Acesso: Ação, limites, reCAPTCHA.

    2. Notificação por E-mail: Destinatários, assunto, template.

    3. Páginas de Redirecionamento: Caminhos de sucesso e erro.

    4. Campos do Formulário: Interface visual da tabela com o CRUD de campos.

    5. Template & Editor HTML: Dropdown de template, iframe de pré-visualização, #html-editor# e a aba para visualização e cópia do código do Widget.


4. Criar Renderizador de Widget Público (Frontend Widget)

4.1 Criar Arquivo gestor/modulos/forms/forms.widget.php

  • Responsabilidade: Renderizar o HTML dinâmico do formulário no site publicado em tempo de execução.

  • Funções:

    • forms_render($params): Executa query para buscar o formulário ativo baseado no ID. Inclui o script controlador público forms.widget.js via gestor_pagina_javascript_incluir(). Chama a função inline.

    • forms_widget_render_inline($params): Executa o loop <!-- item < --> ... <!-- item > --> para cada campo do formulário, processando condicionais de exibição baseadas no tipo de campo (select, textarea, etc.) e placeholders ([[item#label]], [[item#name]]). Injeta tags especiais como CAPTCHA ou token anti-spam conforme metadados.

4.2 Criar Arquivo gestor/modulos/forms/forms.widget.js

  • Responsabilidade: Scripts frontend do widget público.

  • Ações:

    • Inicializar validação básica de campos obrigatórios no formulário.

    • Interceptar submissão do formulário.

    • Gerar token reCAPTCHA v3/v2 de forma dinâmica se o formulário requerer.

    • Disparar envio via AJAX com animação de loading no botão submit.

    • Manipular redirecionamentos de sucesso/erro retornados na resposta do servidor.


5. Ações de Configuração e IA

5.1 Atualizar gestor/db/data/AlvosIaData.json

  • Adicionar o alvo 'forms' no mapeamento de alvos suportados pela IA.

5.2 Atualizar gestor/db/data/ModosIaData.json

  • Adicionar prompts específicos do Modo de IA para Formulários (forms), definindo as tags de repetição de itens e placeholders utilizáveis pelo modelo de linguagem.


6. Verificação do Funcionamento (Tests & Check)

6.1 Executar Migrações do Banco

  • Executar Phinx localmente para aplicar as modificações na tabela forms.

6.2 Testes Automatizados

  • Executar composer test e verificar se todas as suítes passam normalmente.

O Futuro é Híbrido: Humano + IA.

O Conn2Flow é a ferramenta. Se você precisa do Arquiteto para desenhar a estratégia da sua empresa usando essa tecnologia...

Contrate Consultoria Especializada