Vídeo Aula – AdvPL 018 – Modelo 1 em MVC

Olá pessoal…

Na vídeo aula de hoje irei mostrar como construir um Modelo 1 (cadastro que utiliza apenas 1 tabela) em AdvPL, utilizando o conceito de MVC.


Fonte de Exemplo:

//Bibliotecas
#Include 'Protheus.ch'
#Include 'FWMVCDef.ch'

//Variáveis Estáticas
Static cTitulo := "Artista"

/*/{Protheus.doc} zModel1
Exemplo de Modelo 1 para cadastro de Artistas
@author Atilio
@since 31/07/2016
@version 1.0
	@return Nil, Função não tem retorno
	@example
	u_zModel1()
/*/

User Function zModel1()
	Local aArea   := GetArea()
	Local oBrowse
	Local cFunBkp := FunName()
	
	SetFunName("zModel1")
	
	//Instânciando FWMBrowse - Somente com dicionário de dados
	oBrowse := FWMBrowse():New()
	
	//Setando a tabela de cadastro de Autor/Interprete
	oBrowse:SetAlias("ZZ1")

	//Setando a descrição da rotina
	oBrowse:SetDescription(cTitulo)
	
	//Legendas
	oBrowse:AddLegend( "ZZ1->ZZ1_COD <= '000005'", "GREEN",	"Menor ou igual a 5" )
	oBrowse:AddLegend( "ZZ1->ZZ1_COD >  '000005'", "RED",	"Maior que 5" )
	
	//Filtrando
	//oBrowse:SetFilterDefault("ZZ1->ZZ1_COD >= '000000' .And. ZZ1->ZZ1_COD <= 'ZZZZZZ'")
	
	//Ativa a Browse
	oBrowse:Activate()
	
	SetFunName(cFunBkp)
	RestArea(aArea)
Return Nil

/*---------------------------------------------------------------------*
 | Func:  MenuDef                                                      |
 | Autor: Daniel Atilio                                                |
 | Data:  31/07/2016                                                   |
 | Desc:  Criação do menu MVC                                          |
 *---------------------------------------------------------------------*/

Static Function MenuDef()
	Local aRot := {}
	
	//Adicionando opções
	ADD OPTION aRot TITLE 'Visualizar' ACTION 'VIEWDEF.zModel1' OPERATION MODEL_OPERATION_VIEW   ACCESS 0 //OPERATION 1
	ADD OPTION aRot TITLE 'Legenda'    ACTION 'u_zMod1Leg'      OPERATION 6                      ACCESS 0 //OPERATION X
	ADD OPTION aRot TITLE 'Incluir'    ACTION 'VIEWDEF.zModel1' OPERATION MODEL_OPERATION_INSERT ACCESS 0 //OPERATION 3
	ADD OPTION aRot TITLE 'Alterar'    ACTION 'VIEWDEF.zModel1' OPERATION MODEL_OPERATION_UPDATE ACCESS 0 //OPERATION 4
	ADD OPTION aRot TITLE 'Excluir'    ACTION 'VIEWDEF.zModel1' OPERATION MODEL_OPERATION_DELETE ACCESS 0 //OPERATION 5

Return aRot

/*---------------------------------------------------------------------*
 | Func:  ModelDef                                                     |
 | Autor: Daniel Atilio                                                |
 | Data:  31/07/2016                                                   |
 | Desc:  Criação do modelo de dados MVC                               |
 *---------------------------------------------------------------------*/

Static Function ModelDef()
	//Criação do objeto do modelo de dados
	Local oModel := Nil
	
	//Criação da estrutura de dados utilizada na interface
	Local oStZZ1 := FWFormStruct(1, "ZZ1")
	
	//Editando características do dicionário
	oStZZ1:SetProperty('ZZ1_COD',   MODEL_FIELD_WHEN,    FwBuildFeature(STRUCT_FEATURE_WHEN,    '.F.'))                                 //Modo de Edição
	oStZZ1:SetProperty('ZZ1_COD',   MODEL_FIELD_INIT,    FwBuildFeature(STRUCT_FEATURE_INIPAD,  'GetSXENum("ZZ1", "ZZ1_COD")'))         //Ini Padrão
	oStZZ1:SetProperty('ZZ1_DESC',  MODEL_FIELD_VALID,   FwBuildFeature(STRUCT_FEATURE_VALID,   'Iif(Empty(M->ZZ1_DESC), .F., .T.)'))   //Validação de Campo
	oStZZ1:SetProperty('ZZ1_DESC',  MODEL_FIELD_OBRIGAT, Iif(RetCodUsr()!='000000', .T., .F.) )                                         //Campo Obrigatório
	
	//Instanciando o modelo, não é recomendado colocar nome da user function (por causa do u_), respeitando 10 caracteres
	oModel := MPFormModel():New("zModel1M",/*bPre*/, /*bPos*/,/*bCommit*/,/*bCancel*/) 
	
	//Atribuindo formulários para o modelo
	oModel:AddFields("FORMZZ1",/*cOwner*/,oStZZ1)
	
	//Setando a chave primária da rotina
	oModel:SetPrimaryKey({'ZZ1_FILIAL','ZZ1_COD'})
	
	//Adicionando descrição ao modelo
	oModel:SetDescription("Modelo de Dados do Cadastro "+cTitulo)
	
	//Setando a descrição do formulário
	oModel:GetModel("FORMZZ1"):SetDescription("Formulário do Cadastro "+cTitulo)
Return oModel

/*---------------------------------------------------------------------*
 | Func:  ViewDef                                                      |
 | Autor: Daniel Atilio                                                |
 | Data:  31/07/2016                                                   |
 | Desc:  Criação da visão MVC                                         |
 *---------------------------------------------------------------------*/

Static Function ViewDef()
	Local aStruZZ1	:= ZZ1->(DbStruct())
	
	//Criação do objeto do modelo de dados da Interface do Cadastro de Autor/Interprete
	Local oModel := FWLoadModel("zModel1")
	
	//Criação da estrutura de dados utilizada na interface do cadastro de Autor
	Local oStZZ1 := FWFormStruct(2, "ZZ1")  //pode se usar um terceiro parâmetro para filtrar os campos exibidos { |cCampo| cCampo $ 'SZZ1_NOME|SZZ1_DTAFAL|'}
	
	//Criando oView como nulo
	Local oView := Nil

	//Criando a view que será o retorno da função e setando o modelo da rotina
	oView := FWFormView():New()
	oView:SetModel(oModel)
	
	//Atribuindo formulários para interface
	oView:AddField("VIEW_ZZ1", oStZZ1, "FORMZZ1")
	
	//Criando um container com nome tela com 100%
	oView:CreateHorizontalBox("TELA",100)
	
	//Colocando título do formulário
	oView:EnableTitleView('VIEW_ZZ1', 'Dados - '+cTitulo )  
	
	//Força o fechamento da janela na confirmação
	oView:SetCloseOnOk({||.T.})
	
	//O formulário da interface será colocado dentro do container
	oView:SetOwnerView("VIEW_ZZ1","TELA")
	
	/*
	//Tratativa para remover campos da visualização
	For nAtual := 1 To Len(aStruZZ1)
		cCampoAux := Alltrim(aStruZZ1[nAtual][01])
		
		//Se o campo atual não estiver nos que forem considerados
		If Alltrim(cCampoAux) $ "ZZ1_COD;"
			oStZZ1:RemoveField(cCampoAux)
		EndIf
	Next
	*/
Return oView

/*/{Protheus.doc} zMod1Leg
Função para mostrar a legenda
@author Atilio
@since 31/07/2016
@version 1.0
	@example
	u_zMod1Leg()
/*/

User Function zMod1Leg()
	Local aLegenda := {}
	
	//Monta as cores
	AADD(aLegenda,{"BR_VERDE",		"Menor ou igual a 5"  })
	AADD(aLegenda,{"BR_VERMELHO",	"Maior que 5"})
	
	BrwLegenda(cTitulo, "Status", aLegenda)
Return

Se quiser fazer o download desse código ou do conteúdo mostrado na vídeo aula, acesse nosso GitHub pelo link github.com/dan-atilio/AdvPL (Exemplos > Vídeo Aulas > 018 – Modelo 1 em MVC).

Bom pessoal, por hoje é só.
Abraços e até a próxima.

Dan Atilio (Daniel Atilio)
Especialista em Engenharia de Software pela FIB. Entusiasta de soluções Open Source. E blogueiro nas horas vagas.

21 Responses

  1. Artur Lima disse:

    Parabéns Daniel!

  2. Marcio disse:

    Olá. Muito bom seu post. Eu segui seu exemplo mas o menu não aparece na view. Estou usando o Protheus 11

    • Dan_Atilio disse:

      Boa noite Marcio, tudo bem?
      Você está testando no Fórmulas? Se sim, está utilizando o SetFunName?
      Lembrando que é recomendável utilizar um nome até 7 caracteres para User Function em MVC.
      Fico no aguardo.
      Abraços.

  3. Marcio disse:

    eu consegui resolver o problema chamando a função menuDef() dentro da função de usuário. Obrigado pela disponibilidade.

  4. Allan disse:

    Boa tarde eu tambem estou com este problema, e estou chamando a função diretamente pelo menu, perem a tela abre mas o menu não aparece

    Obrigado pela atenção e parabens pelo post

    • Dan_Atilio disse:

      Boa noite Allan, tudo bem?
      Você poderia verificar algumas dessas sugestões:
      – O nome do prw e da User Function deve ter 7 caracteres
      – A utilização do SetFunName
      – Chamar a função MenuDef conforme sugestão do Marcio
      Caso continue o problema, me mande o prw para eu dar uma analisada.
      Abraços.

  5. Conpasul Const Serviços disse:

    ola… bom dia, seria interessante um exemplo de reutilizacao em MVC, utilizando um webservice ou outra aplicacao de fora…. o que achas ?

  6. Teria algum exemplo de reutilizacao de codigo usando o MVC ? seria interessantissimo

  7. Rodrigues disse:

    Olá, tudo bem?
    Estou estudando suas vídeo-aulas sobre MVC. Eu baixei o fonte zModel1 e compilei, criei a tabela e ao executa-lo do menu, não mostra as opções do axcadastro, interessante se eu chamo do formulas, funciona.
    Tem um outro fonte seu, o zMVCMd1, ele está funcionando normal, abrindo o SBM, ele mostra certinho as opções do axcadastro, eu alterei ele para abrir o ZZ1, e, não mostra as opções. Mudei o modo de chamar no menu incluindo u_zModel1, recriei a tabela e etc.. Nada faz aparecer as opçoes. Tem alguma ideia do que poderia ser?

  8. Fabio Costa disse:

    Boa Tarde Atilio, esta acontecendo a mesma coisa comigo ref. aRotina nao aparecer sendo executada pelo xnu, agora quando executamos por LP-Formulas ele traz aRotina mas não traz o filtro ja fiz de tudo ate segui os seus conselhos de diminuir o nome do fonte e função para 7 posições e mesmo assim nao funciona corretamente. O que podemos fazer ? ABS. Fábio

  9. Caio disse:

    Olá Atilio
    ele traz a tela e menu.. mas quando clico em qualquer botao ele nao faz nada e retorna erro
    variable is not an object on FWFORMBROWSE:DESTROY(FWFORMBROWSE.PRW) 01/04/2020 19:16:48 line : 2434

    Muito obrigado

    segue o meu programa
    #Include ‘Protheus.ch’
    #Include ‘FWMVCDef.ch’

    //Variáveis Estáticas
    Static cTitulo := “Cadastro de Parceiros”

    User Function SBBRWSZ6()
    Local aArea := GetArea()
    Local oBrowse

    //Instânciando FWMBrowse – Somente com dicionário de dados
    oBrowse := FWMBrowse():New()

    //Setando a tabela de cadastro de Autor/Interprete
    oBrowse:SetAlias(“SZ6”)

    //Setando a descrição da rotina
    oBrowse:SetDescription(cTitulo)

    //Legendas
    oBrowse:AddLegend( “SZ6->Z6_MSBLQL == ‘2’”, “GREEN”, “Ativo” )
    oBrowse:AddLegend( “SZ6->Z6_MSBLQL == ‘1’”, “RED”, “Inativo” )

    //Ativa a Browse
    oBrowse:Activate()

    RestArea(aArea)
    Return Nil

    Static Function MenuDef()
    Local aRot := {}

    //Adicionando opções
    ADD OPTION aRot TITLE ‘Visualizar’ ACTION ‘PesqBrw’ OPERATION MODEL_OPERATION_VIEW ACCESS 0 //OPERATION 1
    ADD OPTION aRot TITLE ‘Legenda’ ACTION ‘VIEWDEF.SBBRWSZ6’ OPERATION 6 ACCESS 0 //OPERATION X
    ADD OPTION aRot TITLE ‘Incluir’ ACTION ‘VIEWDEF.SBBRWSZ6’ OPERATION MODEL_OPERATION_INSERT ACCESS 0 //OPERATION 3
    ADD OPTION aRot TITLE ‘Alterar’ ACTION ‘VIEWDEF.SBBRWSZ6’ OPERATION MODEL_OPERATION_UPDATE ACCESS 0 //OPERATION 4
    ADD OPTION aRot TITLE ‘Excluir’ ACTION ‘VIEWDEF.SBBRWSZ6’ OPERATION MODEL_OPERATION_DELETE ACCESS 0 //OPERATION 5

    Return aRot

    Static Function ModelDef()
    //Criação do objeto do modelo de dados
    Local oModel := Nil
    //Criação da estrutura de dados utilizada na interface
    Local oStSBM := FWFormStruct(1, “SZ6”)
    //Instanciando o modelo, não é recomendado colocar nome da user function (por causa do u_), respeitando 10 caracteres
    oModel := MPFormModel():New(“SBBRWSZ6”,/*bPre*/, /*bPos*/,/*bCommit*/,/*bCancel*/)
    //Atribuindo formulários para o modelo
    oModel:AddFields(“FORMSZ6”,/*cOwner*/,oStSBM)
    //Setando a chave primária da rotina
    oModel:SetPrimaryKey({‘Z6_FILIAL’,’Z6_CUPOM’})
    //Adicionando descrição ao modelo
    oModel:SetDescription(“Modelo de Dados do Cadastro “+cTitulo)
    //Setando a descrição do formulário
    oModel:GetModel(“FORMSZ6”):SetDescription(“Formulário do Cadastro “+cTitulo)
    Return oModel

    Static Function ViewDef()
    //Criação do objeto do modelo de dados da Interface do Cadastro de Autor/Interprete
    Local oModel := FWLoadModel(“SBBRWSZ6”)
    //Criação da estrutura de dados utilizada na interface do cadastro de Autor
    Local oStSBM := FWFormStruct(2, “SZ6”) //pode se usar um terceiro parâmetro para filtrar os campos exibidos { |cCampo| cCampo $ ‘SBM_NOME|SBM_DTAFAL|’}
    //Criando oView como nulo
    Local oView := Nil
    //Criando a view que será o retorno da função e setando o modelo da rotina
    oView := FWFormView():New()
    oView:SetModel(oModel)
    //Atribuindo formulários para interface
    oView:AddField(“VIEW_SZ6”, oStSBM, “FORMSZ6”)
    //Criando um container com nome tela com 100%
    oView:CreateHorizontalBox(“TELA”,100)
    //Colocando título do formulário
    oView:EnableTitleView(‘VIEW_SZ6’, ‘Dados do Grupo de Produtos’ )
    //Força o fechamento da janela na confirmação
    oView:SetCloseOnOk({||.T.})
    //O formulário da interface será colocado dentro do container
    oView:SetOwnerView(“VIEW_SZ6″,”TELA”)
    Return oView

    • Dan_Atilio disse:

      Analisando por cima, notei uma coisa, o nome da user function e do model estão iguais.
      Recomendo deixar o nome da user function e do prw iguais, ambos com 7 caracteres, por exemplo, SZ6BRW.
      Ai no seu Model, coloque um M na frente, ficando, SZ6BRW.
      Se quiser fazer um teste, entre no Autumn Code Maker, gere um código simples de cadastro em MVC.
      Link: https://autumncodemaker.com

  10. vabujamra disse:

    oModel := MPFormModel():New(“SBBRWSZ6”,/*bPre*/, /*bPos*/,/*bCommit*/,/*bCancel*/)

    Esse MODEL não pode ter mais que 7 caracteres e não pode ser o mesmo nome da Function.

    • Bom dia jovem, tudo bem?

      Acho que não entendi o comentário, se for alguma dúvida quanto ao comentário que citei, é que esse artigo e conteúdo são de agosto de 2016 (na época ainda era o Protheus 11, imagine a LIB ou outros recursos rs).

      Enfim, eu lancei um artigo em Janeiro de 2021, explicando o problema de ter o nome da function ser igual ao MPFormModel e nele eu cito que é possível sim usar 8 caracteres, mas eu recomendo para os meus alunos usarem 7, para que fique sobrando um caractere, e eles usem esse no ponto de entrada.

      O artigo que mencionei, é este: https://terminaldeinformacao.com/2021/01/06/o-que-pode-ser-quando-botoes-nao-funcionam-em-mvc/

      Se não for essa a sua dúvida, e puder detalhar o que esta acontecendo, fico à disposição também.

      Grande abraço.

Deixe uma resposta