Lançado Adianti Framework 8.1!
Clique aqui para saber mais
MANTER O CONTEÚDO RELACIONADO DE CAMPO TDBCombo Olá pessoal. Fiz um cadastro de veículos que possui na sua estrutura um campo de MARCA e MODELO. Estes dois são duas tabelas associadas entre si, conforme vocês podem ver na minha estrutura de tabela do banco de dados. CREATE TABLE marca ( id BIGINT UNSIGNED PRIMARY KEY NOT NULL, nome varchar(100) ) ENGINE=INNODB; CREATE TABLE modelo ( id BIGINT UNSIGNED PRIMARY KEY NOT ...
HB
MANTER O CONTEÚDO RELACIONADO DE CAMPO TDBCombo  
Olá pessoal.
Fiz um cadastro de veículos que possui na sua estrutura um campo de MARCA e MODELO. Estes dois são duas tabelas associadas entre si, conforme vocês podem ver na minha estrutura de tabela do banco de dados.

CREATE TABLE marca (
id BIGINT UNSIGNED PRIMARY KEY NOT NULL,
nome varchar(100)
) ENGINE=INNODB;

CREATE TABLE modelo (
id BIGINT UNSIGNED PRIMARY KEY NOT NULL,
nome varchar(100),
marca_id BIGINT UNSIGNED NOT NULL,
FOREIGN KEY(marca_id) REFERENCES marca(id)
) ENGINE=INNODB;

CREATE TABLE veiculo (
id BIGINT UNSIGNED PRIMARY KEY NOT NULL,
nome varchar(100),
placa varchar(100),
ano varchar(100),
pessoa_id BIGINT UNSIGNED NOT NULL,
marca_id BIGINT UNSIGNED NOT NULL,
FOREIGN KEY(pessoa_id) REFERENCES pessoa(id),
FOREIGN KEY(marca_id) REFERENCES marca(id)) ENGINE=INNODB;

Fiz uma implementação no cadastro de veículos que está no tutor (www.adianti.com.br/framework_files/tutor/index.php?class=FormHierarc), onde ao selecionar uma MARCA o TDBCombo do MODELO só carrega os modelos da marca selecionada.
A implementação em si, está funcionando, o problema está no momento de gravar, pois, o campo MODELO não mantem o conteúdo conforme vocês podem ver na imagem do anexo.

Alguém pode me ajudar a analisar o que eu tô fazendo de errado?

Grato.

  1. <?php
  2. /**
  3.  * VeiculoForm Form
  4.  * @author  <your name here>
  5.  */
  6. class VeiculoForm extends TPage
  7. {
  8.     protected $form// form
  9.     
  10.     /**
  11.      * Form constructor
  12.      * @param $param Request
  13.      */
  14.     public function __construct$param )
  15.     {
  16.         parent::__construct();
  17.         
  18.         // creates the form
  19.         $this->form = new BootstrapFormBuilder('form_Veiculo');
  20.         $this->form->setFormTitle('Veículos');
  21.         
  22.         // create the form fields
  23.         $id        = new TEntry('id');
  24.         $nome      = new TEntry('nome');
  25.         $placa     = new TEntry('placa');
  26.         $ano       = new TEntry('ano');
  27.         $pessoa_id = new TDBCombo('pessoa_id''microerp''Pessoa''id''{nome}','id asc'  );
  28.         $marca_id  = new TDBCombo('marca_id''microerp''Marca''id''{nome}','id asc'  );
  29.         $modelo_id = new TDBCombo('modelo_id''microerp''Modelo''id''{nome}','id asc'  );
  30.         
  31.         /*INICIO DA IMPLEMENTAÇÃO MARCA -> MODELO*/
  32.         $filter = new TCriteria;
  33.         $filter->add(new TFilter('id''<''0'));
  34.         $modelo_id = new TDBCombo('modelo_id''microerp''Modelo''id''{nome}''nome'$filter);
  35.         
  36.         $marca_id->setChangeAction( new TAction( array($this'onMarcaChange' )) );
  37.         
  38.         $nome->addValidation('Descrição', new TRequiredValidator());
  39.         $pessoa_id->addValidation('Proprietário', new TRequiredValidator());
  40.         $marca_id->addValidation('Marca', new TRequiredValidator()); 
  41.         /*FIM DA IMPLEMENTAÇÃO MARCA -> MODELO*/
  42.         
  43.         $id->setEditable(false);
  44.         $id->setSize(100);
  45.         $nome->setSize('59%');
  46.         $placa->setSize('45%');
  47.         $ano->setSize('45%');
  48.         $pessoa_id->setSize('34%');
  49.         $marca_id->setSize('90%');
  50.         $modelo_id->setSize('90%');
  51.         $nome->forceUpperCase();
  52.         $placa->setMask('SSS-9999');
  53.         $ano->setMask('9999');
  54.         $id->setEditable(FALSE);
  55.         
  56.         
  57.         $this->form->addFields([new TLabel('Código:')],[$id]);
  58.         $this->form->addFields([new TLabel('Descrição:''#ff0000')],[$nome]);
  59.         $this->form->addFields([new TLabel('Placa:')],[$placa],[new TLabel('Ano:')],[$ano]);
  60.         $this->form->addFields([new TLabel('Marca:''#ff0000')],[$marca_id],[new TLabel('Modelo:')],[$modelo_id]);
  61.         $this->form->addFields([new TLabel('Proprietário:''#ff0000')],[$pessoa_id]);
  62.         // create the form actions
  63.         $this->form->addAction('Salvar', new TAction([$this'onSave']), 'fa:floppy-o')->addStyleClass('btn-primary');
  64.         $this->form->addAction('Limpar formulário', new TAction([$this'onClear']), 'fa:eraser #dd5a43');
  65.         //$this->form->addAction(_t('Back'),new TAction(array('VeiculoList','onReload')),'fa:arrow-circle-o-left blue');
  66.         // vertical box container
  67.         $container = new TVBox;
  68.         $container->style 'width: 100%';
  69.         $container->class 'form-container';
  70.         //$container->add(new TXMLBreadCrumb('menu.xml', 'VeiculoList'));
  71.         $container->add($this->form);
  72.         
  73.         parent::add($container);
  74.     }
  75.     
  76.      /* MARCA -> MODELO*/
  77.     public static function onMarcaChange($param)
  78.     {
  79.         try
  80.         {
  81.             TTransaction::open('microerp');
  82.             if ($param['marca_id'])
  83.             {
  84.                 $criteria TCriteria::create( ['marca_id' => $param['marca_id'] ] );
  85.                 
  86.                 // formname, field, database, model, key, value, ordercolumn = NULL, criteria = NULL, startEmpty = FALSE
  87.                 TDBCombo::reloadFromModel('form_Veiculo''modelo_id''microerp''Modelo''id''{nome}''nome'$criteriaTRUE);
  88.             }
  89.             else
  90.             {
  91.                 TCombo::clearField('form_Veiculo''marca_id');
  92.             }
  93.             
  94.             TTransaction::close();
  95.         }
  96.         catch (Exception $e)
  97.         {
  98.             new TMessage('error'$e->getMessage());
  99.         }
  100.     }
  101.     /**
  102.      * Save form data
  103.      * @param $param Request
  104.      */
  105.     public function onSave$param )
  106.     {
  107.         try
  108.         {
  109.             TTransaction::open('microerp'); // open a transaction
  110.             
  111.             /**
  112.             // Enable Debug logger for SQL operations inside the transaction
  113.             TTransaction::setLogger(new TLoggerSTD); // standard output
  114.             TTransaction::setLogger(new TLoggerTXT('log.txt')); // file
  115.             **/
  116.             
  117.             $this->form->validate(); // validate form data
  118.             
  119.             $object = new Veiculo;  // create an empty object
  120.             $data $this->form->getData(); // get form data as array
  121.             $object->fromArray( (array) $data); // load the object with data
  122.             $object->store(); // save the object
  123.             
  124.             // get the generated id
  125.             $data->id $object->id;
  126.             
  127.             $this->form->setData($data); // fill form data
  128.             
  129.             $this->fireEvents$object );
  130.             
  131.             TTransaction::close(); // close the transaction
  132.             
  133.             new TMessage('info'TAdiantiCoreTranslator::translate('Record saved'));
  134.         }
  135.         catch (Exception $e// in case of exception
  136.         {
  137.             new TMessage('error'$e->getMessage()); // shows the exception error message
  138.             $this->form->setData$this->form->getData() ); // keep form data
  139.             TTransaction::rollback(); // undo all pending operations
  140.         }
  141.     }
  142.     
  143.     /**
  144.      * Clear form data
  145.      * @param $param Request
  146.      */
  147.     public function onClear$param )
  148.     {
  149.         $this->form->clear(TRUE);
  150.     }
  151.     
  152.     /**
  153.      * Fire form events
  154.      * @param $param Request
  155.      */
  156.     public function fireEvents$object )
  157.     {
  158.         $obj = new stdClass;
  159.         $obj->marca_id $object->marca_id;
  160.         $obj->modelo_id $object->modelo_id;
  161.         TForm::sendData('form_Veiculo'$obj);
  162.     }
  163.     
  164.     
  165.     /**
  166.      * Load object to form data
  167.      * @param $param Request
  168.      */
  169.     public function onEdit$param )
  170.     {
  171.         try
  172.         {
  173.             if (isset($param['key']))
  174.             {
  175.                 $key $param['key'];  // get the parameter $key
  176.                 TTransaction::open('microerp'); // open a transaction
  177.                 $object = new Veiculo($key); // instantiates the Active Record
  178.                 $this->form->setData($object); // fill the form
  179.                 TTransaction::close(); // close the transaction
  180.                 
  181.                 $this->fireEvents$object );
  182.                 
  183.             }
  184.             else
  185.             {
  186.                 $this->form->clear(TRUE);
  187.             }
  188.         }
  189.         catch (Exception $e// in case of exception
  190.         {
  191.             new TMessage('error'$e->getMessage()); // shows the exception error message
  192.             TTransaction::rollback(); // undo all pending operations
  193.         }
  194.     }
  195. }
  196. ?>

Curso Dominando o Adianti Framework

O material mais completo de treinamento do Framework.
Curso em vídeo aulas + Livro completo + Códigos fontes do projeto ERPHouse.
Conteúdo Atualizado!


Dominando o Adianti Framework Quero me inscrever agora!

Comentários (7)


NR

Você atualizou pra versão 5? Se ainda estiver na 4, pelo que vi a função reloadFromModel não interpreta as chaves do parâmetro value:
  1. <?php
  2. TDBCombo::reloadFromModel('form_Veiculo''modelo_id''microerp''Modelo''id''{nome}''nome'$criteriaTRUE); //so funciona na 5
  3. TDBCombo::reloadFromModel('form_Veiculo''modelo_id''microerp''Modelo''id''nome''nome'$criteriaTRUE); // funciona na 4
  4. ?>
HB

Olá Nataniel.
Bom, fiz a atualização do Studio Pro para versão 5.0, então imagino que estou com o framawork na 5.0 também, uma vez que quando adquiri o Studio Pro 4.0 não precisei instalar o framawork.

Mais fiz o teste sem as chaves e não funcionou também.

Sabe me dizer uma forma de verificar em qual versão do framawork eu estou?
NR

Se você iniciou o projeto após a atualização do Studio ele está na versão 5, mas você consegue confirmar verificando os cabeçalhos das classes do Adianti:
  1. <?php
  2. /**
  3.  * HTML Document parser
  4.  *
  5.  * @version    5.0
  6. ?>

Eu adaptei seu código pra minha base de dados e funcionou certinho.

Analise o retorno da requisição ao clicar no salvar pelo console do Chrome(F12) e veja se descobre algo
HB

Nataniel,
Confirmei e realmente estou na versão 5.0

Fiz um F12 no Chrome, e se eu estiver fazendo certo, o método onMarcaChange não passa o id do Modelo.
Confesso que não sei se é esse o problema.
Baixei a aplicação TUTOR na minha máquina e fiz o F12 pra ver o comportamento do TUTOR, e conforme você pode ver abaixo, o TUTOR faz a mesma coisa.

Debug do TUTOR
O resultado abaixo é do momento que cliquei no combo State e o F12 retorna as informações abaixo:

class:FormHierarchicalComboView
method:onStateChange
static:1
Form Data
view source
view URL encoded

id:
name:TUTOR
state_id:1
city_id:
_field_id:tcombo_1114096307
_field_name:state_id
_field_value:1
_field_data:
key:1
ajax_lookup:1


Depois de selecionar a cidade (City), e em seguida pressionar o botão Salvar o F12 retorna as informações abaixo:

class:FormHierarchicalComboView
method:onSave
Form Data
view source
view URL encoded

id:
name:TUTOR
state_id:1
city_id:3


E no final a aplicação TUTOR aciona o método onStateChange novamente e o F12 retorna as informações abaixo:

class:FormHierarchicalComboView
method:onStateChange
static:1
Form Data
view source
view URL encoded
id:1
name:TUTOR
state_id:1
city_id:
_field_id:tcombo_1821886345
_field_name:state_id
_field_value:1
_field_data:
key:1


Já a minha aplicação, pelo que percebi, está fazendo a mesma coisa, e daí não sei realmente o que pode estar errado.

Debug da MINHA APLICAÇÃO
O resultado abaixo é do momento que cliquei no combo Marca e o F12 retorna as informações abaixo:

class:VeiculoForm
method:onMarcaChange
static:1
Form Data
view source
view URL encoded

id:
nome:FIESTA
placa:ETX-3333
ano:2015
marca_id:1
modelo_id:
pessoa_id:
_field_value:1
_field_id:tcombo_1026238825
_field_name:marca_id
_form_name:form_Veiculo
_field_data:
key:1
ajax_lookup:1


Depois de selecionar o Modelo, e em seguida pressionar o botão Salvar o F12 retorna as informações abaixo:

id:
nome:FIESTA
placa:ETX-3333
ano:2015
marca_id:1
modelo_id:1
pessoa_id:1


E no final a aplicação aciona o método onMarcaChange novamente e o F12 retorna as informações abaixo:

class:VeiculoForm
method:onMarcaChange
static:1
Form Data
view source
view URL encoded

id:1
nome:FIESTA
placa:ETX-3333
ano:2015
marca_id:1
modelo_id:
pessoa_id:1
_field_value:1
_field_id:tcombo_1794633002
_field_name:marca_id
_form_name:form_Veiculo
_field_data:
key:1
ajax_lookup:1


E aí consegue me ajudar?
NR

Pelo sql que você passou, o campo modelo_id não está no model Veiculos, correto? Nesse caso, a função fromArray desconsidera esse campo e com isso ele não é passado para a variável $object. Adicione esse atributo manualmente antes de chamar a fireEvents:
  1. <?php
  2. $object->modelo_id $data->modelo_id;
  3. $this->fireEvents$object );
  4. ?>
HB

Olá Nataniel.

É isso mesmo, minha tabela de VEICULO só tem a MARCA.
A minha tabela de MODELO tenho a chave estrangeira de MARCA, porque entendo que uma MARCA pode ter varios MODELOS, assim, a medida que eu vou cadastrando o(s) MODELO(s) vou associando a respectiva MARCA.

A forma que você me indicou acima pra fazer ($object->modelo_id = $data->modelo_id; ) funcionou direitinho no onSave, mais no onEdit não deu certo.

Desta forma tenho as seguintes dúvidas para que você me ajude:

1) No caso do onEdit como eu faço?

2) Como ainda estou iniciando meus entendimentos do framework, neste caso, e em outros que eu possa ter, fica mais correto eu gravar também o MODELO no veículo?
Caso sua resposta seja SIM, gostaria de entender melhor como gravar o MODELO no VEÍCULO, pois, o MODELO e a MARCA são associados diretos. Fazendo assim, eu acredito que posso controlar melhor o usuário, ou seja, ele só vai selecionar o MODELO específico daquela MARCA. Mais como só vou obter o MODELO no momento da INSERÇÃO do veículo, confesso que não sei como gravar o código do MODELO escolhido pelo usuário no respectivo VEICULO. Como fazer isso em tempo de execução?
NR

2 - Sim, eu gravaria o modelo ao invés da marca na tabela veiculo. Não vejo necessidade de manter o campo marca nessa tabela, visto que através do modelo você consegue recuperar essa informação(crie uma associação entre veiculo e modelo). Na questão da gravação não muda nada, pois esse campo já está no formulário e assim que você adicioná-lo ao model Veiculo ele passará a ser reconhecido pelas funções(fromArray, store).

1 - Na função onEdit você continuará chamando a função fireEvents, mas dessa vez vai ter que buscar a informação da marca através do modelo, via associação:
  1. <?php
  2. // criar associacao entre veiculo e modelo
  3. $object->marca_id $object->modelo->marca_id;
  4. $this->fireEvents$object );
  5. ?>