Transformação de Dados

Artigo que mostra os problemas encontrados para transformação de dados entre as camadas de uma aplicação de forma a torná-lo o mais extensível possível e que permita a internacionalização.

Ao desenvolver uma grande aplicação ou um framework Web, é preciso ter consciência de que precisará trabalhar com camadas e que fará várias conversões entre estas camadas para manter o sistema portável. Vamos observar a imagem abaixo:

Conversão de dados entre camadas do sistema

Apesar de ser possível utilizar a mesma notação para representar números reais no formulário, na aplicação e no BD, pode ser que o usuário esteja em uma localidade que usa uma notação diferente da americana (usada no PHP), e pode ser que o BD não utilize a mesma notação que a aplicação para todos tipos de dados. Portanto, é importante realizar a transformação de dados entre as camadas do sistema.

Partindo do usuário, devemos considerar que ele está em uma localidade. É interessante que este usuário utilize a notação usada pela sua localidade para representar números, datas, etc. Para isso, é importante conhecer algumas funções:

  • setlocale - define a notação de uma localidade, que será usada para exibir valores numéricos, monetários, etc.
  • localeconv - devolve um array com informações sobre a localidade definida com setlocale.
  • number_format - permite formatar um número com símbolos personalizados.
  • money_format - formata um valor monetário de acordo com a localidade definida com setlocale.
  • strftime e gmstrftime - formatam datas (alguns valores são afetados pela localidade definida em setlocale).
  • strcoll - compara duas strings de acordo com a localidade definida em setlocale.

Exemplo:

// Definindo localidade do Brasil no Linux
setlocale(LC_ALL, 'pt_BR.UTF-8');

// Obtendo informacoes sobre a localidade
$conv = localeconv();

// Exibindo um numero de acordo com a localidade
echo number_format(1234.567, 3, $conv['decimal_point'], $conv['thousands_sep']);

// Montando uma expressao regular para checar se foi passado um numero real
$sinal = preg_quote($conv['positive_sign'].$conv['negative_sign']);
$milhar = preg_quote($conv['thousands_sep']);
$decimal = preg_quote($conv['decimal_point']);
$exp = "/^([{$sinal}]?)(\d{1,3}([{$milhar}]\d{3})*)([{$decimal}]\d+)?$/";

$valor = '1.234,56';
if (preg_match($exp, $valor)) {
    // Valor valido
}

Para converter o valor real passado na notação da localidade, é preciso adaptar a expressão regular para recuperar as componentes do número individualmente (separar o sinal, porção inteira e porção decimal), depois formatá-los com a notação do PHP, depois realizar o casting para float.

Desta maneira, o seu objeto na camada da aplicação fica com os valores padronizados no formato do PHP, mas quando precisa ser mostrado para o usuário, você pode convertê-los novamente para a notação que ele está adaptado.

Seguindo a mesma lógica, é importante que a ligação entre a aplicação e o Banco de Dados também seja feita a conversão de valores. Primeiro, para a aplicação passar um valor para o banco (através da montagem da SQL de INSERT ou UPDATE) e, depois, para converter um valor recebido do BD e jogá-lo no objeto da aplicação (recuperar um resultado de um SELECT e convertê-lo para notação PHP). Isso porque os dados recuperados de um SELECT costumam ser trazidos na forma de string ou NULL, em alguns casos. Porém, alguns destes campos representam números e é importante convertê-los para o padrão do PHP para que possíveis contas sejam realizadas sem problemas.

A conversão entre aplicação e BD costuma ser mais simples, pois os SGBDs normalmente usam a notação americana com algumas pequenas diferenças. Para realizar tais conversões, é preciso conhecer a sintaxe do BD. Por exemplo, no MySQL, valores booleanos são implementados na forma de um inteiro (TINYINT), que pode assumir valor 1 e 0 (representando true e false respectivamente). Já no PostgreSQL, existe o campo BOOL que pode assumir TRUE e FALSE, porém, em uma consulta, são devolvidos os valores "t" e "f". Ambas, se forem convertidas com casting para bool do PHP assumiriam o valor "true", caracterizando um erro de implementação. O correto é verificar se o valor vale "t" ou "f", conforme exemplo:

// Recuperando um registro do BD
$registro = $pdo->fetchObject();

// Criando um objeto da aplicacao (ORM)
$usuario = new usuario();

// Testando o tipo de um atributo
switch ($tipo_atributo) {
case 'bool':
    $usuario->comprovou = ($registro->comprovou == 't');
    break;
...

Ou seja, cada driver de conexão com o BD deve implementar seu método de conversão da aplicação para o banco e do banco para aplicação. Isso tudo depende de um ORM com tipos bem definidos, para que os tipos usados no PHP possam ser convertidos e recuperados num BD relacional.

0 comentários