Como utilizar a FWModelEvent no lugar do Commit em uma rotina MVC

No artigo de hoje, vamos demonstrar em como substituir o bloco bCommit com um InstallEvent.

Ao passar os códigos pelo Code Analysis, os fontes em MVC que possuem o bloco de código no Commit das operações é acusado de que isso não é recomendado.

Até podemos criar um ponto de entrada com o nome do MPFormModel e usar os pontos MODELCOMMITTTS ou MODELCOMMITNTTS.

Mas a intenção desse artigo é demonstrar em como utilizar o recurso InstallEvent, que é o recomendado pela TOTVS.

Primeiro, iremos ver, como que esta o fonte de forma original, usando o bCommit:

//Bibliotecas
#Include "Totvs.ch"
#Include "FWMVCDef.ch"

//Variveis Estaticas
Static cTitulo := "Artistas (com Commit Manual)"
Static cAliasMVC := "ZD1"

/*/{Protheus.doc} User Function zMVC01b
Cadastro de Artistas
@author Daniel Atilio
@since 21/01/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

User Function zMVC01b()
	Local aArea   := GetArea()
	Local oBrowse
	Private aRotina := {}

	//Definicao do menu
	aRotina := MenuDef()

	//Instanciando o browse
	oBrowse := FWMBrowse():New()
	oBrowse:SetAlias(cAliasMVC)
	oBrowse:SetDescription(cTitulo)
	oBrowse:DisableDetails()

	//Ativa a Browse
	oBrowse:Activate()

	RestArea(aArea)
Return Nil

/*/{Protheus.doc} MenuDef
Menu de opcoes na funcao zMVC01b
@author Daniel Atilio
@since 21/01/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function MenuDef()
	Local aRotina := {}

	//Adicionando opcoes do menu
	ADD OPTION aRotina TITLE "Visualizar" ACTION "VIEWDEF.zMVC01b" OPERATION 1 ACCESS 0
	ADD OPTION aRotina TITLE "Incluir" ACTION "VIEWDEF.zMVC01b" OPERATION 3 ACCESS 0
	ADD OPTION aRotina TITLE "Alterar" ACTION "VIEWDEF.zMVC01b" OPERATION 4 ACCESS 0
	ADD OPTION aRotina TITLE "Excluir" ACTION "VIEWDEF.zMVC01b" OPERATION 5 ACCESS 0

Return aRotina

/*/{Protheus.doc} ModelDef
Modelo de dados na funcao zMVC01b
@author Daniel Atilio
@since 21/01/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function ModelDef()
	Local oStruct := FWFormStruct(1, cAliasMVC)
	Local oModel
	Local bPre := Nil
	Local bPos := Nil
	Local bCommit := {|| fFazCommit()}
	Local bCancel := Nil

	//Cria o modelo de dados para cadastro
	oModel := MPFormModel():New("zMVC01bM", bPre, bPos, bCommit, bCancel)
	oModel:AddFields("ZD1MASTER", /*cOwner*/, oStruct)
	oModel:SetDescription("Modelo de dados - " + cTitulo)
	oModel:GetModel("ZD1MASTER"):SetDescription( "Dados de - " + cTitulo)
	oModel:SetPrimaryKey({})
Return oModel

/*/{Protheus.doc} ViewDef
Visualizacao de dados na funcao zMVC01b
@author Daniel Atilio
@since 21/01/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function ViewDef()
	Local oModel := FWLoadModel("zMVC01b")
	Local oStruct := FWFormStruct(2, cAliasMVC)
	Local oView

	//Cria a visualizacao do cadastro
	oView := FWFormView():New()
	oView:SetModel(oModel)
	oView:AddField("VIEW_ZD1", oStruct, "ZD1MASTER")
	oView:CreateHorizontalBox("TELA" , 100 )
	oView:SetOwnerView("VIEW_ZD1", "TELA")

Return oView

Static Function fFazCommit()
    Local aArea  := FWGetArea()
    Local oModel := FWModelActive()
    Local lRet   := .T.

    //Aqui você pode fazer as operações antes de gravar

    //Aciona o commit dos dados preenchidos no formulário
    FWFormCommit(oModel)

    //Aqui você pode fazer as operações após gravar

    //Exibe uma mensagem, caso não esteja sendo executado via job ou ws
    If ! IsBlind()
        ShowLog("Passei pelo Commit de forma manual (antiga)")
    EndIf

    FWRestArea(aArea)
Return lRet

Notaram que no ModelDef tem um bloco bCommit com uma função chamada fFazCommit.

Agora como podemos adaptar isso sem utilizar mais esse bloco? Abaixo iremos detalhar o procedimento.

O primeiro passo é no fonte em MVC, remover o bCommit, remover a função fFazCommit, e no seu ModelDef adicionar o método InstallEvent apontando para uma classe customizada (aqui chamamos ela de zSuaClasse).

//Bibliotecas
#Include "Totvs.ch"
#Include "FWMVCDef.ch"

//Variveis Estaticas
Static cTitulo := "Artistas (com FWModelEvent)"
Static cAliasMVC := "ZD1"

/*/{Protheus.doc} User Function zMVC01c
Cadastro de Artistas
@author Daniel Atilio
@since 21/01/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

User Function zMVC01c()
	Local aArea   := GetArea()
	Local oBrowse
	Private aRotina := {}

	//Definicao do menu
	aRotina := MenuDef()

	//Instanciando o browse
	oBrowse := FWMBrowse():New()
	oBrowse:SetAlias(cAliasMVC)
	oBrowse:SetDescription(cTitulo)
	oBrowse:DisableDetails()

	//Ativa a Browse
	oBrowse:Activate()

	RestArea(aArea)
Return Nil

/*/{Protheus.doc} MenuDef
Menu de opcoes na funcao zMVC01c
@author Daniel Atilio
@since 21/01/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function MenuDef()
	Local aRotina := {}

	//Adicionando opcoes do menu
	ADD OPTION aRotina TITLE "Visualizar" ACTION "VIEWDEF.zMVC01c" OPERATION 1 ACCESS 0
	ADD OPTION aRotina TITLE "Incluir" ACTION "VIEWDEF.zMVC01c" OPERATION 3 ACCESS 0
	ADD OPTION aRotina TITLE "Alterar" ACTION "VIEWDEF.zMVC01c" OPERATION 4 ACCESS 0
	ADD OPTION aRotina TITLE "Excluir" ACTION "VIEWDEF.zMVC01c" OPERATION 5 ACCESS 0

Return aRotina

/*/{Protheus.doc} ModelDef
Modelo de dados na funcao zMVC01c
@author Daniel Atilio
@since 21/01/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function ModelDef()
	Local oStruct := FWFormStruct(1, cAliasMVC)
	Local oModel
	Local bPre := Nil
	Local bPos := Nil
	Local bCommit := Nil
	Local bCancel := Nil

	//Cria o modelo de dados para cadastro
	oModel := MPFormModel():New("zMVC01cM", bPre, bPos, bCommit, bCancel)
	oModel:AddFields("ZD1MASTER", /*cOwner*/, oStruct)
	oModel:SetDescription("Modelo de dados - " + cTitulo)
	oModel:GetModel("ZD1MASTER"):SetDescription( "Dados de - " + cTitulo)
	oModel:SetPrimaryKey({})

    //Instala um evento no modelo de dados que irá ficar "observando" as alterações do formulário
    oModel:InstallEvent("VLD_ARTISTA", , zClassArtistas():New(oModel))
Return oModel

/*/{Protheus.doc} ViewDef
Visualizacao de dados na funcao zMVC01c
@author Daniel Atilio
@since 21/01/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function ViewDef()
	Local oModel := FWLoadModel("zMVC01c")
	Local oStruct := FWFormStruct(2, cAliasMVC)
	Local oView

	//Cria a visualizacao do cadastro
	oView := FWFormView():New()
	oView:SetModel(oModel)
	oView:AddField("VIEW_ZD1", oStruct, "ZD1MASTER")
	oView:CreateHorizontalBox("TELA" , 100 )
	oView:SetOwnerView("VIEW_ZD1", "TELA")

Return oView

Agora iremos criar a classe herdando a FWModelEvent, sendo que nessa classe teremos o construtor e os métodos para antes, durante e após o commit.

//Bibliotecas
#Include "TOTVS.ch"

/*/{Protheus.doc} zClassArtistas
Declara a Classe vinda da FWModelEvent e os métodos que serão utilizados
@author Atilio
@since 27/01/2023
@version version
@see https://tdn.totvs.com/pages/releaseview.action?pageId=269552294
/*/

Class zClassArtistas From FWModelEvent
	Method New() CONSTRUCTOR
    Method BeforeTTS()
	Method InTTS()
	Method AfterTTS()
EndClass

/*/{Protheus.doc} New
Método para "instanciar" um observador
@author Atilio
@since 27/01/2023
@version version
@param oModel, Objeto, Objeto instanciado do Modelo de Dados
/*/

Method New(oModel) CLASS zClassArtistas
Return

/*/{Protheus.doc} BeforeTTS
Método acionado antes de fazer as gravações da transação
@author Atilio
@since 27/01/2023
@version version
@param oModel, Objeto, Objeto instanciado do Modelo de Dados
/*/

Method BeforeTTS(oModel) Class zClassArtistas
	//Aqui você pode fazer as operações antes de gravar
Return

/*/{Protheus.doc} InTTS
Método acionado durante as gravações da transação
@author Atilio
@since 27/01/2023
@version version
@param oModel, Objeto, Objeto instanciado do Modelo de Dados
/*/

Method InTTS(oModel) Class zClassArtistas
	//Aqui você pode fazer as durante a gravação (como alterar campos)
Return

/*/{Protheus.doc} AfterTTS
Método acionado após as gravações da transação
@author Atilio
@since 27/01/2023
@version version
@param oModel, Objeto, Objeto instanciado do Modelo de Dados
/*/

Method AfterTTS(oModel) Class zClassArtistas
	//Aqui você pode fazer as operações após gravar

    //Exibe uma mensagem, caso não esteja sendo executado via job ou ws
    If ! IsBlind()
        ShowLog("Passei pelo Commit de forma nova (FWModelEvent)")
    EndIf
Return

Referências:

 

Bom pessoal, por hoje é só.

Abraços e até a próxima.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

8 Responses

  1. Everson da Costa Almeida disse:

    Bom dia e parabéns pelo trabalho!

  2. João Leão disse:

    Existem várias formas de fazer algo no desenvolvimento. Essa forma para dar manutenção foi matadora. Agora, se você vai escrever uma tela MVC nova, acredito que o modelo mais adequado seja de escrever a tela e o ponto de entrada.

    • Opa, obrigado pelo comentário e adendo João.

      Apesar de fazer o ponto de entrada ser mais fácil e simples, até inclusive eu cito isso no terceiro parágrafo (“Até podemos criar um ponto de entrada com o nome do MPFormModel e usar os pontos MODELCOMMITTTS ou MODELCOMMITNTTS.”).

      Acontece que ao passar um fonte no code analysis, quando se usa o bCommit, a TOTVS indica a substituição pela interceptação com o InstallEvent ( https://tdn.totvs.com/pages/releaseview.action?pageId=269552294 ), ai por isso a montagem desse artigo de exemplo.

      Um grande abraço.

  3. Ana Lins disse:

    Sempre aprendo com suas publicações!!

  4. Alexandre Behling disse:

    No exemplo serão chamados todos os eventos e eu tenho que ver se é pra executar algo? Ou como que coloco para chamar um método especifico após certa ação do usuário?

    • Boa tarde Alexandre, tudo joia?

      No fonte original, note que tem um trecho das linhas 110 até 128, onde pode ter tratativas antes, durante e após o commit.

      Então na classe que você for criar, ela terá também os 3 métodos, o antes (BeforeTTS), o durante (o InTTS) e o depois (AfterTTS).

      Ai você transporta suas customizações para esses métodos (igual fizemos no exemplo com o AfterTTS).

      Agora no caso, se você quiser apenas o AfterTTS, ai você ignorar os outros, e nem precisa criar eles dentro do seu fonte que terá a classe.

      Grande abraço.

Deixe uma resposta para Dan (Daniel Atilio)Cancelar resposta

Terminal de Informação