|Rodrigo Senra:
|>
|>  Acho que vc pode criar um mutator para o campo.
|>  O  AT cria setters default para cada campo, mas estes
|>  podem ser sobrescritos por rotinas suas (bem como getters).

[ Rafael Oliveira ]:
|Essa solução funcionaria sim. Porém o meu cenário é um pouco pior (eu
|não deixei muito claro): eu gostaria de ter esse comportamento para
|todos os campos de vários tipos de objetos diferentes. Ou seja, eu
|quero registrar qualquer mudança em qualquer campo.

Só no momento da criação, ou em qualquer atualização de campo ?
Pelo que vc disse, me parece ser a segunda opção, ou seja 
um hook em qualquer atualização de campo.

Eu trabalhei em uma arquitetura genérica para isso [1] em 1997
(caraca já faz 10 anos) em parceria com o lendário Alexandre Oliva
(hoje secretário da FSF para a América Latina).
Uma das lições aprendidas com isso (ainda que não fosse aplicado a
PZP) é que hooks em *tudo* são os assassinos do desempenho.
Por isso tome bastante cuidado, em geral hooks devem ser colocados
em *poucos* objetos e mediante uma escolha cuidadosa de onde colocar.

Feita essa advertência, uma forma seria no at_post_create_script()
da classe Base (da qual todos seus tipos herdam) vc coloca um 
código reflexivo que inspeciona os campos (percorrendo o atributo 
schema) e troca os getters/setters por wrappers que chamam o seu
método de hook (em pré-chain ou pós-chain) e chamam também o
getter/setter original. Não é trivial, mas também não é nada
do outro mundo. 

É preciso ter dois cuidados:

  1) evitar recursão infinita - de dentro do hook, se vc tentar
     inspecionar o campo (que está sendo interceptado) tem que 
     fazê-lo de uma forma que não redispare o acesso ao getter/setter
     que por conseguinte irá disparar uma chamada recursiva  para
     o seu hook. Uma forma fácil de detctar isso é ver a CPU em 100% e
     a memória livre indo para o saco (se não estourar o maximum recursion
     depth antes) ;o)
      
   2) O outro cuidado é não causar efeitos colaterais com os encantamentos
      do AT, CMF, ExtensionClass do Zope. 



|Como eu não preciso dessa fucionalidade urgentemente eu não parei para
|pensar na solução mais elegante.

Touché, não sei se essa é elegante tampouco.

|A primeira coisa que me veio a cabeça
|foi sobrescrever o __getattr__() das classes para interceptar as
|chamadas dos setters de todos os campos 

Acho que *não* vai funcionar, pois o __getattr__ só é chamado se
os atributos *não estiverem previamente definidos*. Ou seja, só
funciona para atributos virtuais. Nessa linha seria melhor
usar __getattribute__, que é chamado até mesmo para atributos
*já definidos*. Todavia, esta estratégia recai no problem de
"interceptar tudo" -> vai ficar uma carroça-de-boi-manco e vai
ser difícil escrever o código do hook. 
Mas, se vc quiser ir por essa linha eu ficaria *contente* 
se vc me provasse que eu estou errado a este respeito.
Toda a comunidade ganharia com isso.

[1] http://www.lsd.ic.unicamp.br/~oliva/guarana/

Abração,
Senra

-------------
Rodrigo Senra
GPr Sistemas 
http://www.gpr.com.br

Responder a