มาสร้าง Grails Custom Validation กันเถอะ
ที่มา :: http://grails.org/doc/1.1.x/ref/Constraints/validator.html

หลังจากที่ได้เรียนรู้การใช้ build-in constraints สำหรับการ validate properties ต่างๆ ใน domain classes ที่ การใช้งาน validation เบื้องต้น แต่บ่อยครั้งที่สิ่งที่เตรียมไว้ให้นั้นอาจจะไม่เพียงพอต่อความต้องการ ดังนั้น ผู้สร้าง Grails จึงอนุญาติให้ผู้พัฒนาสามารถสร้าง Custom Validation ขึ้นมาใช้เองได้

การใช้งานจะผ่าน constraint ชื่อ validator ซึ่งจะสนับสนุน closure หรือ block

constraint validator สามารถมีหรือไม่มี parameter ก็ได้ดังนี้
1. ไม่มี parameter คือ value ของ property ที่ส่งเข้ามา
2. มี 1 parameter คือ value ของ property ที่ส่งเข้ามา
3. มี 2 parameters คือ value และ object reference
4. มี 3 parameters คือ value, object reference และ error object

ส่วนค่าที่ return ออกจาก closure นั้นสามารถเป็นค่าดังนี้
- null หรือ true เมื่อข้อมูลของ property นั้นถูกต้อง
- false เมื่อข้อมูลของ property นั้นไม่ถูกต้อง
- String ซึ่งจะอ้างถึง error code ที่จะแสดง
- list ของ String และ parameter ต่างๆ
- กำหนด error ออกมาได้เอง ซึ่งจะใช้ได้ก้ต่อเมื่อ validator มี parameter 3 ตัว

อธิบายมากไปเดี๋ยวจะงง ???? มาถึงที่เราต้องการทำกันดีกว่าครับ ………..

สิ่งที่ผมอยากสร้างคือ ต้องการ validate ข้อมูลของหมายเลขบัตรประชาชนที่มีรูปแบบดังนี้

X-XXXX-XXXXX-XX-X

มาดูขั้นตอนการสร้าง Custom Validation ว่าเป็นอย่างไร ???

1. ผมต้องการจะใช้งาน Custom Validation ดังนี้

class User {
	String id_number

	static constraints = {
		id_number( idNumber:true )
	}
}

คำอธิบาย
constraint ที่ผมสร้างและต้องการใช้งานชื่อ idNumber จะทำการตรวจสอบเพียงว่า ข้อมูลนั้นถูกต้องตามรูปแบบที่กำหนดหรือต้องการหรือไม่เท่านั้น [ ค่าที่จะ return ออกมาจะมีค่าเป็นดังนี้ null/true/false ]

2.ทำการสร้าง Custom Validation Class
ต้อง extends มาจาก org.codehaus.groovy.grails.validation.AbstractConstraint โดย Grails ได้เตรียมไว้ให้สำหรับงานนี้โดยเฉพาะ

ผมจะสร้าง class IdNumberConstraint ขึ้นมาเพื่อตรวจสอบรูปแบบของหมายเลขบัตรประชาชนดังนี้

import org.codehaus.groovy.grails.validation.AbstractConstraint
import org.springframework.validation.Errors

class IdNumberConstraint extends AbstractConstraint {

    private static final String DEFAULT_MESSAGE_CODE = "default.idNumber.invalid.message";
    public static final String NAME = "idNumber";

    private boolean validateConstraint

    public void setParameter(Object constraintParameter) {
        if (!(constraintParameter instanceof Boolean))
            throw new IllegalArgumentException("Parameter for constraint ["
                    + NAME + "] of property ["
                    + constraintPropertyName + "] of class ["
                    + constraintOwningClass + "] must be a boolean value");

        this.validateConstraint = ((Boolean) constraintParameter).booleanValue()
        super.setParameter(constraintParameter);
    }

    protected void processValidate(Object target, Object propertyValue, Errors errors) {
        if (validateConstraint && !validate(target, propertyValue)) {
            def args = (Object[]) [constraintPropertyName, constraintOwningClass,
                    propertyValue]
            super.rejectValue(target, errors, DEFAULT_MESSAGE_CODE,
                    "not." + NAME, args);
        }
    }

    boolean supports(Class type) {
        return type != null && String.class.isAssignableFrom(type);
    }

    String getName() {
        return NAME;
    }

    boolean validate(target, propertyValue) {
        propertyValue ==~/^(\d{1})?\s*[\(\-]?(\d{4})[\)\-]?\s*(\d{5})[\-](\d{2})[\-](\d{1})$/
    }
}

คำอธิบาย
ส่วนที่น่าสนใจคือ
- class จะต้อง extends AbstractConstraint ซึ่งทาง Grails จะเตรียมไว้ให้
class IdNumberConstraint extends AbstractConstraint

- กำหนด constant หรือ ค่าคงที่ที่จำเป็นต่อการใช้งานคือ
NAME คือชื่อของ constraint
DEFAULT_MESSAGE_CODE คือ property name ของ error message ที่จะกำหนดใน message.properties

- method validate() จะทำการตรวจสอบความถูกต้องของข้อมูล ให้เป็นไปตามรูปแบบที่กำหนด โดยผมทำการตรวจสอบด้วย RE [ Regular Expression ]

boolean validate(target, propertyValue) {
        propertyValue ==~/^(\d{1})?\s*[\(\-]?(\d{4})[\)\-]?\s*(\d{5})[\-](\d{2})[\-](\d{1})$/
}

3. การใช้งาน Custom Validation ตัวนี้สามารถใช้ได้ 2 แบบคือ

3.1 แบบคนขี้เหนียว คือใช้ใน Grails Application นั้นๆ ไปเลย ทำดังนี้
- นำ IdNumberConstraint.groovy ไปไว้ที่ src/groovy
- ทำการ register Custom Validation ใน file /grails-app/conf/Config.groovy ดังนี้

org.codehaus.groovy.grails.validation.ConstrainedProperty.registerNewConstraint(
IdNumberConstraint.NAME, IdNumberConstraint.class)

3.2 แบบคนใจดี คือสร้าง Grails Plug-in เพื่อสามารถนำไปใช้ใน Grails Application อื่นๆ ได้
ขั้นตอนในการสร้าง plug-in ก็ไม่ยากเท่าไร มีขั้นตอนดังนี้ ดูเพิ่มเติมได้ที่นี่ http://www.grails.org/Creating+Plugins

- สร้าง Grails Plug-in project
>grails create-plugin MyCustomValidation

ทำการแก้ไข file MyCustomValidationPlugin.groovy ดังนี้

import IdNumberConstraint
import org.codehaus.groovy.grails.validation.ConstrainedProperty 

class MyCustomValidationPlugin{
    def version = 0.1
    def author = "USER"
    def description = '''
This plugin adds specific functionality to the application for my app.
'''
    def dependsOn = [:]
	def loadAfter = ['controllers']

    def doWithSpring = {
        ConstrainedProperty.registerNewConstraint(IdNumberConstraint.NAME, IdNumberConstraint.class);
    }
}

- copy file IdNumberConstraint มาไว้ที่ /src/groovy

- ทำการ package plug-in ด้วยคำสั่ง
> grails package-plugin

ระบบจะทำการสร้าง file xxxx.zip

- เพิ่ม plug-in เข้ามายัง Grails application ด้วยคำสั่ง
>grails install-plugin /path/to/plugin/xxxx.zip

เท่านี้ก้สามารถใช้ idNumber constraint ใน domain class ได้แล้วครับ

4. เพิ่ม error code ใน file /grails-app/i18n/message.properties และ /grails-app/i18n/message_th.properties ดังนี้ เพื่อใช้สำหรับการแสดง default error message ของ idNumber constraint ครับ

default.invalid.creditCard.message=Property [{0}] of class [{1}] with value [{2}] is not a valid id card number

default.idNumber.invalid.message=คุณสมบัติ [{0}] ของคลาส [{1}] ซึ่งมีค่าเป็น [{2}] ไม่ถูกต้องตามรูปแบบหมายเลขบัตรประจำตัวประชาชน

ผมทดสอบนำไปใช้งานด้วยการใช้ Plug-in ที่สร้างขึ้นมา จะทำงานได้ประมาณนี้ครับ

ด้วยขั้นตอนประมาณนี้ก็สามารถสร้างและใช้งาน Grails Custom Validation ได้แล้วครับ ซึ่งไม่น่ายากไปเท่าไรครับ
^_^ ^_^ ^_^

Tags: , ,

3 Responses to “มาสร้าง Grails Custom Validation กันเถอะ”

  1. โอ้ สุดยอดครับ

  2. มาแรก เจงๆ เวบนี้

  3. ขอบคุณมากครับ…
    …สำหรับบทความดีมากๆ ของคุณ up1
    …ขอรับความรู้ไปลองใช้ดูครับ.

Leave a Reply