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

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', $criteria, TRUE); //so funciona na 5
  3. TDBCombo::reloadFromModel('form_Veiculo', 'modelo_id', 'microerp', 'Modelo', 'id', 'nome', 'nome', $criteria, TRUE); // 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. ?>