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.
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.
- <?php
- /**
- * VeiculoForm Form
- * @author <your name here>
- */
- class VeiculoForm extends TPage
- {
- protected $form; // form
- /**
- * Form constructor
- * @param $param Request
- */
- public function __construct( $param )
- {
- parent::__construct();
- // creates the form
- $this->form = new BootstrapFormBuilder('form_Veiculo');
- $this->form->setFormTitle('Veículos');
- // create the form fields
- $id = new TEntry('id');
- $nome = new TEntry('nome');
- $placa = new TEntry('placa');
- $ano = new TEntry('ano');
- $pessoa_id = new TDBCombo('pessoa_id', 'microerp', 'Pessoa', 'id', '{nome}','id asc' );
- $marca_id = new TDBCombo('marca_id', 'microerp', 'Marca', 'id', '{nome}','id asc' );
- $modelo_id = new TDBCombo('modelo_id', 'microerp', 'Modelo', 'id', '{nome}','id asc' );
- /*INICIO DA IMPLEMENTAÇÃO MARCA -> MODELO*/
- $filter = new TCriteria;
- $filter->add(new TFilter('id', '<', '0'));
- $modelo_id = new TDBCombo('modelo_id', 'microerp', 'Modelo', 'id', '{nome}', 'nome', $filter);
- $marca_id->setChangeAction( new TAction( array($this, 'onMarcaChange' )) );
- $nome->addValidation('Descrição', new TRequiredValidator());
- $pessoa_id->addValidation('Proprietário', new TRequiredValidator());
- $marca_id->addValidation('Marca', new TRequiredValidator());
- /*FIM DA IMPLEMENTAÇÃO MARCA -> MODELO*/
- $id->setEditable(false);
- $id->setSize(100);
- $nome->setSize('59%');
- $placa->setSize('45%');
- $ano->setSize('45%');
- $pessoa_id->setSize('34%');
- $marca_id->setSize('90%');
- $modelo_id->setSize('90%');
- $nome->forceUpperCase();
- $placa->setMask('SSS-9999');
- $ano->setMask('9999');
- $id->setEditable(FALSE);
- $this->form->addFields([new TLabel('Código:')],[$id]);
- $this->form->addFields([new TLabel('Descrição:', '#ff0000')],[$nome]);
- $this->form->addFields([new TLabel('Placa:')],[$placa],[new TLabel('Ano:')],[$ano]);
- $this->form->addFields([new TLabel('Marca:', '#ff0000')],[$marca_id],[new TLabel('Modelo:')],[$modelo_id]);
- $this->form->addFields([new TLabel('Proprietário:', '#ff0000')],[$pessoa_id]);
- // create the form actions
- $this->form->addAction('Salvar', new TAction([$this, 'onSave']), 'fa:floppy-o')->addStyleClass('btn-primary');
- $this->form->addAction('Limpar formulário', new TAction([$this, 'onClear']), 'fa:eraser #dd5a43');
- //$this->form->addAction(_t('Back'),new TAction(array('VeiculoList','onReload')),'fa:arrow-circle-o-left blue');
- // vertical box container
- $container = new TVBox;
- $container->style = 'width: 100%';
- $container->class = 'form-container';
- //$container->add(new TXMLBreadCrumb('menu.xml', 'VeiculoList'));
- $container->add($this->form);
- parent::add($container);
- }
- /* MARCA -> MODELO*/
- public static function onMarcaChange($param)
- {
- try
- {
- TTransaction::open('microerp');
- if ($param['marca_id'])
- {
- $criteria = TCriteria::create( ['marca_id' => $param['marca_id'] ] );
- // formname, field, database, model, key, value, ordercolumn = NULL, criteria = NULL, startEmpty = FALSE
- TDBCombo::reloadFromModel('form_Veiculo', 'modelo_id', 'microerp', 'Modelo', 'id', '{nome}', 'nome', $criteria, TRUE);
- }
- else
- {
- TCombo::clearField('form_Veiculo', 'marca_id');
- }
- TTransaction::close();
- }
- catch (Exception $e)
- {
- new TMessage('error', $e->getMessage());
- }
- }
- /**
- * Save form data
- * @param $param Request
- */
- public function onSave( $param )
- {
- try
- {
- TTransaction::open('microerp'); // open a transaction
- /**
- // Enable Debug logger for SQL operations inside the transaction
- TTransaction::setLogger(new TLoggerSTD); // standard output
- TTransaction::setLogger(new TLoggerTXT('log.txt')); // file
- **/
- $this->form->validate(); // validate form data
- $object = new Veiculo; // create an empty object
- $data = $this->form->getData(); // get form data as array
- $object->fromArray( (array) $data); // load the object with data
- $object->store(); // save the object
- // get the generated id
- $data->id = $object->id;
- $this->form->setData($data); // fill form data
- $this->fireEvents( $object );
- TTransaction::close(); // close the transaction
- new TMessage('info', TAdiantiCoreTranslator::translate('Record saved'));
- }
- catch (Exception $e) // in case of exception
- {
- new TMessage('error', $e->getMessage()); // shows the exception error message
- $this->form->setData( $this->form->getData() ); // keep form data
- TTransaction::rollback(); // undo all pending operations
- }
- }
- /**
- * Clear form data
- * @param $param Request
- */
- public function onClear( $param )
- {
- $this->form->clear(TRUE);
- }
- /**
- * Fire form events
- * @param $param Request
- */
- public function fireEvents( $object )
- {
- $obj = new stdClass;
- $obj->marca_id = $object->marca_id;
- $obj->modelo_id = $object->modelo_id;
- TForm::sendData('form_Veiculo', $obj);
- }
- /**
- * Load object to form data
- * @param $param Request
- */
- public function onEdit( $param )
- {
- try
- {
- if (isset($param['key']))
- {
- $key = $param['key']; // get the parameter $key
- TTransaction::open('microerp'); // open a transaction
- $object = new Veiculo($key); // instantiates the Active Record
- $this->form->setData($object); // fill the form
- TTransaction::close(); // close the transaction
- $this->fireEvents( $object );
- }
- else
- {
- $this->form->clear(TRUE);
- }
- }
- catch (Exception $e) // in case of exception
- {
- new TMessage('error', $e->getMessage()); // shows the exception error message
- TTransaction::rollback(); // undo all pending operations
- }
- }
- }
- ?>
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:
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?
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:
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
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?
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:
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?
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: