Software Development Kit
to the Delphi-Win32 and Free Pascal compilers
Home > Wiki > br/Criando atributos

br/Criando atributos

english (en) | português (br)

Os atributos de usuário são criados quando há necessidade de distribuir a mesma funcionalidade para diversas classes diferentes, ou quando é necessário alguma customização que não é prevista (ou sequer é possível de prever) pelo framework Data Type do PressObjects.

Exemplos: é possível criar um atributo TTelefone que formata um número de telefone com parênteses, espaço e traço; ou TCPF que faz a checagem da entrada para verificar se o dígito está correto e formatar a saída; ou ainda para atributos container (estilo mestre-detalhe), para que seus métodos apontem para a classe correta e façam proveito da tipagem forte do Object Pascal.

Contents

Criando um atributo

A criação de um atributo está dividida em três passos simples:

  • Crie a classe, herdando de um atributo existente
  • Sobrecarregue métodos virtuais para alterar o comportamento do atributo
    • Para atributos container (Parts e References), o método ValidObjectClass deve ser implementado sempre
  • Registre o método na área initialization da unit e remova o registro na área finalization

Atributos simples

São todos os atributos que não descendem de TPressStructure, ou seja, não são nem agregações nem composições (chaves estrangeiras ou mestre-detalhe)

Verificando a entrada do usuário

O exemplo a seguir cria um atributo que verifica a entrada do usuário:

TCPF = class(TPressString)
protected
  procedure SetValue(const AValue: string); override;
end;

...

procedure TCPF.SetValue(const AValue: string);
begin
  if not IsValidCPF(AValue) then
    // erro
  inherited;
end;

...

initialization
  TCPF.RegisterAttribute;

finalization
  TCPF.UnregisterAttribute;

Para usar o novo atributo em uma classe de negócio:

TCliente = class(TPressObject)
  _CPF: TCPF;
protected
  class function InternalMetadataStr: string; override;
end;

...

class function InternalMetadataStr: string;
begin
  Result := 'TCliente IsPersistent (' +
   'CPF: TCPF;' +
   ')';
end;

A partir de agora, sempre que o CPF for alterado (através do MVP ou associando um novo valor diretamente no objeto), a rotina será chamada para validar a entrada.

Formatando a apresentação dos dados

Para formatar a apresentação, basta seguir as informações da seção anterior e sobrecarregar o método GetDisplayText, conforme o exemplo a seguir:

TTelefone = class(TPressString)
protected
  function GetDisplayText: string; override;
end;

...

function TTelefone.GetDisplayText: string;
begin
  Result := FormataFone(Value);
end;

Além de registrar o componente e utilizar nos objetos de negócio apropriadamente.

Sempre que o foco estiver fora do componente, o conteúdo formatado é quem será usado ao invés do conteúdo nativo.

Atributos containeres

Um dos grandes benefícios de se registrar um atributo container é poder contar com a tipagem forte do compilador e validar o uso de métodos para manutenção do container. Para o seguinte exemplo:

var
  VItem: TPedidoItem;
begin
  VItem := APedido.Itens.Add;

o compilador irá reclamar porque o método Add retorna um TPressObject, que é a base para todos os objeto de negócio. No entanto estamos manipulando um item de pedido, nós sabemos disso, e esta situação obriga o uso de cast para que o compilador possa validar a sentença.

Ao invés disto é possível criar uma nova classe que entenda nosso container:

TPedidoItemParts = class(TPressParts)
public
  function Add: TPedidoItem;
  class function ValidObjectClass: TPressObjectClass; override;
end;

...

function TPedidoItemParts.Add: TPedidoItem;
begin
  Result := inherited Add as TPedidoItem;
end;

class function TPedidoItemParts.ValidObjectClass: TPressObjectClass;
begin
  Result := TPedidoItem;
end;

...

initialization
  TPedidoItemParts.RegisterAttribute;

finalization
  TPedidoItemParts.UnregisterAttribute;
end;

Obs.: o método ValidObjectClass deve sempre ser sobrecarregado e deve apontar para a classe-alvo correta.

Agora basta utilizar o novo atributo na classe de negócio. Note a declaração do metadata e também do acessor deste atributo na declaração da própria classe:

TPedido = class(TPressObject)
  _Itens: TPedidoItemParts;
protected
  class function InternalMetadataStr: string;
public
  property Itens: TPedidoItemParts read _Itens;
end;

...

class function TPedido.InternalMetadataStr: string;
begin
  Result := 'TPedido IsPersistent (' +
   'Itens: TPedidoItemParts;' +
   ')';
end;