A arquitetura Model-View-Controller ou MVC, como é mais conhecida, é um padrão de arquitetura de software que visa separar a lógica de negócio da lógica de apresentação, permitindo desenvolvimento, teste e manutenção isolados.Aqueles que já desenvolveram uma aplicação em AdvPL vão perceber, que justamente a diferença mais importante entre a forma de construir uma aplicação em MVC e a forma tradicional é essa separação, que permitirá usar a regra de negócio em aplicações que tenham ou não interfaces, como WebServices e aplicação automática e seu reuso em outras aplicações. As funções de uma aplicação MVC são.
/*Importar as bibliotecas*/ #INCLUDE "PROTHEUS.CH" #INCLUDE "FWMBROWSE.CH" #INCLUDE "FWMVCDEF.CH" /*Iniciando sua função*/ User Function MVC001() /*Declarando as variáveis que serão utilizadas*/ Local lRet := .T. Local aArea := SX5->(GetArea()) Private oBrowse Private cChaveAux := "" //Iniciamos a construção básica de um Browse. oBrowse := FWMBrowse():New() //Definimos a tabela que será exibida na Browse utilizando o método SetAlias oBrowse:SetAlias("SX5") //Definimos o título que será exibido como método SetDescription oBrowse:SetDescription("Grupo Tributário") //Adiciona um filtro ao browse oBrowse:SetFilterDefault( "X5_TABELA == '21'" ) //Desliga a exibição dos detalhes //oBrowse:DisableDetails() //Ativamos a classe oBrowse:Activate() RestArea(aArea) Return
//------------------------------------------------------------------- // Montar o menu Funcional //------------------------------------------------------------------- Static Function MenuDef() Local aRotina := {} ADD OPTION aRotina TITLE "Pesquisar" ACTION 'PesqBrw' OPERATION 1 ACCESS 0 ADD OPTION aRotina TITLE "Visualizar" ACTION "VIEWDEF.MVC001" OPERATION 2 ACCESS 0 ADD OPTION aRotina TITLE "Incluir" ACTION "VIEWDEF.MVC001" OPERATION 3 ACCESS 0 ADD OPTION aRotina TITLE "Alterar" ACTION "VIEWDEF.MVC001" OPERATION 4 ACCESS 0 ADD OPTION aRotina TITLE "Excluir" ACTION "VIEWDEF.MVC001" OPERATION 5 ACCESS 0 ADD OPTION aRotina TITLE "Imprimir" ACTION "VIEWDEF.MVC001" OPERATION 8 ACCESS 0 ADD OPTION aRotina TITLE "Copiar" ACTION "VIEWDEF.MVC001" OPERATION 9 ACCESS 0 Return aRotinaA função ViewDef define como o será a interface e portanto como o usuário interage com o modelo de dados (Model) recebendo os dados informados pelo usuário, fornecendo ao modelo de dados (definido na ModelDef) e apresentando o resultado. A interface pode ser baseada totalmente ou parcialmente em um metadado (dicionário), permitindo: Reaproveitamento do código da interface, pois uma interface básica pode ser acrescida de novos componentes; Simplicidade no desenvolvimento de interfaces complexas. Um exemplo disso são aquelas aplicações onde uma GRID depende de outra. No MVC a construção de aplicações que tem GRIDs dependentes é extremamente fácil; Agilidade no desenvolvimento, a criação e a manutenção se tornam muito mais ágeis; Mais de uma interface por Bussiness Object. Poderemos ter interfaces diferentes para cada variação de um segmento de mercado, como o varejo. A ViewDef deve ser uma Static Function dentro da aplicação.
Static Function ViewDef() Local oView Local oModel := ModelDef() Local oStr1:= FWFormStruct(2, 'SX5') // Cria o objeto de View oView := FWFormView():New() // Define qual o Modelo de dados será utilizado oView:SetModel(oModel) //Adiciona no nosso View um controle do tipo FormFields(antiga enchoice) oView:AddField('Formulario' , oStr1,'CamposSX5' ) //Remove os campos que não irão aparecer oStr1:RemoveField( 'X5_DESCENG' ) oStr1:RemoveField( 'X5_DESCSPA' ) // Criar um "box" horizontal para receber algum elemento da view oView:CreateHorizontalBox( 'PAI', 100) // Relaciona o ID da View com o "box" para exibicao oView:SetOwnerView('Formulario','PAI') oView:EnableTitleView('Formulario' , 'Grupo Tributário' ) oView:SetViewProperty('Formulario' , 'SETCOLUMNSEPARATOR', {10}) //Força o fechamento da janela na confirmação oView:SetCloseOnOk({||.T.}) Return oViewA função ModelDef define a regra de negócios propriamente dita onde são definidas: Todas as entidades (tabelas) que farão parte do modelo de dados (Model); Regras de dependência entre as entidades; Validações (de campos e aplicação); Persistência dos dados (gravação).
Static Function ModelDef() Local oModel Local oStr1:= FWFormStruct( 1, 'SX5', /*bAvalCampo*/,/*lViewUsado*/ ) // Construção de uma estrutura de dados //Cria o objeto do Modelo de Dados //Irie usar uma função MVC001V que será acionada quando eu clicar no botão "Confirmar" oModel := MPFormModel():New('GrupoTributario', /*bPreValidacao*/, { | oModel | MVC001V( oModel ) } , /*{ | oMdl | MVC001C( oMdl ) }*/ ,, /*bCancel*/ ) oModel:SetDescription('Grupo Tributário') //Abaixo irei iniciar o campo X5_TABELA com o conteudo da sub-tabela oStr1:SetProperty('X5_TABELA' , MODEL_FIELD_INIT,{||'21'} ) //Abaixo irei bloquear/liberar os campos para edição oStr1:SetProperty('X5_TABELA' , MODEL_FIELD_WHEN,{|| .F. }) //Podemos usar as funções INCLUI ou ALTERA //oStr1:SetProperty('X5_CHAVE' , MODEL_FIELD_WHEN,{|| INCLUI }) //Ou usar a propriedade GetOperation que captura a operação que está sendo executada oStr1:SetProperty("X5_CHAVE" , MODEL_FIELD_WHEN,{|oModel| oModel:GetOperation()== 3 }) oStr1:RemoveField( 'X5_DESCENG' ) oStr1:RemoveField( 'X5_DESCSPA' ) oStr1:RemoveField( 'X5_FILIAL' ) // Adiciona ao modelo uma estrutura de formulário de edição por campo oModel:addFields('CamposSX5',,oStr1,{|oModel|MVC001T(oModel)},,) //Define a chave primaria utilizada pelo modelo oModel:SetPrimaryKey({'X5_FILIAL', 'X5_TABELA', 'X5_CHAVE' }) // Adiciona a descricao do Componente do Modelo de Dados oModel:getModel('CamposSX5'):SetDescription('TabelaSX5') Return oModel
//Esta função será executada no inicio do carregamento da tela, neste exemplo irei //apenas armazenar numa variável o conteudo de um campo Static Function MVC001T( oModel ) Local lRet := .T. Local oModelSX5 := oModel:GetModel( 'CamposSX5' ) cChaveAux := SX5->X5_CHAVE Return(lRet)
//------------------------------------------------------------------- // Validações ao salvar registro // Input: Model // Retorno: Se erros foram gerados ou não //------------------------------------------------------------------- Static Function MVC001V( oModel ) Local lRet := .T. Local oModelSX5 := oModel:GetModel( 'CamposSX5' ) Local nOpc := oModel:GetOperation() Local aArea := GetArea() //Capturar o conteudo dos campos Local cChave := oModelSX5:GetValue('X5_CHAVE') Local cTabela := oModelSX5:GetValue('X5_TABELA') Local cDescri := oModelSX5:GetValue('X5_DESCRI') Begin Transaction if nOpc == 3 .or. nOpc == 4 if Empty(cTabela) oModelSX5:SetValue('X5_TABELA','21') Endif dbSelectArea("SX5") SX5->(dbSetOrder(1)) SX5->(dbGoTop()) If(SX5->(dbSeek(xFilial("SX5")+cTabela+cChave))) if cChaveAux != cChave SFCMsgErro("A chave "+Alltrim(cChave)+" ja foi informada!","MVC001") lRet := .F. Endif Endif if Empty(cChave) SFCMsgErro("O campo chave é obrigatório!","MVC001") lRet := .F. Endif if Empty(cDescri) SFCMsgErro("O campo descrição é obrigatório!","MVC001") lRet := .F. Endif Endif if !lRet DisarmTransaction() Endif End Transaction RestArea(aArea) FwModelActive( oModel, .T. ) Return lRetComo pode ver, não é tão difícil começar a desenvolver em MVC.