CODE GENERATOR – PHP – Criando formulários Automaticamente

Tempo de Leitura: 5 Minutos

Bom neste artigo, vamos abordar a programação de uma maneira diferente, vamos criar um código que produz código. Isso mesmo, muitas vezes vi em projetos onde trabalhei de todos os tamanhos o desenvolvimento de software sendo feito com a escolha de um framework não pelas funcionalidades do aplicativo, mais pelo simples fato dele produzir grande parte do código necessário de maneira automática. Então, vamos lá.

Que frameworks são uma mão na roda em projetos de médio porte, é sem sombra de dúvida uma verdade. Porém para grandes projetos muitas vezes eles consomem grandes quantidades de recursos de máquina e processamento que acabam tornando os custos de manutenção muito maiores que os próprios custos de desenvolvimento já que uma base mal projetada vai produzir um resultado mal feito para sempre. E alta disponibilidade não é o ponto forte da maioria dos frameworks de mercado, principalmente no quesito performance.

E projetos pequenos também acabam não sendo viáveis, pois estaríamos usando uma motosserra para fatiar um assado de natal, cortaria, porém a bagunça não justificaria o investimento, nem mesmo o uso por ela estar ali a mão. Em tecnologia essa analogia é bem válida, principalmente porque grande parte dos projetos que estão passando por reestruturação foram concebidos de maneira errada, o que acabou comprometendo seu ciclo de vida.

Quando você está se desenvolvendo um software as operações que mais tomam tempo, também são basicamente as mais repetitivas, mais de 20% do tempo de desenvolvimento economizado pelo uso de um framework vem da automatização dos processos de autenticação e validação de dados, e outros 40% desse tempo vem de rotinas CRUD (Cadastro, Leitura, Atualização, Exclusão) de registros em bases de dados, veja que aqui, a proposta não é criar um novo framework, e sim, criar código seguindo boas práticas de desenvolvimento que possa ser produzido de maneira rápida, e utilizado dentro de um projeto de pequeno a médio porte sem consumir recursos preciosos e sem onerar custos em todo o ciclo de vida do projeto.

A proposta desse trecho de código é criar a base por traz desses geradores, aqui foi feito um que lê a estrutura de uma dada tabela, e produz um FORM para permitir o CREATE, o READ e o UPDATE de dados, porém, ele pode ser expandido para permitir também o DELETE com mais algumas linhas de código. Outro método que pode basicamente ser também implementado é criar um LIST, e se tiver um bom comentário em uma etapa futura faça todo o método, criando não só a VIEW como o CONTROL dos dados.

header('Content-Type: text/plain; charset=utf-8');

  try {
    $dbhost=127.0.0.1;
    $dbname=artigos_2020;
    $dbuser=root;
    $dbpass=123456;
    $db = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
  } catch (PDOException $e) {
    die("ERRO! Banco de Dados: " . $e->getMessage(),503);
  }
$r=SqlQuery('SELECT COLUMN_NAME,DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMN_KEY, COLUMN_COMMENT,COLUMN_KEY
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME="'.$_GET['table'].'" ');
$fields = array();
echo '
<div class="d-flex flex-row">
  <div class="col mx-auto">
    <div class="table-responsive">
      <form method="POST" action="'.$_GET['table'].'/save/<?php echo($dados[\'nId\']);?>" id="id_form_'.$_GET['table'].'" name="form_'.$_GET['table'].'">
      <fieldset class="frm_field">
        <legend>'.$_GET['table'].'</legend>';
          while($f = $r->fetch(PDO::FETCH_ASSOC)) {
            if($f['DATA_TYPE']=='varchar' or $f['DATA_TYPE']=='char' or $f['DATA_TYPE']=='tinytext'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>
                <input type="text" class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="<?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?>" maxlength='.$f['CHARACTER_MAXIMUM_LENGTH'].'>
              </div>';
            } 
            if($f['DATA_TYPE']=='text' or $f['DATA_TYPE']=='mediumtext' or $f['DATA_TYPE']=='longtext'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>
                <textarea class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="" wrap="hard" cols=80><?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?></textarea>
              </div>';
            }
            if($f['DATA_TYPE']=='blob' or $f['DATA_TYPE']=='mediumblob' or $f['DATA_TYPE']=='longblob'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>BLOB
                <textarea class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="<?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?>" cols=200></textarea>
              </div>';
            }
            if($f['DATA_TYPE']=='tinyint' or $f['DATA_TYPE']=='smallint' or $f['DATA_TYPE']=='mediumint' or $f['DATA_TYPE']=='int' or $f['DATA_TYPE']=='bigint'){
              if($f['COLUMN_KEY']=='PRI'){
                echo '
                <TT class="hiden">Campo Oculto</TT>
                <input type="hidden" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="<?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?>">
                ';
              } else {
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>
                <input type="number" class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="<?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?>" maxlength='.$f['CHARACTER_MAXIMUM_LENGTH'].' step="1" min="0">
              </div>';
              }
            }
            if($f['DATA_TYPE']=='float' or $f['DATA_TYPE']=='double' or $f['DATA_TYPE']=='decimal'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>
                <input type="number" class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="<?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?>" maxlength='.$f['CHARACTER_MAXIMUM_LENGTH'].' step="0.01" min="0">
              </div>';
            }
            if($f['DATA_TYPE']=='date'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>
                <input type="date" class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="<?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?>" maxlength='.$f['CHARACTER_MAXIMUM_LENGTH'].' step="0.01" min="0">
              </div>';
            }
            if($f['DATA_TYPE']=='datetime'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>
                <input type="datetime-local" class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="<?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?>" maxlength='.$f['CHARACTER_MAXIMUM_LENGTH'].' step="0.01" min="0">
              </div>';
            }
            if($f['DATA_TYPE']=='timestamp'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>TIMESTAMP
                <input type="datetime-local" class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="<?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?>" maxlength='.$f['CHARACTER_MAXIMUM_LENGTH'].' step="0.01" min="0">
              </div>';
            }
            if($f['DATA_TYPE']=='time'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>BLOB
                <input type="time" class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" value="<?php echo($dados[\''.$f['COLUMN_NAME'].'\']);?>" maxlength='.$f['CHARACTER_MAXIMUM_LENGTH'].' step="0.01" min="0">
              </div>';
            }
            if($f['DATA_TYPE']=='boolean'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>
                <select class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'" >
                <option value=0>Falso</option>
                <option value=1>Verdadeiro</option>
                </select>
              </div>';
            }
            if($f['DATA_TYPE']=='enum' or $f['DATA_TYPE']=='set'){
              echo '
              <div class="form-group p-2">
                <label for="message-text" class="col-form-label">'.$f['COLUMN_COMMENT'].'</label>SET
                <select class="form-control" id="id_'.$f['COLUMN_NAME'].'" name="'.$f['COLUMN_NAME'].'">
                <?php
                foreach($dados[\''.$f['COLUMN_NAME'].'_opc\'] as $k=>$v){
                    if($dados[\''.$f['COLUMN_NAME'].'\']==$k){
                        ?>
                        <option value="<?php echo($k);?>" selected><?php echo($v);?></option>
                        <?
                    } else {
                        ?>
                        <option value="<?php echo($k);?>"><?php echo($v);?></option>
                        <?    
                    }
                }
                ?>
                </select>
              </div>';
            }
          } // ENDWHILE
        echo '
        <div class="form-group">
        <button class="btn btn-secondary" onclick="ClickCancel()" >Cancelar</Button>
          <button type="submit" class="btn btn-primary" onclick="spinner.show();">Salvar</button>
        </div>
      </fieldset>
      </form>
    </div>
  </div>
</div>';

function SqlQuery($sql, array $pr = null){
  global $db;
  $r=$db->prepare("$sql");
  if (!$r->execute($pr)){
      $error= $r->errorInfo();
      $erro="SQL ERRO:".$error[1].'-'.$error[2];;
      die("$erro");
  }  
  return $r;
}
?>

Deixei propositalmente a saída para a tela, para que você possa lêr a saída, porém, é facilmente adaptável para que a saída seja dada diretamente em um arquivo .php para testar, basta passar pelo método GET a variável table=table_name, o nosso código neste exemplo basicamente:

1 – Se conecta a nossa base de dados, no caso específico em uma base mysql ou mariadb porém com poucas adaptações é possível fazer em qualquer base de dados;
2 – Pega a lista de colunas e seus atributos para saber o tipo de campo ou de dados a ser usado.
3 – Faz um looping, nestas colunas e, conforme o tipo definido, ele insere um tipo de campo no formulário, já criando seus names e ids, e definindo as classes corretas em bootstrap conforme o tipo de dados.

Note, que você pode estender muito as funcionalidades desse script, e justamente isso que vamos continuar nos próximos artigos. Usar este tipo de código, ajuda muito no desenvolvimento de sistemas, e é interessante, para auxiliar na produção em equipe, mantendo uma coerência das classes usadas, e diminuindo a quantidade de código repetitivo a ser gerado.