iberck
3/3/2017 - 10:12 PM

Grails command-databinding-p5.md

Grails command-databinding-p5.md

Alternativa 5

Esta alternativa fue creada porque la alternativa 4 era tan genérica que se volvía una alternativa difícil de entender y de mantener. Esta alternativa es similar a la 4, pero inspirada en el principio de la simplicidad.

Ventajas:

  • Saca la lógica de validaciones de la vista del domain class y la pasa a un command object.
  • Define claramente qué operaciones de validación se harán en cada panel.
  • Cada command object define sus constraints dentro de static constraints {}.
  • Respeta principio open/close, bajo acoplamiento, alta cohesión.
  • Respeta el principio KISS

En esta alternativa, cuando se guarda el panel se podría retornar el resultado del método save() para realizar una validación de los constraints al guardar el domain class en la bd, sin embargo para mantenerlo más simple se pueden agregar los mismos constraints del domain class dentro del commmand object, todo depende de la complejidad de las validaciones.

Desventajas:

  • Se sigue rompiendo el principio open/close porque al agregar un nuevo panel, hay que modificar los métodos del controlador de los demás paneles de la página.
class MembresiaController {

    // Envía a la página de configuración
    def config(Membresia membresiaInstance) {
        PanelAcceso panelAcceso = new PanelAcceso(membresiaInstance)
        PanelConekta panelConekta = new PanelConekta(membresiaInstance)
        render view: "config", model: [panelAcceso: panelAcceso, panelConekta: panelConekta]
    }
    
    def updatePanelAcceso(PanelAcceso panelAcceso) {
        if (panelAcceso.hasErrors()) {
            render(view: "config", model: [panelAcceso: panelAcceso, panelConekta: new PanelConekta(panelAcceso.membresia)])
            return
        }
        panelAcceso.savePanel()
        flash.success = "Se guardaron correctamente los parámetros del panel acceso"
        redirect action: "config", params: [id: panelAcceso.membresia.id]
    }
    
    def updatePanelConekta(PanelConekta panelConekta) {
        if (panelConekta.hasErrors()) {
            render(view: "config", model: [panelConekta: panelConekta, panelAcceso: new PanelAcceso(panelConekta.membresia)])
            return
        }
        panelConekta.savePanel()
        flash.success = "Se guardaron correctamente los parámetros del panel conekta"
        redirect action: "config", params: [id: panelConekta.membresia.id]
    }
  
}
<g:hasErrors bean="${panelAcceso}">
    <div class="alert alert-danger">
        <g:renderErrors bean="${panelAcceso}" as="list"/>
    </div>
</g:hasErrors>

%{--Membresia--}%
<g:hiddenField name="membresia.id" value="${panelAcceso.membresia.id}"/>

%{-- Usuario registrado --}%
<div class="form-group has-feedback">
    <label class="control-label col-sm-3">
        <t:labelText label="Usuario registrado" tooltip="Indica si el socio ya ha dado de alta su usuario/password en el sistema" />
    </label>
    <div class="col-sm-4">
        <t:onoff name="onoff1" options="{onText:'Si', offText:'No', size:'small', disabled:true}"
                 value="${panelAcceso?.isUsuarioRegistrado()}"/>
    </div>
</div>

%{--Nombre de usuario--}%
<div class="form-group ${hasErrors(bean: panelAcceso, field: 'username', 'has-error')} has-feedback">
    <label for="username" class="control-label col-sm-3">
        <t:labelText required="true" tooltip="Indique el username con el que ingresará el socio a la aplicación"
                     label="Nombre de usuario" error="${hasErrors(bean: panelAcceso, field: 'username', 'true')}"/>
    </label>

    <div class="col-sm-4">
        <g:textField name="username" value="${panelAcceso?.username}"/>
    </div>
</div>

%{--Password--}%
<div class="form-group ${hasErrors(bean: panelAcceso, field: 'password', 'has-error')} has-feedback">
    <label for="password" class="control-label col-sm-3">
        <t:labelText required="true" tooltip="Indique el password con el que ingresará el socio a la aplicación"
                     label="Password" error="${hasErrors(bean: panelAcceso, field: 'password', 'true')}"/>
    </label>

    <div class="col-sm-4">
        <g:passwordField name="password" value="${panelAcceso?.password}" autocomplete="new-password"/>
    </div>
</div>
<g:hasErrors bean="${panelConekta}">
    <div class="alert alert-danger">
        <g:renderErrors bean="${panelConekta}" as="list"/>
    </div>
</g:hasErrors>

%{--Membresia--}%
<g:hiddenField name="membresia.id" value="${panelConekta.membresia.id}"/>

%{--Id cliente--}%
<div class="form-group ${hasErrors(bean: panelConekta, field: 'idCliente', 'has-error')} has-feedback">
    <label for="idCliente" class="control-label col-sm-3">
        <t:labelText tooltip="Este campo se actualiza automáticamente cuando el administrador/socio crea/guarda una tarjeta de crédito por primera vez, evite actualizar el campo a menos que el administrador lo indique"
                     label="Id cliente conekta" error="${hasErrors(bean: panelConekta, field: 'idCliente', 'true')}"/>
    </label>

    <div class="col-sm-4">
        <g:textField name="idCliente" value="${panelConekta?.idCliente}"/>
    </div>
</div>
<g:form method="post" class="form-horizontal" role="form" action="updatePanelAcceso">
    <div class="box-body">
        <g:render template="panel_config_acceso" model="[panelAcceso: panelAcceso]"/>
    </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>

<g:form method="post" class="form-horizontal" role="form" action="updatePanelConekta">
    <div class="box-body">
        <g:render template="panel_config_conekta" model="[panelConekta: panelConekta]"/>
    </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>
package us.incorpora.sigrem.commands.config

@GrailsCompileStatic
@Validateable
class PanelAcceso {

    Membresia membresia
    String username
    String password
    AccesoService accesoService

    PanelAcceso() {
    }

    PanelAcceso(Membresia membresia) {
        this.membresia = membresia
        username = membresia.accesoSocio?.username
        password = membresia.accesoSocio?.password
    }

    boolean isUsuarioRegistrado() {
        return membresia.accesoSocio != null
    }

    void savePanel() {
        accesoService.saveOrUpdatePanelAccesoSocio(this)
    }

    static constraints = {
        username blank: false, validator: {String value, PanelAcceso _this ->
            if (!_this.accesoService.isUserNameAvailable(value)) {
                return "acceso.usuarioRepetido"
            }
        }
        password blank: false, minSize: 6
    }
}
package us.incorpora.sigrem.commands.config

@GrailsCompileStatic
@Validateable
class PanelConekta {

    Membresia membresia
    String idCliente
    AccesoService accesoService

    PanelConekta() {
    }

    PanelConekta(Membresia membresia) {
        this.membresia = membresia
        idCliente = membresia.conektaCustomerId
    }

    void savePanel() {
        accesoService.saveOrUpdatePanelConekta(this)
    }

    static constraints = {
        idCliente nullable: true, blank: true
    }
}