Mini tutorial mod_harbour
Moderador: Moderadores
Mini tutorial mod_harbour
Pessoal, estou estudando mod_harbour e vou postar algumas observações que fiz aqui.
Pré-requisitos :
* Baixar e instalar o mod_harbour no xampp windows
* Um pouco de HTML (CSS Bootstrap é recomendável, mas zipei todos os exemplos, de modo que dá pra entender)
O Itamar postou um material aqui tb https://pctoledo.org/forum/viewto ... =5&t=24242
O site mod_harbour tem um wiki : https://github.com/FiveTechSoft/mod_harbour/wiki
O tutorial é bem básico, para quem não está familiarizado com linguagens web.
Pré-requisitos :
* Baixar e instalar o mod_harbour no xampp windows
* Um pouco de HTML (CSS Bootstrap é recomendável, mas zipei todos os exemplos, de modo que dá pra entender)
O Itamar postou um material aqui tb https://pctoledo.org/forum/viewto ... =5&t=24242
O site mod_harbour tem um wiki : https://github.com/FiveTechSoft/mod_harbour/wiki
O tutorial é bem básico, para quem não está familiarizado com linguagens web.
Mini tutorial mod_harbour
O objetivo desse tutorial é ensinar a construir
um grid simples usando :
(1) HTML5
(2) CSS (Bootstrap)
(3) ADO (MSAccess)
Pré-requisitos:
(1) Conhecimentos básicos (bem básicos) de HTML5
(2) mod-harbour instalado em um servidor local (usei o xampp)
(2.1) Para instalar o mod-harbour no windows acesse as instruções no link oficial :
https://github.com/FiveTechSoft/mod_har ... dows-Xampp
Em anexo um zip com o nosso ponto de partida. Ele tem uma página HTML simples com a biblioteca bootstrap.
PS: A ideia inicial era criar com exemplos em SQLMIX + SQLite, mas não foi incluída na compilação.
um grid simples usando :
(1) HTML5
(2) CSS (Bootstrap)
(3) ADO (MSAccess)
Pré-requisitos:
(1) Conhecimentos básicos (bem básicos) de HTML5
(2) mod-harbour instalado em um servidor local (usei o xampp)
(2.1) Para instalar o mod-harbour no windows acesse as instruções no link oficial :
https://github.com/FiveTechSoft/mod_har ... dows-Xampp
Em anexo um zip com o nosso ponto de partida. Ele tem uma página HTML simples com a biblioteca bootstrap.
PS: A ideia inicial era criar com exemplos em SQLMIX + SQLite, mas não foi incluída na compilação.
Mini tutorial mod_harbour
O objetivo dessa etapa é colocar o código HTML do passo anterior
em um arquivo prg. Só isso.
Apenas coloquei o conteúdo do HTML dentro do comando TEMPLATE ... ENDTEXT
em um arquivo prg. Só isso.
Apenas coloquei o conteúdo do HTML dentro do comando TEMPLATE ... ENDTEXT
Código: Selecionar todos
function main
TEMPLATE // <-------------------------
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="Vlademiro">
<title>Sistema </title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<main role="main" class="container">
<h1>Tutorial de Mod-Harbour + Grid</h1>
<p class="lead">Ponto de partida</p>
</main><!-- /.container -->
</body>
</html>
ENDTEXT // <----------------------------------
return nil
Mini tutorial mod_harbour
O objetivo dessa etapa é enviar argumentos para o seu HTML
Como passar argumentos para o TEMPLATE ?
Use PARAMS :
Para exibir esses comandos faça assim :
Não adianta fazer como nos scripts PHP ou ASP. O exemplo abaixo não vai funcionar.
Como passar argumentos para o TEMPLATE ?
Use PARAMS :
Código: Selecionar todos
function main
local cMsg := "Mensagem para o usuário"
local cMsg2 := "Mensagem para o usuário (modelo 2)"
TEMPLATE PARAMS cMsg, cMsg2
<!doctype html>
<html lang="en">
Código: Selecionar todos
<?prg return cMsg?>
Código: Selecionar todos
<div class="alert alert-warning" role="alert"><?prg Qout( cMsg ) ?></div>
<div class="alert alert-primary" role="alert"><?prg ?? cMsg2 ?></div>
Mini tutorial mod_harbour
Exemplo de erro!!
Essa etapa mostra uma diferenças básicas entre o mod_harbour e os scripts php ou asp.
O código abaixo vai gerar um erro.
Erro gerado :
Ou seja, não "quebre" um IF.
E nem qualquer outra estrutura.
Todo trecho entre <?prg ... ?> funcionam como uma função anônima.
Blocos de código extendidos, creio eu.
Ex:
<?prg local a := 10
return a*a ?>
**
Essa etapa mostra uma diferenças básicas entre o mod_harbour e os scripts php ou asp.
O código abaixo vai gerar um erro.
Código: Selecionar todos
<?prg if nFlag == 1 ?>
<div class="alert alert-warning" role="alert"><?prg return cMsg?></div>
<?prg else ?>
<div class="alert alert-primary" role="alert"><?prg return cMsg2?></div>
<?prg end ?>
Código: Selecionar todos
Error: Unclosed control structure 'IF*'
operation: line:3
called from: HB_COMPILEFROMBUF, line: 0
called from: ..\source\exec.prg, EXECUTE, line: 60
called from: ..\source\exec.prg, EXECINLINE, line: 115
called from: ..\source\exec.prg, INLINEPRG, line: 95
called from: pcode.hrb, MAIN, line: 43
called from: HB_HRBDO, line: 0
called from: ..\source\exec.prg, EXECUTE, line: 62
E nem qualquer outra estrutura.
Todo trecho entre <?prg ... ?> funcionam como uma função anônima.
Blocos de código extendidos, creio eu.
Ex:
<?prg local a := 10
return a*a ?>
**
Mini tutorial mod_harbour
O objetivo dessa etapa é abrir um arquivo.
Se vc nunca trabalhou com CGI ou extensões do apache (mod_perl, por exemplo)
vc deve achar essa etapa esquisita. Mas esse é um problema comum nesses ambientes.
Quando vc "está" no diretório C:\myapp e deseja abrir um arquivo em C:\myapp\data
Basta referenciar ele do ponto onde você está (path relativo)
USE ( "data\meuarquivo.dbf" ) por exemplo
Mas no nosso caso será necessário especificar o caminho completo.
USE ( "c:\myapp\data\meuarquivo.dbf" )
*
O mod_harbour facilita para você através da função PathBase(), ela retorna o caminho até o local onde o script está.
Note que vc pode passar parâmetros para a PathBase(), assim :
PathBase( "/data" ) --> Caminho até o script + "/data"
As barras de separação são assim mesmo, no padrão *Nix.
*
Nota para usuários *Nix
O Apache2 cria o usuário www-data no grupo www-data.
O arquivo que vc vai abrir precisa ser visível para esse usuário.
chown -R www-data.www-data <pasta dos meus dbfs ou textos>
Se vc nunca trabalhou com CGI ou extensões do apache (mod_perl, por exemplo)
vc deve achar essa etapa esquisita. Mas esse é um problema comum nesses ambientes.
Quando vc "está" no diretório C:\myapp e deseja abrir um arquivo em C:\myapp\data
Basta referenciar ele do ponto onde você está (path relativo)
USE ( "data\meuarquivo.dbf" ) por exemplo
Mas no nosso caso será necessário especificar o caminho completo.
USE ( "c:\myapp\data\meuarquivo.dbf" )
*
O mod_harbour facilita para você através da função PathBase(), ela retorna o caminho até o local onde o script está.
Note que vc pode passar parâmetros para a PathBase(), assim :
PathBase( "/data" ) --> Caminho até o script + "/data"
As barras de separação são assim mesmo, no padrão *Nix.
Código: Selecionar todos
function main
local cArq := PathBase("/data") + "/clientes.dbf"
?? "Abrindo em : " , cArq
USE ( cArq ) SHARED // Use shared por causa do ambiente compartilhado
DO WHILE .NOT. EOF()
? field->nome
skip
ENDDO
return nil
Nota para usuários *Nix
O Apache2 cria o usuário www-data no grupo www-data.
O arquivo que vc vai abrir precisa ser visível para esse usuário.
chown -R www-data.www-data <pasta dos meus dbfs ou textos>
Mini tutorial mod_harbour
O objetivo dessa etapa é criar uma conexão via ADO/ODBC com um banco de dados MSAccess
Caso você esteja usando um windows 7 e não tiver instalado o cliente para MsAccess (64bits),
o exemplo não vai funcionar.
Isso porque esse harbour, distribuido junto com a mod-harbour é um harbour
compilado para arquiteturas 64 bits e o seu ODBC também será o de 64bits.
A Microsoft disponibiliza dois ODBCs, um para cada arquitetura.
No meu caso, o meu windows é o 7 (64bits)
O ODBC 64 bits está em painel de controle, etc.
%systemdrive%\Windows\System32\odbcad32
O ODBC 32 está em %systemdrive%\Windows\SysWoW64\odbcad32 <-- Usado pelo harbour 32 bits (não é esse o caso)
É estranho. Deveria ser odbcad32 e odbcad64, mas não é.
Caso não tenha o cliente ODBC instalado vc deve baixar ele de :
https://www.microsoft.com/en-us/downloa ... x?id=54920
Se não tiver os exemplos não vão funcionar.
**
Essa versão do mod-harbour compilada pode acessar DBF, ADO (todos os bancos, via ODBC) e SQLite.
As demais versões de acesso nativo aos bancos não estão inclusas.
Para vc ter isso (PostgreSQL nativo, MySQL nativo, Firebird nativo, Oracle nativo) você precisa compilar o seu
próprio mod_harbour com um harbour que tenha esses acessos devidamente configurados.
**
Caso você esteja usando um windows 7 e não tiver instalado o cliente para MsAccess (64bits),
o exemplo não vai funcionar.
Isso porque esse harbour, distribuido junto com a mod-harbour é um harbour
compilado para arquiteturas 64 bits e o seu ODBC também será o de 64bits.
A Microsoft disponibiliza dois ODBCs, um para cada arquitetura.
No meu caso, o meu windows é o 7 (64bits)
O ODBC 64 bits está em painel de controle, etc.
%systemdrive%\Windows\System32\odbcad32
O ODBC 32 está em %systemdrive%\Windows\SysWoW64\odbcad32 <-- Usado pelo harbour 32 bits (não é esse o caso)
É estranho. Deveria ser odbcad32 e odbcad64, mas não é.
Caso não tenha o cliente ODBC instalado vc deve baixar ele de :
https://www.microsoft.com/en-us/downloa ... x?id=54920
Se não tiver os exemplos não vão funcionar.
**
Essa versão do mod-harbour compilada pode acessar DBF, ADO (todos os bancos, via ODBC) e SQLite.
As demais versões de acesso nativo aos bancos não estão inclusas.
Para vc ter isso (PostgreSQL nativo, MySQL nativo, Firebird nativo, Oracle nativo) você precisa compilar o seu
próprio mod_harbour com um harbour que tenha esses acessos devidamente configurados.
**
Código: Selecionar todos
#define adOpenForwardOnly 0
#define adOpenKeyset 1
#define adOpenDynamic 2
#define adOpenStatic 3
#define adLockReadOnly 1
#define adLockPessimistic 2
#define adLockOptimistic 3
#define adLockBatchOptimistic 4
#define adUseNone 1
#define adUseServer 2
#define adUseClient 3
#define adStateClose 0
function main
LOCAL oRs , oCn, cSql
LOCAL cString := "Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=" + PathBase() + "/scott.mdb"
LOCAL i
for i = 0 to 25
?? hb_Version( i )
endfor
oCn := win_oleCreateObject( "ADODB.Connection" )
oCn:ConnectionString := cString
oCn:Open()
oRs := win_oleCreateObject( "ADODB.Recordset" )
oRs:CursorLocation = adUseClient
oRs:Open( "SELECT * FROM emp", oCn , adOpenDynamic, adLockOptimistic )
if oCn:State = adStateClose
? ('Failed open table EMP')
Return
Endif
if oRs:recordcount > 0
oRs:Movefirst()
do while !oRs:eof()
? oRs:fields("ename"):value
oRs:movenext()
enddo
oRs:Movefirst() // Opcional, retorna para o primeiro registro
endif
return nil
Mini tutorial mod_harbour
O objetivo dessa etapa é criar um grid em bootstrap e colocar os dados da tabela
no grid
Confesso que fiquei um pouco decepcionado. Eu imaginava um grid no estilo PHP/ASP,
do tipo que fica o código HTML e o da linguagem "convivendo" sem ter que ficar "printando"
comandos HTML com o código PHP ou ASP, mas como as minhas expectativas foram frustradas na etapa 3
(exemplo do if/endif) a unica solução (até que não ficou ruim) foi criar uma função FData() para retornar
os dados e evitar ao máximo ficar "printando" códigos htmls. Mas é o que tem para hoje.
Dá pra fazer muita coisa com o mod_harbour. É se adaptar e ir criando as soluções com o que está disponível.
Para quem não entendeu o que eu quis dizer, veja um exemplo em PHP :
O nosso código ficou assim :
Nada mal.
no grid
Confesso que fiquei um pouco decepcionado. Eu imaginava um grid no estilo PHP/ASP,
do tipo que fica o código HTML e o da linguagem "convivendo" sem ter que ficar "printando"
comandos HTML com o código PHP ou ASP, mas como as minhas expectativas foram frustradas na etapa 3
(exemplo do if/endif) a unica solução (até que não ficou ruim) foi criar uma função FData() para retornar
os dados e evitar ao máximo ficar "printando" códigos htmls. Mas é o que tem para hoje.
Dá pra fazer muita coisa com o mod_harbour. É se adaptar e ir criando as soluções com o que está disponível.
Para quem não entendeu o que eu quis dizer, veja um exemplo em PHP :
Código: Selecionar todos
<body>
<table border="1">
<tr>
<td>Código</td>
<td>Nome</td>
<td>E-mail</td>
<td>Data de Cadastro</td>
<td>Ação</td>
</tr>
<?php while($dado = $con->fetch_array()) { ?>
<tr>
<td><?php echo $dado['usu_codigo']; ?></td>
<td><?php echo $dado['usu_nome']; ?></td>
<td><?php echo $dado['usu_email']; ?></td>
<td><?php echo date('d/m/Y', strtotime($dado['usu_datadecadastro'])); ?></td>
<td>
<a href="usu_editar.php?codigo=<?php echo $dado['usu_codigo']; ?>">Editar</a>
<a href="usu_excluir.php?codigo=<?php echo $dado['usu_codigo']; ?>">Excluir</a>
</td>
</tr>
<?php } ?>
</table>
Código: Selecionar todos
#define adOpenForwardOnly 0
#define adOpenKeyset 1
#define adOpenDynamic 2
#define adOpenStatic 3
#define adLockReadOnly 1
#define adLockPessimistic 2
#define adLockOptimistic 3
#define adLockBatchOptimistic 4
#define adUseNone 1
#define adUseServer 2
#define adUseClient 3
#define adStateClose 0
function main
LOCAL oRs , oCn, cSql
LOCAL cString := "Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=" + PathBase() + "/scott.mdb"
oCn := win_oleCreateObject( "ADODB.Connection" )
oCn:ConnectionString := cString
oCn:Open()
oRs := win_oleCreateObject( "ADODB.Recordset" )
oRs:CursorLocation = adUseClient
oRs:Open( "SELECT * FROM emp", oCn , adOpenDynamic, adLockOptimistic )
if oCn:State = adStateClose
? "<script>alert('Failed open table EMP')</script>"
Return
Endif
TEMPLATE PARAMS oRs
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="Vlademiro">
<title>Sistema </title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<main role="main" class="container">
<h1>Tutorial de Mod-Harbour + Grid</h1>
<p class="lead">Grid versão inicial</p>
<div class="row">
<table id="registros" class="table table-striped">
<thead><tr><th>EMPNO</th><th>ENAME</th></tr></thead>
<!-- Dados -->
<tbody>
<!-- Dados -->
<?prg
return FData( oRs )
?>
</tbody>
</table>
</div>
</main><!-- /.container -->
</body>
</html>
ENDTEXT
return nil
FUNCTION FData( oRs )
LOCAL cData := ""
if oRs:recordcount > 0
oRs:Movefirst()
do while !oRs:eof()
cData += "<tr>"
cData += "<td>" + hb_ntos( oRs:fields("empno"):value ) + "</td>"
cData += "<td>" + oRs:fields("ename"):value + "</td>"
cData += "</tr>"
oRs:movenext()
enddo
oRs:Movefirst() // Opcional, retorna para o primeiro registro
endif
RETURN cData
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Mini tutorial mod_harbour
Não pra atrapalhar, mas pra talvez inspirar alterações no mod_harbour.
No ASP é misturado fonte com HTML de forma talvez diferente.
Uma tabela:
a b c d
1 2 3 4
1 2 3 4
Vou ter que eliminar os sinais de maior/menor no html pra aceitar aqui
Vai de table até /table, tr /tr pra indicar inicio e fim de linha da tabela, td /td pra indicar cada coluna
table
tr td a /td td b /td td c /td td d /td /tr
tr td 1 /td td 2 /td td 3 /td td 4 /td /tr
/table
A página em ASP, misturando html com fonte
html
script language=VBScript
table
tr td a /td td b /td td c /td td d /td /tr
FOR nCont = 1 TO 2
tr
FOR nCont2 = 1 TO 4
td nCont2 /td
NEXT
/tr
NEXT
/table
É só pra dar uma idéia.
Misturar html e fonte.... não é fácil.
É aí que entram rotinas prontas/frameworks.
Por exemplo, passar o array multidimensional pra rotina, e ela se vira.
Toda essa complicação continua existindo, mas no "nosso" fonte, isso não aparece.
Se a rotina for em javascript ou outra coisa, tanto faz, porque o html permite misturar tudo.
Mas.... precisa entender de tudo pra misturar, não é porque vai usar VB ou Harbour, que só precisa conhecer VB ou Harbour.
Se está pensando em algo mágico... melhor esquecer.
No ASP é misturado fonte com HTML de forma talvez diferente.
Uma tabela:
a b c d
1 2 3 4
1 2 3 4
Vou ter que eliminar os sinais de maior/menor no html pra aceitar aqui
Vai de table até /table, tr /tr pra indicar inicio e fim de linha da tabela, td /td pra indicar cada coluna
table
tr td a /td td b /td td c /td td d /td /tr
tr td 1 /td td 2 /td td 3 /td td 4 /td /tr
/table
A página em ASP, misturando html com fonte
html
script language=VBScript
table
tr td a /td td b /td td c /td td d /td /tr
FOR nCont = 1 TO 2
tr
FOR nCont2 = 1 TO 4
td nCont2 /td
NEXT
/tr
NEXT
/table
É só pra dar uma idéia.
Misturar html e fonte.... não é fácil.
É aí que entram rotinas prontas/frameworks.
Por exemplo, passar o array multidimensional pra rotina, e ela se vira.
Toda essa complicação continua existindo, mas no "nosso" fonte, isso não aparece.
Se a rotina for em javascript ou outra coisa, tanto faz, porque o html permite misturar tudo.
Mas.... precisa entender de tudo pra misturar, não é porque vai usar VB ou Harbour, que só precisa conhecer VB ou Harbour.
Se está pensando em algo mágico... melhor esquecer.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Mini tutorial mod_harbour
A propósito..... a Vlademiro já chamou a atenção justamente pra uma diferença nisso do mod_harbour
No asp daria pra misturar HTML / ASP no meio do fonte, sem precisar ser um ou outro de cada vez
Já no mod_harbour não, o fonte Harbour precisa gerar todo bloco de html
No asp basta que a parte que se refere a fonte esteja entre "<% >", o fonte tem precedência
Numa explicação simples:
No mod_harbour o bloco do fonte PRG é compilado e executado, então ele precisa conter tudo.
no asp o fonte vai sendo executado conforme aparece no html.
No asp daria pra misturar HTML / ASP no meio do fonte, sem precisar ser um ou outro de cada vez
Código: Selecionar todos
< tr >
<% FOR nCont = 1 TO 10 %>
< td >
<% nCont %>
< /td >
<% NEXT %>
< /td >
Código: Selecionar todos
<?prg >
? "< tr >"
FOR nCont = 1 TO 10
? "< td >" + Str( ncont, 6 ) + "< /td >"
NEXT
? "< /tr >"
?>
Numa explicação simples:
No mod_harbour o bloco do fonte PRG é compilado e executado, então ele precisa conter tudo.
no asp o fonte vai sendo executado conforme aparece no html.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
- JoséQuintas
- Administrador

- Mensagens: 20267
- Registrado em: 26 Fev 2007 11:59
- Localização: São Paulo-SP
Mini tutorial mod_harbour
Ou de outra forma:
é como ter um texto assim:
< html > [rotina1()] <table> [rotina2()] </table> </html >
o Harbour recebe o texto como parâmetro, e substitui:
cHtml := StrTran( "[rotina1()]", Rotina1() )
cHtml := StrTran( "[rotina2()]", Rotina2() )
Para a substituição, são retirados os blocos [], e o conteúdo é compilado.
Ou seja, uma coisa bem básica mesmo, que a maioria aqui já fez.
O único diferencial, é configurar isso no apache, pro programa Harbour receber o HTML primeiro e substituir tudo, antes do HTML ser executado. Isso é feito pela extensão PRG.
Na verdade outro diferencial: foi alterada a saída padrão, do ? "x", pra gravar direto no html, sem precisar ficar concatenando texto.
Ao invés de ir pra console, vai para o html resultado final.
é como ter um texto assim:
< html > [rotina1()] <table> [rotina2()] </table> </html >
o Harbour recebe o texto como parâmetro, e substitui:
cHtml := StrTran( "[rotina1()]", Rotina1() )
cHtml := StrTran( "[rotina2()]", Rotina2() )
Para a substituição, são retirados os blocos [], e o conteúdo é compilado.
Ou seja, uma coisa bem básica mesmo, que a maioria aqui já fez.
O único diferencial, é configurar isso no apache, pro programa Harbour receber o HTML primeiro e substituir tudo, antes do HTML ser executado. Isso é feito pela extensão PRG.
Na verdade outro diferencial: foi alterada a saída padrão, do ? "x", pra gravar direto no html, sem precisar ficar concatenando texto.
Ao invés de ir pra console, vai para o html resultado final.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"
https://github.com/JoseQuintas/
Mini tutorial mod_harbour
É verdade, Quintas
Na realidade da pra fazer muita coisa do jeito que está, inclusive o padrão de projeto MVC , bastante usado, diz que os dados tem que ficar separados da view. Ponto para o mod_harbour.
Quando eu comecei a programar para web era ASP antigo, depois PHP. Para quem está iniciando a mistura de código com HTML é normal e, na minha opinião, faz parte do aprendizado. Nem sempre a gente quer fazer um sistema completo, quer só uma página para abrir no celular do cliente para ele ver os pedidos do dia. Coisa simples mesmo. Nesse caso o PHP facilita por deixar misturar tudo em uma página.
Na realidade da pra fazer muita coisa do jeito que está, inclusive o padrão de projeto MVC , bastante usado, diz que os dados tem que ficar separados da view. Ponto para o mod_harbour.
Quando eu comecei a programar para web era ASP antigo, depois PHP. Para quem está iniciando a mistura de código com HTML é normal e, na minha opinião, faz parte do aprendizado. Nem sempre a gente quer fazer um sistema completo, quer só uma página para abrir no celular do cliente para ele ver os pedidos do dia. Coisa simples mesmo. Nesse caso o PHP facilita por deixar misturar tudo em uma página.
Mini tutorial mod_harbour
Segunda Parte
Chegamos a parte dois do nosso mini-tutorial.
Os pré-requisitos para essa parte são :
(1) Ter acompanhado os exemplos da parte 1
(2) Saber o que é JSON e as funções do Harbour para manipulação (encode/decode)
(3) Entender os métodos POST/GET do protocolo HTTP
(4) Básico de JQuery (Básico mesmo)
Se vc não souber, mesmo assim dá para acompanhar, eu acho...
O objetivo dessa etapa é criar um grid usando AJAX e com paginação.
Nada de mod_harbour será usado nessa primeira etapa. Iremos somente criar um modelo para as etapas posteriores.
**
A ideia é essa :
São dois arquivos, o principal (contendo a view) e o segundo só com o json.
Nas etapas seguintes nós iremos gerar o arquivo json com mod_harbour.
A equipe do mod_harbour (indiretamente) indica uma biblioteca para
geração de grids que pode ser baixada gratuitamente em https://datatables.net/
Nós não iremos usar essa biblioteca. As vezes baixamos coisa demais que não vamos usar.
Nesses exemplos a seguir, com pouco código, já dá para ter um ótimo resultado.
**
O código json estático é bem simples :
A leitura desse arquivo é bem simples, primeiro vamos criar um "id" no html para informar
o ponto onde os dados serão escritos. Vou chamar esse "id" de "registros"
Agora o código Javascript (JQuery) que vai pegar o JSON e colocar na tabela.
Rápidos comentários sobre o código acima para quem não trabalhou com JQuery ainda.
Essa função chamada por success é simples, basta lembrar da função de usuário do DBEDIT. É a mesma ideia.
O parâmetro data é o valor lido do arquivo já devidamente convertido para JSON (eu disse que era um JSON em dataType)
Esse $.each é um laço disfarçado de função que vai percorrer todos os elementos do JSON (agora devidamente convertido para um hash data).
E para cada elemento vai chamar um bloco de código function( key , val )
* o segundo parâmetro "val" é o que interessa. Ele já contém a chave e o valor de cada hash. Tudo automático.
* o método appendTo coloca os dados na marca que eu criei no início.
Você pode achar que eu compliquei com o AJAX, mas é até mais fácil.
Na próxima etapa vamos gerar o dados.json com mod_harbour.
Chegamos a parte dois do nosso mini-tutorial.
Os pré-requisitos para essa parte são :
(1) Ter acompanhado os exemplos da parte 1
(2) Saber o que é JSON e as funções do Harbour para manipulação (encode/decode)
(3) Entender os métodos POST/GET do protocolo HTTP
(4) Básico de JQuery (Básico mesmo)
Se vc não souber, mesmo assim dá para acompanhar, eu acho...
O objetivo dessa etapa é criar um grid usando AJAX e com paginação.
Nada de mod_harbour será usado nessa primeira etapa. Iremos somente criar um modelo para as etapas posteriores.
**
A ideia é essa :
Código: Selecionar todos
HTML5 + JQuery ------AJAX--------> arquivo.json
(VIEW) (DATA)
Nas etapas seguintes nós iremos gerar o arquivo json com mod_harbour.
A equipe do mod_harbour (indiretamente) indica uma biblioteca para
geração de grids que pode ser baixada gratuitamente em https://datatables.net/
Nós não iremos usar essa biblioteca. As vezes baixamos coisa demais que não vamos usar.
Nesses exemplos a seguir, com pouco código, já dá para ter um ótimo resultado.
**
O código json estático é bem simples :
Código: Selecionar todos
[
{ "id":9, "nome":"João Marcelo" },
{ "id":1, "nome":"Jefferson" },
{ "id":2, "nome":"Daniel" }
]
o ponto onde os dados serão escritos. Vou chamar esse "id" de "registros"
Código: Selecionar todos
<table id="registros" class="table table-striped">
Código: Selecionar todos
<script>
$( document ).ready( function(){
$.ajax({
type: 'GET',
url: "dados.json",
async: true,
dataType: 'json',
success: function( data ){
$.each( data, function( key, val ) {
$('<tr>').html( "<td>" + val.id + "</td>" +
"<td>" + val.nome + "</td>" ).appendTo("#registros tbody");
});
}
}); // ajax
}); // $( document ).ready
</script>
Código: Selecionar todos
(1) $( document ).ready( // Aguarda o documento carregar para executar o código
(2) $.ajax // Inicio da chamada ajax
(3) type : 'GET' // Tipo de método usado (não faz diferença porque não tem dados para enviar)
(4) dataType: 'json' // O tipo de dado que será convertido.
(5) url // Endereço onde eu devo pegar os dados (aceita endereços relativos)
(6) success // Bloco de código que será executado em caso de sucesso (a página existe)
O parâmetro data é o valor lido do arquivo já devidamente convertido para JSON (eu disse que era um JSON em dataType)
Esse $.each é um laço disfarçado de função que vai percorrer todos os elementos do JSON (agora devidamente convertido para um hash data).
E para cada elemento vai chamar um bloco de código function( key , val )
* o segundo parâmetro "val" é o que interessa. Ele já contém a chave e o valor de cada hash. Tudo automático.
* o método appendTo coloca os dados na marca que eu criei no início.
Você pode achar que eu compliquei com o AJAX, mas é até mais fácil.
Na próxima etapa vamos gerar o dados.json com mod_harbour.
Mini tutorial mod_harbour
* Gerando o JSON dinâmicamente com mod-harbour
Essa parte já foi vista na primeira parte do nosso tutorial, é laço que lerá os dados.
Apenas acrescento duas coisas :
(1) O laço terá seus dados armazenados em um array de hash para posterior conversão em JSON
(2) Use hb_JsonEncode para criar o json e exibir
* Obs: Não deve ter nada impresso antes da exibição do JSON, por isso usei ?? e não ?.
O nosso código ficou assim :
No nosso cliente apenas informo que ele deve pegar de dados.prg e não mais de dados.json
Aproveitei e coloquei um método a mais AJAX do JQuery, é o simples, é só para ele retornar
algo em caso de erro. Por exemplo, o seu servidor pode estar fora do ar. O usuário precisa
pelo menos saber disso, senão fica um grid estático sem nada.
Isso é feito com :
Dentro da função $.ajax do JQuery. O mesmo princípio da função de usuário da DBEDIT também.
Essa parte já foi vista na primeira parte do nosso tutorial, é laço que lerá os dados.
Apenas acrescento duas coisas :
(1) O laço terá seus dados armazenados em um array de hash para posterior conversão em JSON
(2) Use hb_JsonEncode para criar o json e exibir
* Obs: Não deve ter nada impresso antes da exibição do JSON, por isso usei ?? e não ?.
O nosso código ficou assim :
Código: Selecionar todos
#define adOpenForwardOnly 0
#define adOpenKeyset 1
#define adOpenDynamic 2
#define adOpenStatic 3
#define adLockReadOnly 1
#define adLockPessimistic 2
#define adLockOptimistic 3
#define adLockBatchOptimistic 4
#define adUseNone 1
#define adUseServer 2
#define adUseClient 3
#define adStateClose 0
function main
LOCAL oRs , oCn, cSql
LOCAL cString := "Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=" + PathBase() + "/scott.mdb"
LOCAL hReg
LOCAL aReg := {}
oCn := win_oleCreateObject( "ADODB.Connection" )
oCn:ConnectionString := cString
oCn:Open()
oRs := win_oleCreateObject( "ADODB.Recordset" )
oRs:CursorLocation = adUseClient
oRs:Open( "SELECT * FROM emp", oCn , adOpenDynamic, adLockOptimistic )
if oCn:State = adStateClose
Return "ERRO"
Endif
if oRs:recordcount > 0
oRs:Movefirst()
do while !oRs:eof()
hReg := {=>}
hReg[ "id" ] := oRs:fields("empno"):value
hReg[ "nome" ] := oRs:fields("ename"):value
AADD( aReg , hReg )
oRs:movenext()
enddo
oRs:Movefirst() // Opcional, retorna para o primeiro registro
endif
?? hb_JsonEncode( aReg )
return nil
Código: Selecionar todos
url: "dados.prg",
algo em caso de erro. Por exemplo, o seu servidor pode estar fora do ar. O usuário precisa
pelo menos saber disso, senão fica um grid estático sem nada.
Isso é feito com :
Código: Selecionar todos
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
