Grails commands databinding alternativa 6
<%@ taglib prefix="datatables" uri="http://github.com/dandelion/datatables" %>
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="adminlte">
<title>Configuración</title>
<t:assetsInfoBox/>
<t:assetsOnOff/>
</head>
<body>
%{--BodyHeader--}%
<content tag="header">
<g:render template="/layouts/active_items" model="[menu: '1', submenu: pageConfig.membresia ? '1.1' : '1.2']"/>
<h2 class="page-title">
<g:if test="${pageConfig.membresia}">Edición de la membresía ${pageConfig.membresia.folio}</g:if><g:else>Nueva membresía</g:else>
</h2>
<t:breadcrumbs
data="${['menu.membresias.label': createLink(action: 'listMembresias'), 'Lista de membresías': createLink(action: 'listMembresias')]}"/>
</content>
%{--Datos del contrato--}%
<div class="row">
<div class="col-sm-2">
<g:render template="submenuleft" model="[item7: 'active', membresiaInstance:pageConfig.membresia]"/>
</div>
<div class="col-sm-10">
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title">Datos del contrato</h3>
</div>
<div class="box-body">
<g:if test="${pageConfig.membresia}">
<t:membresiaDashboard membresia="${pageConfig.membresia}"/>
</g:if>
<g:else>
<div class="box-body">
<t:callout type="warning" title="Advertencia"
text="No puede ingresar a esta sección hasta no capturar la carátula de la membresía."/>
</div>
</g:else>
</div>
</div>
</div>
</div>
%{--Datos de acceso--}%
<div class="row">
<div class="col-lg-2 col-md-3">
</div>
<div class="col-lg-10 col-md-9">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">Datos de acceso</h3>
</div>
<g:form method="post" class="form-horizontal" role="form" action="updatePanelAcceso">
<div class="box-body">
<g:render template="panel_config_acceso" model="[panelAcceso: pageConfig.getPanelAcceso()]"/>
</div>
<div class="box-footer">
<t:onceSubmit name="submit3" class="btn btn-default pull-right">
<i class="fa fa-save fa-2x"></i> </br>
<g:message code="default.button.save.label"/>
</t:onceSubmit>
<g:link controller="membresia" action="listMembresias" class="btn btn-default"><i
class="fa fa-remove fa-2x"></i> </br>
<g:message code="default.cancel.label"/>
</g:link>
</div>
</g:form>
</div>
</div>
</div>
%{--Parámetros Conekta--}%
<div class="row">
<div class="col-lg-2 col-md-3">
</div>
<div class="col-lg-10 col-md-9">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">Parámetros conekta</h3>
</div>
<g:form method="post" class="form-horizontal" role="form" action="updatePanelConekta">
<div class="box-body">
<g:render template="panel_config_conekta" model="[panelConekta: pageConfig.getPanelConekta()]"/>
</div>
<div class="box-footer">
<t:onceSubmit name="submit3" class="btn btn-default pull-right">
<i class="fa fa-save fa-2x"></i> </br>
<g:message code="default.button.save.label"/>
</t:onceSubmit>
<g:link controller="membresia" action="listMembresias" class="btn btn-default"><i
class="fa fa-remove fa-2x"></i> </br>
<g:message code="default.cancel.label"/>
</g:link>
</div>
</g:form>
</div>
</div>
</div>
%{--Parámetros Generales--}%
<div class="row">
<div class="col-lg-2 col-md-3">
</div>
<div class="col-lg-10 col-md-9">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">Parámetros generales</h3>
</div>
<g:form method="post" class="form-horizontal" role="form" action="updatePanelGral">
<div class="box-body">
<g:render template="panel_config_gral" model="[panelGral: pageConfig.getPanelGral()]"/>
</div>
<div class="box-footer">
<t:onceSubmit name="submit3" class="btn btn-default pull-right">
<i class="fa fa-save fa-2x"></i> </br>
<g:message code="default.button.save.label"/>
</t:onceSubmit>
<g:link controller="membresia" action="listMembresias" class="btn btn-default"><i
class="fa fa-remove fa-2x"></i> </br>
<g:message code="default.cancel.label"/>
</g:link>
</div>
</g:form>
</div>
</div>
</div>
</body>
</html>
@GrailsCompileStatic
class PageConfig extends PageWithPanels<Membresia> {
Membresia membresia
PageConfig(Membresia membresia) {
this.membresia = membresia
buildPanels(membresia)
}
void addPanels() {
panels.add(new PanelAcceso())
panels.add(new PanelConekta())
panels.add(new PanelGral())
}
PanelAcceso getPanelAcceso() {
return getPanel("PANEL_ACCESO") as PanelAcceso
}
PanelConekta getPanelConekta() {
return getPanel("PANEL_CONEKTA") as PanelConekta
}
PanelGral getPanelGral() {
return getPanel("PANEL_GRAL") as PanelGral
}
}
@GrailsCompileStatic
@Validateable
class PanelConekta implements Panel<Membresia> {
Membresia membresia
String idCliente
AccesoService accesoService
@Override
String getKey() {
return "PANEL_CONEKTA"
}
@Override
Membresia getInstance() {
return membresia
}
@Override
void build(Membresia membresia) {
this.membresia = membresia
idCliente = membresia.conektaCustomerId
}
@Override
void savePanel() {
accesoService.saveOrUpdatePanel(this)
}
@Override
boolean validateHasErrors() {
return hasErrors()
}
static constraints = {
idCliente nullable: true, blank: true
}
}
@GrailsCompileStatic
@Validateable
class PanelAcceso implements Panel<Membresia> {
Membresia membresia
String username
String password
AccesoService accesoService
@Override
String getKey() {
return "PANEL_ACCESO"
}
@Override
Membresia getInstance() {
return membresia
}
@Override
void build(Membresia membresia) {
this.membresia = membresia
username = membresia.accesoSocio?.username
password = membresia.accesoSocio?.password
}
@Override
void savePanel() {
accesoService.saveOrUpdatePanel(this)
}
@Override
boolean validateHasErrors() {
return hasErrors()
}
boolean isUsuarioRegistrado() {
return membresia.accesoSocio != null
}
static constraints = {
username blank: false, validator: {String value, PanelAcceso _this ->
if (!_this.accesoService.isUserNameAvailable(value)) {
return "acceso.usuarioRepetido"
}
}
password blank: false, minSize: 6
}
}
@GrailsCompileStatic
abstract class PageWithPanels<T> {
List<Panel> panels = new ArrayList()
protected void buildPanels(T instance) {
addPanels()
for (def panel : panels) {
panel.build(instance)
}
}
protected Panel<T> getPanel(String id) {
for (int i = 0; i < panels.size(); i++) {
if (id == panels[i].key) {
return panels[i]
}
}
}
void replace(Panel<T> panel) {
for (int i = 0; i < panels.size(); i++) {
if (panel.key == panels[i].key) {
panels[i] = panel
break
}
}
}
abstract void addPanels()
}
@GrailsCompileStatic
class PageConfig extends PageWithPanels<Membresia> {
Membresia membresia
PageConfig(Membresia membresia) {
this.membresia = membresia
buildPanels(membresia)
}
// Paneles de la página, cuando se agregue un nuevo panel habrá que agregarlo aquí.
void addPanels() {
panels.add(new PanelAcceso())
panels.add(new PanelConekta())
panels.add(new PanelGral())
}
PanelAcceso getPanelAcceso() {
return getPanel("PANEL_ACCESO")
}
PanelConekta getPanelConekta() {
return getPanel("PANEL_CONEKTA")
}
PanelConekta getPanelGral() {
return getPanel("PANEL_GRAL")
}
}
class MembresiaController {
// Envía a la página de configuración
def config(Membresia membresiaInstance) {
PageConfig pageConfig = new PageConfig(membresiaInstance)
render view: "config", model: [pageConfig: pageConfig]
}
def updatePanelAcceso(PanelAcceso panelAcceso) {
updatePanel(panelAcceso)
}
def updatePanelConekta(PanelConekta panelConekta) {
updatePanel(panelConekta)
}
def updatePanelGral(PanelGral panelGral) {
updatePanel(panelGral)
}
private def updatePanel(Panel<Membresia> panel) {
PageConfig pageConfig = new PageConfig(panel.instance)
pageConfig.replace(panel)
if (panel.validateHasErrors()) {
render(view: "config", model: [pageConfig: pageConfig])
return
}
panel.savePanel()
flash.success = "Se guardaron correctamente los parámetros del panel"
redirect action: "config", params: [id: panel.instance.id]
}
}
Estas alternativas son ideales para una página que tiene N paneles y cada uno ejecuta una lógica de validación distinta.
La alternativa 5 tiene el problema que cuando se agrega un nuevo panel, hay que modificar todas las acciones para agregar el nuevo panel rompiendo el principio open/close. Esta alternativa no repite código como en la alternativa 5, además que respeta el principio open/close.
Esta alternativa se basa en la idea de tener 1 command object que represente cada panel, y una clase PageWithPanels
que representa la página con todos los paneles.
Ventajas
@GrailsCompileStatic
interface Panel<T> {
// Id que representa al panel
String getKey()
// el panel se construye en base al objeto instance
void build(T instance)
// Obtiene la instancia con la que se construyen todos los paneles
T getInstance()
// se guarda el panel
void savePanel()
boolean validateHasErrors()
}