sexta-feira, 8 de abril de 2011

Função para encodar texto em UTF-8 recursivamente

Se você está encontrando problemas em obter dados do mysql para retornar um JSON, onde a função json_encode não pega todas as colunas da tabela, provavelmente deve ser o charset.

Achei uma função para encodar texto em UTF-8 recursivamente:

function utf8_encode_all($dat) {
if (is_string($dat)) return utf8_encode(nl2br($dat));
if (!is_array($dat)) return nl2br($dat);
$ret = array();
foreach($dat as $i=>$d) $ret[$i] = utf8_encode_all($d);
return $ret;
}


Agora para retornar o seu JSON faça algo do tipo:

...

while($row = mysql_fetch_array($resource)) {
$data[] = $row;
}

...

json_encode(utf8_encode_all($data));

...



Espero que gostem!
[]'s

sábado, 2 de abril de 2011

Instalando PHPUnit no windows

Para instalar PHPUnit no windows, devemos instalar o PEAR executando o script go-pear.bat que encontra-se no diretório de instalação do PHP.

C:\php\>go-pear
Are you installing a system-wide PEAR or a local copy?
(system|local) [system] : (ENTER)
Below is a suggested file layout for your new PEAR installation. To
change individual locations, type the number in front of the
directory. Type 'all' to change all of them or simply press Enter to
accept these locations.
1. Installation base ($prefix) : C:\php
2. Temporary directory for processing : C:\php\tmp
3. Temporary directory for downloads : C:\php\tmp
4. Binaries directory : C:\php
5. PHP code directory ($php_dir) : C:\php\pear
6. Documentation directory : C:\php\docs
7. Data directory : C:\php\data
8. User-modifiable configuration files directory : C:\php\cfg
9. Public Web Files directory : C:\php\www
10. Tests directory : C:\php\tests
11. Name of configuration file : C:\Windows\pear.ini
12. Path to CLI php.exe : C:\php

1-12, 'all' or Enter to continue: (ARRUME OS PATHS)
Beginning install...
Configuration written to C:\Windows\pear.ini...
Initialized registry...
Preparing to install...

installing phar://go-pear.phar/PEAR/go-pear-tarballs/Archive_Tar-1.3.3.tar...
installing phar://go-pear.phar/PEAR/go-pear-tarballs/Console_Getopt-1.2.3.tar...
installing phar://go-pear.phar/PEAR/go-pear-tarballs/PEAR-1.9.0.tar...
installing phar://go-pear.phar/PEAR/go-pear-tarballs/Structures_Graph-1.0.2.tar...
installing phar://go-pear.phar/PEAR/go-pear-tarballs/XML_Util-1.2.1.tar...

install ok: channel://pear.php.net/Archive_Tar-1.3.3
install ok: channel://pear.php.net/Console_Getopt-1.2.3
install ok: channel://pear.php.net/Structures_Graph-1.0.2
install ok: channel://pear.php.net/XML_Util-1.2.1
install ok: channel://pear.php.net/PEAR-1.9.0

PEAR: Optional feature webinstaller available (PEAR's web-based installer)
PEAR: Optional feature gtkinstaller available (PEAR's PHP-GTK-based installer)
PEAR: Optional feature gtk2installer available (PEAR's PHP-GTK2-based installer)
PEAR: To install optional features use "pear install pear/PEAR#featurename"

The 'pear' command is now at your service at c:\php\pear.bat

* WINDOWS ENVIRONMENT VARIABLES *
For convenience, a REG file is available under c:\php\PEAR_ENV.reg

This file creates ENV variables for the current user.
Double-click this file to add it to the current user registry.

Press any key to continue . . .


Adicione os repositórios do PHPUnit e atualize-os:
C:\php\>pear channel-discover pear.phpunit.de
Adding Channel "pear.phpunit.de" succeeded
Discovery of channel "pear.phpunit.de" succeeded

C:\php\>pear channel-discover pear.symfony-project.com
Adding Channel "pear.symfony-project.com" succeeded
Discovery of channel "pear.symfony-project.com" succeeded

C:\php\>pear update-channels
Updating channel "doc.php.net"
Channel "doc.php.net" is up to date
Updating channel "pear.php.net"
Channel "pear.php.net" is up to date
Updating channel "pear.phpunit.de"
Channel "pear.phpunit.de" is up to date
Updating channel "pear.symfony-project.com"
Channel "pear.symfony-project.com" is up to date
Updating channel "pecl.php.net"
Channel "pecl.php.net" is up to date

C:\php>pear upgrade-all
Will upgrade channel://pear.php.net/archive_tar
Will upgrade channel://pear.php.net/pear
Will upgrade channel://pear.php.net/structures_graph
downloading Archive_Tar-1.3.7.tgz ...
Starting to download Archive_Tar-1.3.7.tgz (17,610 bytes)
......done: 17,610 bytes
downloading PEAR-1.9.1.tgz ...
Starting to download PEAR-1.9.1.tgz (293,587 bytes)
...done: 293,587 bytes
downloading Structures_Graph-1.0.3.tgz ...
Starting to download Structures_Graph-1.0.3.tgz (30,191 bytes)
...done: 30,191 bytes
upgrade-all ok: channel://pear.php.net/Archive_Tar-1.3.7
upgrade-all ok: channel://pear.php.net/Structures_Graph-1.0.3
upgrade-all ok: channel://pear.php.net/PEAR-1.9.1

PEAR: Optional feature webinstaller available (PEAR's web-based installer)
PEAR: Optional feature gtkinstaller available (PEAR's PHP-GTK-based installer)
PEAR: Optional feature gtk2installer available (PEAR's PHP-GTK2-based installer)
PEAR: To install optional features use "pear install pear/PEAR#featurename"


Instalando PHPUnit 3.4.14

C:\php\>pear install phpunit/PHPUnit
Did not download optional dependencies: pear/Image_GraphViz, pear/Log, symfony/YAML,
use --alldeps to download automatically

phpunit/PHPUnit can optionally use package "pear/Image_GraphViz" (version >= 1.2.1)
phpunit/PHPUnit can optionally use package "pear/Log"
phpunit/PHPUnit can optionally use package "symfony/YAML" (version >= 1.0.2)
phpunit/PHPUnit can optionally use PHP extension "soap"
phpunit/PHPUnit can optionally use PHP extension "xdebug" (version >= 2.0.5)

downloading PHPUnit-3.4.14.tgz ...
Starting to download PHPUnit-3.4.14.tgz (254,983 bytes)
.....................................................done: 254,983 bytes
install ok: channel://pear.phpunit.de/PHPUnit-3.4.14


É isso! Espero que gostem.

domingo, 18 de janeiro de 2009

Arquivos de configuração .ini no PHP

Arquivos .ini no PHP

Autor: João Pinto Neto
E-mail: joaopintoneto (arroba) gmail (ponto) com



Um exemplo bem prático de como utilizar arquivos de configuração .ini lendo suas propriedades em um array. Com poucas linhas de código faremos com que a classe Config, atravéz do método estático getConfigFiles(), leia o diretório /Config/ da aplicação. O outro método (parseConfigFile()), faz um parse de um arquivo .ini que for informado o path (caminho completo), retornando um array com os parâmetros desse arquivo .ini.

Config.class.php:

<?php
final class Config
{

static public function getConfigFiles()
{
$configFiles = glob('Config/*.{ini}', GLOB_BRACE);

if (count($configFiles) <= 0)
{
return false;
}

$callback = create_function('$file', 'return array(basename($file, ".ini") => $file);');

$configFiles = array_map($callback, $configFiles);

foreach ($configFiles as $oldKey => $oldValue)
foreach ($oldValue as $newKey => $newValue)
$return[strtolower($newKey)] = $newValue;

return $return;
}

static public function parseConfigFile($configFile)
{
return parse_ini_file($configFile, true);
}
}

/**
* Aqui, a forma de usar:
*/
$configFiles = Config::getConfigFiles();

// debug
print_r($configFiles);

foreach ($configFiles as $file) {
$configVars = Config::parseConfigFile($file);
}
?>


para usar:
- Copie o código acima e salve como Config.class.php
- No mesmo diretório, crie uma pasta de nome: Config
- Entre no diretório config e crie um arquivo .ini (salve como qualquer_nome.ini)
- Coloque alguns parâmetros, ex:

; Comentários com (ponto e vírgula)
; arquivo .ini
; qualquer_nome.ini
; ----------------------

app_name=teste
app_version=1.0



É isso!
Espero que gostem.
Abraços

sexta-feira, 16 de janeiro de 2009

TWebBrowser

Tutorial: Usando o componente TWebBrowser

Autor: João Pinto Neto
E-mail: joaopintoneto (arroba) gmail (ponto) com

Introdução

O componente TWebBrowser possibilita embutir funcionalidades do Internet Explorer nas aplicações desenvolvidas para executar em plataformas Windows. Com esse componente, é possível interagir com o browser e criar aplicações baseadas em web. Existem várias formas de utilizar-lo:

Para criar um browser customizado;
Criar sistema de troca de skin;
Criar sistema baseado em HTML dinâmico;
Usar javascript e vbscript;

Como utilizar

Neste tutorial, explicarei passo a passo como criar uma aplicação que atravéz de um documento HTML, pega o evento do link para fechar o Form principal. Criaremos um documento HTML com formatações padrões, de forma que execute em qualquer browser, independente de ser o Microsoft Internet Explorer ou não. Só que, em vez do link referenciar para um URL válido, ele apontará para um flag (esse flag será o código para ativar o evento Close) que fecha o Form principal.

Mãos à massa!

Requisitos mínimos para o desenvolvimento do tutorial

Conhecimento básico em HTML;
Windows 98;
Microsoft Internet Explorer 6;
Delphi 5;

Observação: Este tutorial foi desenvolvido com Delphi 7, verifique na paleta de componentes Internet se existe o componente TWebBrowser.
Paleta de componentes Internet do Delphi

Criando o documento HTM

Abra o seu editor HTML, digite as linhas de código abaixo e mande salvar como index.html:


<html>
<h1>Web Browser</h1>
<br />
<br />
<br />
<a href="teste:fechar">Fechar</a>
</html>

Criando o Form Principal

Primeiramente abra o Delphi, se estiver com algum projeto aberto, feche tudo no menu File / Close All. Crie uma nova aplicaçãono no menu File / New / Application. Agora altere as propriedades do Form1 no Object Inspector:

Heigth: 392
Width: 410

Altere o evento onCreate do Form1:

OnCreate do Form1
procedure TForm1.FormCreate(Sender: TObject);
begin
WebBrowser1.Navigate('file://'+ExtractFilePath(Application.ExeName)+'main.html');
end;

Insira um componente TWebBrowser TWebBrowser da paleta de componentes Internet em Form1 e altere as suas propriedades:

Heigth: 320
Width: 370
Left: 16
Top: 16
Heigth: 392
Width: 410

Altere o evento onBeforeNavegate2 do WebBrowser1:

OnCreate do Form1
procedure TForm1.WebBrowser1BeforeNavigate2(Sender: TObject;
const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
Headers: OleVariant; var Cancel: WordBool);
begin
//Lembra do link Fechar ???
if URL = 'teste:fechar' then Close;
end;

Resultado final


Depois de configurar todas essas propriedades e eventos, o seu Form1 deve estar semelhante à figura abaixo, agora salve tudo no menu File / Save All..., no dialogo de Save Unit1 As, salve como main.pas e no dialogo Save Project1 As, salve como webbrowser.dpr
Antes de compilar, verifique se o index.html está no mesmo diretório do projeto e se estiver, aperte F9 para compilar e executar.
Quando o programa estiver em execução, clique no link fechar, para sair do aplicativo.
Form1 Resultado final

quinta-feira, 15 de janeiro de 2009

Delphi e MySQL de outra forma

Tutorial: libmysql.dll através do mysql.pas no Delphi / MySQL 5


Autor: João Pinto Neto
E-mail: joaopintoneto (arroba) gmail (ponto) com


Introdução

Existem várias formas para acessar os dados de uma Base de Dados MySQL no Delphi, o mais comum é através do driver ODBC adequado à versão do MySQL que se deseja utilizar. Neste tutorial eu ensinarei como obter acesso através da biblioteca libmysql.dll, uma alternativa muito interessante para trabalhar em um nível de comunicação quase que direto, passando as funções da DLL diretamente para o Banco de Dados. A biblioteca libmysql.dll é uma DLL que vem incluída na instalação padrão do MySQL, ela possui todas as funções necessárias para comunicação direta. E para utilizar essas funções é preciso criar um link de cada uma no projeto em que se deseja acessar o Banco de Dados, tarefa essa que esta implementada em C e que originalmente também vem com a instalação padrão, foi traduzida e adaptada por Matthias Fichtner para Delphi (4 ou superior), com o nome de mysql.pas, é nessa Unit que se encontram as funções. Ela pode ser encontrada para download no site: http://www.fichtner.net/delphi/mysql/. Porém, o autor anunciou em seu site a descontinuação de atualizações para essa Unit e está com o projeto parado dês de o MySQL 3.23.49. Mas esta Unit funciona com a libmysql.dll do MySQL 5. Este tutorial considera que você já esteja com o MySQL 5 instalado, vá ao site http://www.mysql.com/ para fazer o download do instalador ou do pacote .zip que contem os binários para windows e siga os passos para instalar e iniciar o Banco de Dados, caso você ainda não tenha feito.

Criando a Base de Dados

Abra um prompt de comando do windows e entre na pasta dos arquivos binários do MySQL, conecte-se como root para criar a nova Base de Dados, a tabela e o usuário do Banco de Dados que utilizaremos no decorrer de todo o tutorial, para isto, execute os seguintes passos:

1- Criar a Base de Dados e o usuário:

: Entre na pasta dos binários do MySQL
: Conecte como root, se tiver senha use o parâmetro -p

C:\> cd \mysql\bin
C:\mysql\bin> mysql -u root

-- Crie a Base de Dados
mysql> create database agenda;
Query OK, 1 row affected (0.08 sec)

-- Mude a Base de Dados atual
mysql> use agenda
Database changed

-- Crie um novo usuário
mysql> grant all privileges on agenda.* to agenda1 identified by "agenda123";
Query OK, 0 rows affected (0.03 sec)

-- Vamos testar o usuário que acabamos de criar, desconecte como root
mysql> quit
Bye

2- Criar as tabelas necessárias:

: Conecte com o usuário agenda1 na Base de Dados agenda
C:\mysql\bin>mysql -u agenda1 -p agenda
Enter password: *********

-- Tabela dos contatos
mysql> create table contatos(
-> con_codigo smallint(6) not null auto_increment,
-> con_nome varchar(40) default NULL,
-> con_endereco varchar(60) default NULL,
-> con_bairro varchar(20) default NULL,
-> con_cep char(8) default NULL,
-> con_cidade varchar(40) default NULL,
-> con_telefone varchar(16) default NULL,
-> con_celular varchar(16) default NULL,
-> con_email varchar(255) default NULL,
-> primary key(con_codigo)
-> );
Query OK, 0 rows affected (0.08 sec)

3- Cadastrar alguns contatos:

mysql> insert into contatos (con_nome) values
-> ('JOAO PINTO NETO'),
-> ('JOSE DA SILVA'),
-> ('BILLIE JOE ARMTRONG'),
-> ('CURT COBAIN'),
-> ('AXEL ROSE'),
-> ('ROBERT DE NIRO');
Query OK, 6 rows affected (0.05 sec)
Registros: 6 - Duplicados: 0 - Avisos: 0

Preparando a interface

Primeiramente teremos que criar uma pasta para o novo projeto, crie o diretório C:\AGENDA. Agora coloque a biblioteca que vem junto com o MySQL C:\mysql\lib\opt\libmysql.dll e também a Unit mysql.pas no diretório do projeto. Faça o download do projeto completo, com a DLL libmysql.dll, a Unit e o codigo-fonte completo aqui.

Agora abra o Delphi e crie uma nova aplicação, mande salvar tudo (Save All...), quando pedir nome do arquivo para Unit1, salve como main.pas e o projeto, salve como agenda. Insira 2 componentes Panels, selecione o Panel1 e inclua 10 SpeedButtons, selecione o Panel2 e inclua 9 componentes Label e 9 componentes Edit. Agora altere as propriedades no Object Inspector dos componentes:

Form1
Caption = Agenda
BorderStyle = bsSingle
BorderIcons = biMaximize = False

Panel1
Caption = deixe nulo
BevelOuter = bvNone
Align = alTop
Height = 48

Panel2
Caption = deixe nulo
BevelOuter = bvNone
Align = alClient

Altere a propriedade Name dos SpeedButtons para facilitar a programação do código de cada um:

SpeedButton1 = btnPrimeiro
SpeedButton2 = btnAnterior
SpeedButton3 = btnProximo
SpeedButton4 = btnUltimo
SpeedButton5 = btnNovo
SpeedButton6 = btnEditar
SpeedButton7 = btnSalvar
SpeedButton8 = btnCancelar
SpeedButton9 = btnDeletar
SpeedButton10 = btnFechar

Altere as propriedades dos componentes para que o formulário fique semelhante à figura abaixo:
Form1

Codificação

Antes de começar a explicar os procedimentos do código-fonte do exemplo, darei uma explicação básica de como fazer uma conexão com o Banco de Dados MySQL. Precisaremos definir 3 variáveis, essas variáveis na verdade serão ponteiros apontando uma para conexão (myData), outra para os resultados da query SQL (myRes) e outra que aponta as linhas do resultado.

Linha 01: inicia o ponteiro myData; Linha 02: estabelece a conexão com o banco; Linha 03: seleciona a Base de Dados; Linha 04: executa consulta SQL; Linha 05: pega os resultados da consulta SQL em myRes; Linha 06: Pega a linha 0 do resultado de myRes em myRow; Linha 07: exibe mensagem A; Linha 08: Pega a linha 1 do resultado de myRes em myRow; Linha 09: exibe mesagem B; Linha 10: Fecha a conexão; Linha 11: myData aponta para nil (nada); myRow[X] é a coluna, onde X é o número da coluna e a coluna é o campo da tabela.

{ Linha 01 } myData:= mysql_init(myData);
{ Linha 02 } mysql_real_connect(myData,PChar('localhost'),PChar('USUARIO'),PChar('SENHA'),nil,3306,nil,0);
{ Linha 03 } mysql_select_db(myData,PChar('DATABASE'));
{ Linha 04 } mysql_query(myData,PChar('SELECT NOW()'));
{ Linha 05 } myRes:= mysql_store_result(myData);
{ Linha 06 } myRow:= mysql_fetch_row(myRes); // Aqui o valor é A
{ Linha 07 } ShowMessage(myRow[0]); // Exibe A
{ Linha 08 } myRow:= mysql_fetch_row(myRes); // Aqui o valor é B
{ Linha 09 } ShowMessage(myRow[0]); // Exibe B
{ Linha 10 } mysql_close(myData);
{ Linha 11 } myData:= nil;

A biblioteca libmysql.dll torna a codificação parecida com PHP, que recupera os dados através de uma consulta SQL e fecha a conexão. Para manipular os registros, criaremos um índice na chave primária. O índice será um TStringList (variável Registros) que armazenará todos os códigos da tabela contatos de uma consulta SQL na tabela contatos, cada código terá uma posição no índice, tornando possível a navegação entre os registros.
Para identificar o estado das tabelas, criaremos o tipo TMySQLState (variável Estado) com 3 estados: msEdit, msInsert e msBrowse. Assim, será possível saber se o que está acontecendo com a tabela. Será necessário armazenar o código atual (variável Codigo) para poder edita-lo ou exclui-lo e a posição dele no índice TStringList, aramazenando o índice (variável Indice) para identificar se o índice está no início (BOF) ou no fim (EOF) da tabela. Criaremos o tipo TMySQLPos (variável Posicao) com 3 estados: BOF, NORMAL e EOF para armazenar esta posição do índice.

Declarando constantes, variáveis, funções e procedimentos:

unit main;
interface
uses
// Inclua a Unit mysql
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms, Dialogs, Buttons, ExtCtrls, Grids, StdCtrls, mysql;

type
// Declaração de tipos adicionais
TMySQLState = (msEdit, msInsert, msBrowse);
TMySQLPos = (BOF, NORMAL, EOF);

type
TForm1 = class(TForm)
{ . . . }
// Declaração de procedimentos adicionais
procedure LimpaEdits;
procedure AtualizaBarra;
procedure AtualizaRegistros(TUDO: Boolean);
procedure AbreContato(Cod: ShortString);
{ . . . }
private
{ Private declarations }
myData: PMYSQL; // Ponteiro de conexão do MySQL
myRes: PMYSQL_RES; // Ponteiro de resultado da query
myRow: PMYSQL_ROW; // Ponteiro de linha do resultado
public
{ Public declarations }
SQL: PAnsiChar; // SQL
Estado: TMySQLState; // Estado dos registros na tabela
Posicao: TMySQLPos; // Posição dos registros na tabela
Codigo: ShortString; // Código atual
Indice: integer; // Índice do código atual
Registros: TStringList; // Todos os códigos da tabela
end;

var
Form1: TForm1;

const
// Constantes de conexão
myDB: PAnsiChar = 'agenda';
myUser: PAnsiChar = 'agenda1';
myPass: PAnsiChar = 'agenda123';
myLocalHost: PAnsiChar = 'localhost';

Procedimento LimpaEdits:

O procedimento LimpaEdits, serve para limpar o valor Text de todos os componentes Edits do formulário de uma vez.

procedure TForm1.LimpaEdits;
var x: byte;
begin
for x:= 0 to ComponentCount - 1 do
if Components[x].ClassType = TEdit
then (Components[x] as TEdit).Clear;
end;

Procedimento AtualizaBarra:

O procedimento AtualizaBarra, serve para atualizar a barra de botões, habilitando e desabilitando cada um de acordo com o Estado (msBrowse = Navegação, msInsert = Novo registro e msEdit = Edição do registro), Posicao (BOF = Primeiro registro, NORMAL = Nem no primeiro e nem no último e EOF = Último registro) e a quantidade dos registros.

procedure TForm1.AtualizaBarra;
begin
btnPrimeiro.Enabled:= (Estado = msBrowse) and (Posicao in [EOF, NORMAL]) and (Registros.Count > 0);
btnAnterior.Enabled:= (Estado = msBrowse) and (Posicao <> BOF) and (Registros.Count > 0);
btnProximo.Enabled:= (Estado = msBrowse) and (Posicao <> EOF) and (Registros.Count > 1);
btnUltimo.Enabled:= (Estado = msBrowse) and (Posicao in [BOF, NORMAL]) and (Registros.Count > 1);
btnNovo.Enabled:= (Estado = msBrowse);
btnEditar.Enabled:= (Estado = msBrowse) and (Registros.Count > 0);
btnSalvar.Enabled:= (Estado in [msInsert, msEdit]);
btnCancelar.Enabled:= (Estado in [msInsert, msEdit]);
btnDeletar.Enabled:= (Estado in [msBrowse, msEdit]) and (Registros.Count > 0);
Panel2.Enabled:= (Estado in [msInsert, msEdit]);
end;

Procedimento AtualizaRegistros:

O procedimento AtualizaRegistros, serve para atualizar o índice (Registro) de códigos, a opção TUDO, é para, se caso True, atualizar todos os códigos dentro do índice, ou no caso de False, atualizar apenas a posição (Posicao) e o índice (Indice).

procedure TForm1.AtualizaRegistros(TUDO: Boolean);
var x: integer;
begin
if TUDO then
begin
SQL:= PChar('select con_codigo from contatos order by con_nome');
Registros.Clear;
myData:= mysql_init(myData);
if (myData = nil)
or (mysql_real_connect(myData,myLocalHost,myUser,myPass,nil,3306,nil,0) = nil) then
begin
MessageDlg('Conexão perdida, o Banco de Dados parece estar off-line.',mtError,[mbOK],0);
mysql_close(myData);
myData:= nil;
end else
begin
mysql_select_db(myData,myDB);
mysql_query(myData,SQL);
myRes:= mysql_store_result(myData);

for x:= 0 to mysql_num_rows(myRes) - 1 do
begin
myRow:= mysql_fetch_row(myRes);
Registros.Add(myRow[0]);
end;

mysql_free_result(myRes);
mysql_close(myData);
myData:= nil;
myRes:= nil;
myRow:= nil;
end;
end;

if Registros.IndexOf(Codigo) <= 0 then Posicao:= BOF
else if Registros.IndexOf(Codigo) >= Registros.Count - 1
then Posicao:= EOF
else Posicao:= NORMAL;
Indice:= Registros.IndexOf(Codigo);
end;

Procedimento AbreContato:

O procedimento AbreContato, serve para recuperar todos os dados relativos a um determinado código (Cod) nos Edits do formulário e no fim do procedimento, aciona o procedimento AtualizaRegistros(False) para atualizar a posição do índice (Registro). Devemos prestar atenção quando o parâmetro Cod é informado, não é o seu índice que é passado e sim o código real do contato, aquele que está cadastrado na tabela no campo con_codigo.

procedure TForm1.AbreContato(Cod: ShortString);
begin
SQL:= PChar('select * from contatos where con_codigo = '+Cod+' limit 1');
myData:= mysql_init(myData);
if (myData = nil)
or (mysql_real_connect(myData,myLocalHost,myUser,myPass,nil,3306,nil,0) = nil) then
begin
MessageDlg('Conexão perdida, o Banco de Dados parece estar off-line.',mtError,[mbOK],0);
mysql_close(myData);
myData:= nil;
end else
begin
mysql_select_db(myData,myDB);
mysql_query(myData,SQL);
myRes:= mysql_store_result(myData);
myRow:= mysql_fetch_row(myRes);
Codigo:= myRow[0];
Edit1.Text:= myRow[0];
Edit2.Text:= myRow[1];
Edit3.Text:= myRow[2];
Edit4.Text:= myRow[3];
Edit5.Text:= myRow[4];
Edit6.Text:= myRow[5];
Edit7.Text:= myRow[6];
Edit8.Text:= myRow[7];
Edit9.Text:= myRow[8];
mysql_free_result(myRes);
mysql_close(myData);
myRow:= nil;
myRes:= nil;
myData:= nil;
end;
AtualizaRegistros(False);
end;

Procedimento FormCreate:

Abra o procedumento FormCreate e inclua o código abaixo. Quando o Form for criado, o índice Registros é criado, Estado inicia em modo navegação (msBrowse), o índice dos códigos é preenchido em AtualizaRegistros(True), se a quantidade de Registros for maior que 0, então abre o primeiro registro de Registros. Strings[0] quer dizer para passar como parâmetro o código (con_codigo) que esta na posição 0 das strings do Registros. E por fim, AtualizaBarra, que habilita ou desabilita os botões de controle do formulário.

procedure TForm1.FormCreate(Sender: TObject);
begin
Registros:= TStringList.Create;
Estado:= msBrowse;
AtualizaRegistros(True);
if (Registros.Count > 0) then AbreContato(Registros.Strings[0]);
AtualizaBarra;
end;

Procedimento FormDestroy:

Se criamos o índice de Registros, temos que liberar ele no FormDestroy.

procedure TForm1.FormDestroy(Sender: TObject);
begin
Registros.Free;
end;

Procedimento btnPrimeiroClick:

Dê duplo clique no botão btnPrimeiro e inclua o o código abaixo. Registros.Strings[0] é o primeiro código, como já foi dito anteriormente e se quisermos ir para o segundo código informamos Registros.Strings[1], assim por diante.

procedure TForm1.btnPrimeiroClick(Sender: TObject);
begin
AbreContato(Registros.Strings[0]);
AtualizaBarra;
end;

Procedimento btnAnteriorClick:

Dê duplo clique no botão btnAnterior e inclua o o código abaixo. A verificação de Posicao <> BOF, garante que se Posicao estiver no início da tabela, não volte, pois estaria fora do contexto selecionado em Registros e depois atualiza os botões de controle do formulário. Indice é a posição atual do índice então, Indice menos 1 será o registro anterior.

procedure TForm1.btnAnteriorClick(Sender: TObject);
begin
if Posicao <> BOF then AbreContato(Registros.Strings[Indice-1]);
AtualizaBarra;
end;

Procedimento btnProximoClick:

Dê duplo clique no botão btnProximo e inclua o código abaixo. Aqui a verificação é para o fim da tabela e o código será o íncice atual Indice mais 1.

procedure TForm1.btnProximoClick(Sender: TObject);
begin
if Posicao <> EOF then AbreContato(Registros.Strings[Indice+1]);
AtualizaBarra;
end;

Procedimento btnUltimoClick:

Dê duplo clique no botão btnUltimo e inclua o código abaixo. Registros.Count retorna o número de itens de Registros, assim é possível saber quantos registros a tabela têm e ir ao último, retira-se menos 1, por calsa da contagem de ítens começar em 1.

procedure TForm1.btnUltimoClick(Sender: TObject);
begin
AbreContato(Registros.Strings[Registros.Count-1]);
AtualizaBarra;
end;

Procedimento btnNovoClick:

Dê duplo clique no botão btnNovo e inclua o código abaixo. Estado muda para msInsert e habilita os Edits para cadastrar um novo registro. LimpaEdits limpa o Text de todos os Edits do formulário.

procedure TForm1.btnNovoClick(Sender: TObject);
begin
Estado:= msInsert;
AtualizaBarra;
LimpaEdits;
end;

Procedimento btnEditarClick:

Dê duplo clique no botão btnEditar e inclua o código abaixo. A diferença entre btnEditarClick e btnNovoClick é o Estado em msEdit e o Text dos Edits são mantidos.

procedure TForm1.btnEditarClick(Sender: TObject);
begin
Estado:= msEdit;
AtualizaBarra;
end;

Procedimento btnCancelarClick:

Dê duplo clique no botão btnCancelar e inclua o código abaixo. Se o Estado for msEdit ou msInsert, neste procedimento, ele volta para o modo de navegação entre registros msBrowse e abre o contato da posição Indice, que indica o código do último registro aberto, esta função é necessária porque o Estado em msEdit limpa os Edits, então, temos que carrega-los novamente.

procedure TForm1.btnCancelarClick(Sender: TObject);
begin
Estado:= msBrowse;
AbreContato(Registros.Strings[Indice]);
AtualizaBarra;
end;

Procedimento btnSalvarClick:

Dê duplo clique no botão btnSalvar e inclua o código abaixo. O comando SQL se altera para caso Estado = msInsert, então o SQL muda para inserção, ou Estado = msEdit, então SQL muda para edição. Na Linha 16 a variável myData é iniciada como um ponteiro do tipo PMYSQL, se o ponteiro não conseguir iniciar ele aponta para nil, que significa apontar "para o nada" e também se a conexão falhar ela aponta para nil, se estas 2 condições forem verdadeiras, então é preciso fechar a conexão e anular o ponteiro myData, setando o seu valor como nil, uma mensagem de erro aparece para o usuário dizendo que "o Banco de Dados parece estar off-line". Na Linha 25, seleciona a database myDB (que corresponde à agenda). Então se Estado = msInsert, verifica se já existe algum outro contato de nomes identicos (veja Linha 28) avisa o usuário e cansela, esta verificação é apenas para ilustrar essa possibilidade, neste caso não haveria necessidade, se não existir nenhum nome igual, executa comando SQL para inserir o novo registro e sai do procedimento (veja linha 52), caso contrário, se Estado = msEdit, executa o comando SQL para atualizar os dados (veja linha 54, ela só executa para Estado = msEdit). No fim, o Estado volta para msBrowse.

procedure TForm1.btnSalvarClick(Sender: TObject);
var Cod: ShortString;
begin
Panel2.Enabled:= False;
// Insert
if Estado = msInsert then
SQL:= PChar('insert into contatos(con_nome,con_endereco,con_bairro,con_cep,con_cidade,con_telefone,con_celular,con_email) ' +
'values("' + Trim(Edit2.Text) + '","' + Trim(Edit3.Text) + '","' + Trim(Edit4.Text) + '","' + Trim(Edit5.Text) + '","' + Trim(Edit6.Text) + '","' +
Trim(Edit7.Text) + '","' + Trim(Edit8.Text) + '","' + Trim(Edit9.Text) + '")')
else // Edit
SQL:= PChar('update contatos set ' +
'con_nome = "' + Trim(Edit2.Text) + '", con_endereco = "' + Trim(Edit3.Text) + '", con_bairro = "' + Trim(Edit4.Text) + '", con_cep = "' +
Trim(Edit5.Text) + '", con_cidade = "' + Trim(Edit6.Text) + '", con_telefone = "' + Trim(Edit7.Text) + '", con_celular = "' + Trim(Edit8.Text) +
'", con_email = "' + Trim(Edit9.Text) + '" where con_codigo = ' + Codigo);

myData:= mysql_init(myData); { Linha 16 }
if (myData = nil)
or (mysql_real_connect(myData,myLocalHost,myUser,myPass,nil,3306,nil,0) = nil) then
begin
MessageDlg('Conexão perdida, o Banco de Dados parece estar off-line.',mtError,[mbOK],0);
mysql_close(myData);
myData:= nil;
end else
begin
mysql_select_db(myData,myDB); { Linha 25 }
if Estado = msInsert then
begin
mysql_query(myData,PChar('select con_codigo from contatos where con_nome like "'+Edit2.Text+'"')); { Linha 28 }
myRes:= mysql_store_result(myData);
// Se já existir usuario
if mysql_num_rows(myRes) > 0 then
begin
MessageDlg('"'+Edit2.Text+'" já está cadastrado.',mtInformation,[mbOK],0);
mysql_close(myData);
myData:= nil;
Panel2.Enabled:= True;
Exit;
end;
mysql_query(myData,SQL);
mysql_query(myData,PChar('select con_codigo from contatos where con_nome like "'+Trim(Edit2.Text)+'"'));
myRes:= mysql_store_result(myData);
myRow:= mysql_fetch_row(myRes);
Cod:= myRow[0];
mysql_close(myData);
myData:= nil;
myRes:= nil;
myRow:= nil;
Estado:= msBrowse;
AtualizaRegistros(True);
AbreContato(Cod);
AtualizaBarra;
Exit; { Linha 52 }
end;
mysql_query(myData,SQL); { Linha 54 }
mysql_close(myData);
myData:= nil;
end;

Estado:= msBrowse;
AbreContato(Registros.Strings[Indice]);
AtualizaBarra;
end;

Procedimento btnDeletarClick:

Dê duplo clique no botão btnDeletar e inclua o código abaixo. Se a resposta for não para deletar o registro, então sai do procedimento e não executa nada. Senão, deleta o registro de código Codigo, atualiza o índice Registros e abre outro contato, tentando abrir primeiro um anterior, se não tiver nenhum antes, tenta abrir um depois.

procedure TForm1.btnDeletarClick(Sender: TObject);
begin
if (MessageDlg('Deseja remover "'+Edit2.Text+'" do registro definitivamente?',mtConfirmation,[mbYes,mbNo],0) = mrNo)
then Exit;
myData:= mysql_init(myData);
if (myData = nil)
or (mysql_real_connect(myData,myLocalHost,myUser,myPass,nil,3306,nil,0) = nil) then
begin
MessageDlg('Conexão perdida, o Banco de Dados parece estar off-line.',mtError,[mbOK],0);
mysql_close(myData);
myData:= nil;
end else
begin
mysql_select_db(myData,myDB);
// Deleta o contato
SQL:= PChar('delete from contatos where con_codigo = '+Codigo);
mysql_query(myData,SQL);
mysql_close(myData);
myData:= nil;
end;
AtualizaRegistros(True);
if Registros.Count > 0 then
try
AbreContato(Registros.Strings[Indice-1]);
except
AbreContato(Registros.Strings[Indice+1]);
end;
AtualizaBarra;
end;

quarta-feira, 14 de janeiro de 2009

Menu sanfona com UL e LI.

Existem vários tutorias de menus que utilizam tags DL, DT, UL e LI, mas vários menus gerados dinamicamente utilizam apenas tags UL e LI (já me deparei com isso). Para resolver esse problema veja este script.


Faça o download do jQuery aqui: http://code.google.com/p/jqueryjs/downloads/list




<html>
<head>
<title>JQuery - Menu Sanfona</title>
<script type="text/javascript" src="jquery.js"></script>
<style>
#leftblock {
float:left;

font-family:Arial, Helvetica, sans-serif;
font-size:10px;
}

#leftblock ul {
margin:10px;
padding:0;

list-style:none;
width:200px;
}

#leftblock ul li a {
display:block;
text-decoration:none;

color:#666666;
background:#FFFFFF;
padding:5px;
border-bottom:0;
}

#leftblock ul li a:hover {

color:#FF3300;
}

#leftblock ul ul {
margin:0px;
top:0;
}


#leftblock li ul li a {
padding:5px 20px;
background:none;
}
</style>

<script type="text/javascript">
var cores = new Array("#FFFFF5", "#F5FFF5", "#FFF5F5", "#F5F5FF", "#F5FFFF", "#FFF5FF", "#F9F9F9", "#FDF5F5");

$(document).ready(function(){
$("#leftmenu ul").each(function(i){$(this).css({"backgroundColor":cores[i+1]})});
$("#leftmenu ul:not(:first)").hide();
$("#leftmenu li a").click(function() {
$("#leftmenu li ul:visible").slideUp("slow");
$(this).parent().find("ul:eq(0)").slideToggle("slow");

});
});
</script>
</head>

<body>
<div id="leftblock">
<ul id="leftmenu">

<li><a href="index.php">Pagina principal</a></li>
<li><a href="#">Usuarios &#187;</a>
<ul>

<li><a href="novo.php">Cadastrar</a></li>
<li><a href="lista.php">Listar</a></li>
</ul>

</li>
<li><a href="#">Centro de Distribuicao &#187;</a>
<ul>
<li><a href="novo.php">Novo centro de distribuicao</a></li>

<li><a href="lista.php">Listar centro de distribuicao</a></li>
</ul>
</li>
<li><a href="#">Estoque &#187;</a>

<ul>
<li><a href="novo.php">Novo produto em estoque</a></li>
<li><a href="lista.php">Listar produtos em estoque</a></li>

<li><a href="busca.php">Buscar item no estoque</a></li>
</ul>
</li>
</ul>
</div>

<h1>Menu sanfona com JQuery</h1>
Apenas usando as tags UL e LI.
<br />
<br />
<br />
Por: João Pinto Neto<br />
e-mail: joaopintoneto at gmail dot com

</body>
</html>

quinta-feira, 27 de novembro de 2008

Convertendo uma distro Linux para coLinux

Introdução

Neste tutorial, você aprenderá converter a sua distribuição favorita em uma distribuição para executar no coLinux. Para fazer isso, será necessário: entender um pouco de comandos no prompt do windows, um bom espaço em disco, coLinux já instalado e funcionando, o utilitário dd para windows (http://unxutils.sourceforge.net/), que realiza cópias binárias, ele criará a imagem vazia para a instalação e também o emulador de maquina virtual Qemu (http://www.qemu.com/).

Criando a imagem vazia

dd if=\\.\C: of=debian.img bs=1024000 count=4096

Quando terminar o processo, você terá uma imagem de 4G

Ripando o CD da sua distro

Se você já tiver o ISO da instalação da distribuição Linux, melhor, não será necessário este passo. Mas, para extrair, faça o seguinte (troque a letra da unidade de CD-ROM conforme necessário):

dd if=\\.\D: of=inst_debian.iso

Iniciando o instalador

qemu -L .\bios -m 128 -hda debian.img -cdrom inst_debian.iso -boot d –localtime

Apartir daqui, faça a instalação normal da distro. E quando terminar feche o Qemu.

Acertando a imagem para rodar no coLinux

dd if=debian.img of=colinux_debian bs=512 skip=63

Depois deste comando, não apague a imagem debian.img ainda, ela servirá de backup caso você faça algo errado, deixe para apagar depois de todos os passos.

Montando a imagem no coLinux

Agora, iremos montar a imagem para criar os arquivos de dispositivos necessários para montar as imagens do coLinux. Abra o arquivo de configuração para incluir a imagem da sua distro e inclua a seguinte linha alterando com a localização correta da sua imagem:
<block_device index="2" path="\DosDevices\c:\coLinux\images\colinux_debian" enabled="true"></block_device>

Inicie o coLinux, crie o diretório /mnt/tmp e monte a unidade em /mnt/tmp:
mkdir /mnt/tmp
mount -t ext3 /dev/cobd2 /mnt/tmp

Se tudo correr bem e sua imagem montar, crie os dispositivos com o comando:

for i in 0 1 2 3 4 5 6 7
do
mknod /mnt/tmp/dev/cobd$i b 117 $i
done

Copie os módulos do coLinux para a nova imagem:

cp -R /lib/modules/2.6.11-co-0.6.3 /mnt/tmp/lib/modules/2.6.11-co-0.6.3

Por último, finalize o coLinux e altere novamente o arquivo de configuração, adequando para a nova imagem:

<block_device index="0" path="\DosDevices\c:\coLinux\images\colinux_debian" enabled="true"></block_device>

Esta pronto, agora inicie sua nova distro.


Um exemplo de uma imagem convertida para coLinux é o Arch Linux 2008 06 core: