Guia sobre o modelo de persistência (Active Record, TRecord, TRepository) do Adianti Framework.
Este guia cobre a camada de persistência orientada a objetos do Adianti Framework, baseada nos padrões Active Record e Repository.
app/config)As conexões são definidas em arquivos PHP que retornam um array de configuração.
Exemplo (erpcertificadodigital.php):
return [
'host' => "127.0.0.1",
'name' => "gestaocd",
'user' => "gestaocd",
'pass' => "TJ@123456@bd",
'type' => "mysql",
'prep' => "1" // Prepared Statements
];
TRecord)Toda classe de modelo deve estender TRecord.
[!IMPORTANT] Ao criar um modelo, TODOS os elementos abaixo devem ser incluídos quando aplicável. Nunca omita nenhum deles.
A estrutura de um modelo completo segue esta ordem obrigatória:
TABLENAME, PRIMARYKEY, IDPOLICY)CREATEDAT, UPDATEDAT, DELETEDAT)CREATEDBY, UPDATEDBY, USERBYATT)private tipadas para cada FK/associaçãoaddAttribute() para TODAS as colunas da tabelaset_/get_ para cada FK (associação N:1)get<Entidade>s()) para relações 1:N_to_string para exibição de dados relacionadosclass Pessoa extends TRecord
{
const TABLENAME = 'pessoa'; // Nome da tabela
const PRIMARYKEY = 'id'; // Chave primária
const IDPOLICY = 'serial'; // {max, serial, uuid}
// Campos automáticos de timestamp
const CREATEDAT = 'created_at';
const UPDATEDAT = 'update_at';
const DELETEDAT = 'deleted_at'; // Habilita Soft Delete
// Usuários automáticos (Template/Framework) - quando aplicável
const CREATEDBY = 'created_by';
const UPDATEDBY = 'updated_by';
const USERBYATT = 'userid'; // {userid, login, usercustomcode}
// Propriedades tipadas para cada FK/associação
private SystemUnit $system_unit;
private TipoCliente $tipo_cliente;
private SystemUsers $system_users;
private CategoriaCliente $categoria_cliente;
public function __construct($id = NULL, $callObjectLoad = TRUE)
{
parent::__construct($id, $callObjectLoad);
// TODAS as colunas da tabela, incluindo FKs e timestamps
parent::addAttribute('tipo_cliente_id');
parent::addAttribute('categoria_cliente_id');
parent::addAttribute('system_users_id');
parent::addAttribute('system_unit_id');
parent::addAttribute('nome');
parent::addAttribute('documento');
parent::addAttribute('cpf');
parent::addAttribute('telefone');
parent::addAttribute('email');
parent::addAttribute('dt_nascimento');
parent::addAttribute('aboservacao');
parent::addAttribute('obs');
parent::addAttribute('login');
parent::addAttribute('senha');
parent::addAttribute('created_at');
parent::addAttribute('update_at');
parent::addAttribute('updated_at');
parent::addAttribute('deleted_at');
}
// --- Métodos set_/get_ para cada FK (seção 5.1) ---
public function set_tipo_cliente(TipoCliente $object)
{
$this->tipo_cliente = $object;
$this->tipo_cliente_id = $object->id;
}
public function get_tipo_cliente()
{
if (empty($this->tipo_cliente))
$this->tipo_cliente = new TipoCliente($this->tipo_cliente_id);
return $this->tipo_cliente;
}
public function set_system_unit(SystemUnit $object)
{
$this->system_unit = $object;
$this->system_unit_id = $object->id;
}
public function get_system_unit()
{
if (empty($this->system_unit))
$this->system_unit = new SystemUnit($this->system_unit_id);
return $this->system_unit;
}
// --- Métodos de coleção 1:N (seção 5.2) ---
public function getPessoaEnderecos()
{
$criteria = new TCriteria;
$criteria->add(new TFilter('pessoa_id', '=', $this->id));
return PessoaEndereco::getObjects( $criteria );
}
public function getPessoaContatos()
{
$criteria = new TCriteria;
$criteria->add(new TFilter('pessoa_id', '=', $this->id));
return PessoaContato::getObjects( $criteria );
}
// --- Métodos _to_string (seção 5.4) ---
// Ver seção 5.4 para exemplos completos
}
[!CAUTION] Regras obrigatórias ao criar um modelo:
- Sempre incluir
CREATEDAT,UPDATEDATeDELETEDATse a tabela possuir essas colunas.- Sempre declarar
private <Tipo> $propriedadepara cada FK.- Sempre criar métodos
set_<nome>()eget_<nome>()para cada FK.- Sempre listar TODAS as colunas da tabela em
addAttribute(), inclusive FKs (*_id) e timestamps (created_at,updated_at,deleted_at).- Sempre criar métodos de coleção (
get<Entidade>s()) para relações 1:N.- Sempre criar métodos
_to_stringquando a model é exibida em listagens com colunas de tabelas relacionadas.
As operações são executadas dentro de uma transação (TTransaction).
TTransaction::open('erpcertificadodigital');
// Create
$p = new Pessoa;
$p->nome = 'João Silva';
$p->store();
// Load / Find
$p = new Pessoa(1); // Lança exceção se não encontrar
$p = Pessoa::find(1); // Retorna FALSE se não encontrar
// Update
$p = Pessoa::find(1);
if ($p) {
$p->nome = 'João Alterado';
$p->store();
}
// Delete
$p->delete(); // Exclusão física ou lógica (se DELETEDAT estiver definido)
Pessoa::delete(1); // Exclusão direta por ID
TTransaction::close();
TCriteria e TRepository)Para manipular conjuntos de objetos.
$criteria = new TCriteria;
$criteria->add(new TFilter('tipo_cliente_id', '=', 1));
$criteria->setProperty('order', 'nome');
$repository = new TRepository('Pessoa');
$pessoas = $repository->load($criteria);
// Atalhos estáticos (Fluent API)
$pessoas = Pessoa::where('tipo_cliente_id', '=', 1)
->orderBy('nome')
->load();
$count = Pessoa::where('cidade_id', '=', 4)->count();
set_/get_Para cada coluna FK (*_id), crie:
private tipada no topo da classeset_<nome>() / get_<nome>()// Propriedade tipada
private TipoCliente $tipo_cliente;
// Setter - permite atribuir o objeto diretamente: $pessoa->tipo_cliente = $obj;
public function set_tipo_cliente(TipoCliente $object)
{
$this->tipo_cliente = $object;
$this->tipo_cliente_id = $object->id;
}
// Getter com lazy load - permite acessar: $pessoa->tipo_cliente->nome;
public function get_tipo_cliente()
{
if (empty($this->tipo_cliente))
$this->tipo_cliente = new TipoCliente($this->tipo_cliente_id);
return $this->tipo_cliente;
}
Para cada tabela filha que referencia esta tabela, crie um método get<Entidade>s():
public function getPessoaEnderecos()
{
$criteria = new TCriteria;
$criteria->add(new TFilter('pessoa_id', '=', $this->id));
return PessoaEndereco::getObjects( $criteria );
}
O "todo" gerencia as "partes" no store, load e delete usando os métodos nativos saveComposite, loadComposite e deleteComposite.
Utiliza uma tabela associativa. Gerenciada por saveAggregate, loadAggregate e deleteComposite.
_to_string (Virtual Data)Estes métodos são usados pelo Adianti Builder para exibir dados de tabelas relacionadas em listagens (DataGrids). Para cada tabela filha (1:N) e suas respectivas FKs, crie pares set_/get_ de virtual data.
[!IMPORTANT] Estes métodos são OBRIGATÓRIOS em modelos gerados para o sistema. Sem eles, as listagens com colunas de tabelas relacionadas não funcionam.
Padrão de nomenclatura: <tabela_filha>_<fk_da_filha>_to_string
Exemplo completo (para a relação Pessoa -> PessoaEndereco -> Cidade):
// Setter: recebe array de IDs ou string direta
public function set_pessoa_endereco_cidade_to_string($pessoa_endereco_cidade_to_string)
{
if(is_array($pessoa_endereco_cidade_to_string))
{
$values = Cidade::where('id', 'in', $pessoa_endereco_cidade_to_string)->getIndexedArray('nome', 'nome');
$this->pessoa_endereco_cidade_to_string = implode(', ', $values);
}
else
{
$this->pessoa_endereco_cidade_to_string = $pessoa_endereco_cidade_to_string;
}
$this->vdata['pessoa_endereco_cidade_to_string'] = $this->pessoa_endereco_cidade_to_string;
}
// Getter: retorna os nomes concatenados da FK na tabela filha
public function get_pessoa_endereco_cidade_to_string()
{
if(!empty($this->pessoa_endereco_cidade_to_string))
{
return $this->pessoa_endereco_cidade_to_string;
}
$values = PessoaEndereco::where('pessoa_id', '=', $this->id)->getIndexedArray('cidade_id','{cidade->nome}');
return implode(', ', $values);
}
Regra geral para _to_string:
<ModelFK>::where('id', 'in', $param)->getIndexedArray('<campo_display>', '<campo_display>')<TabelaFilha>::where('<fk_para_pai>', '=', $this->id)->getIndexedArray('<fk_da_filha>','{<relacao>-><campo_display>}')$this->vdata[...] para virtual data.Os ganchos permitem interceptar o ciclo de vida da persistência para validações ou ações automáticas.
onBeforeStore($object): Antes de salvar.onAfterStore($object): Após salvar.onBeforeDelete($object): Antes de excluir. Útil para verificar dependências manuais.onAfterDelete($object): Após excluir.onBeforeLoad($id): Antes de carregar.onAfterLoad($object): Após carregar.onBeforeDelete)public function onBeforeDelete()
{
// Verifica se há registros dependentes antes de permitir a exclusão
if (ItemRelacionado::where('parent_id', '=', $this->id)->first()) {
throw new Exception("Não é possível deletar este registro pois ele possui itens relacionados.");
}
}
TTransaction::setLogger(new TLoggerTXT('log.txt')): Habilita log.TTransaction::dump(): Exibe SQL em tela.TTransaction::rollback(): Cancela operações em caso de erro.Ao criar um novo modelo TRecord, garanta que TODOS os itens abaixo sejam atendidos:
TABLENAME, PRIMARYKEY, IDPOLICY definidasCREATEDAT, UPDATEDAT, DELETEDAT definidas (se a tabela tiver essas colunas)CREATEDBY, UPDATEDBY, USERBYATT definidas (se aplicável)private <Tipo> $nome para cada FKaddAttribute() para TODAS as colunas da tabela (FKs *_id, timestamps, e campos normais)set_<nome>() e get_<nome>() para cada FK/associaçãoget<Entidade>s() para cada relação 1:N_to_string (set/get) para virtual data de tabelas filhas e suas FKsonBeforeDelete() para verificar dependências (se necessário)