SkinnyFrameworkのバリデーション機能はskinny.validator.ValidationRuleを派生させて作成することができます。
このバリデーション機能は基本的に対象フィールドの値のフォーマットを検証するようになっていますが、ちょっと強引に複雑なバリデーションを行う方法をあげてみます。
2つのフィールドの値を比較して検証する
2つのフィールド間の大小関係などを検証するバリデータを作ってみました。
/**
* 日時データ比較
*
* @param targetKey 比較対象のフィールドキー
* @param targetValue 比較対象の値
* @param compareName 比較方法の名称
* @param comparator 比較処理
*/
class compareDateTime(targetKey: String, targetValue: Any, compareName: String,
comparator: (DateTime, DateTime) => Boolean) extends ValidationRule {
def name = "compareDateTime"
override def messageParams = Seq(I18nKeyParam(targetKey), I18nKeyParam(compareName))
def isValid(v: Any): Boolean = {
val value = targetValue match {
case Some(v) => v
case None => null
case v => v
}
(v, value) match {
case (lhsStr: String, rhsStr: String) =>
(for (
lhs <- Try(DateTimeUtil.parseDateTime(lhsStr)).toOption;
rhs <- Try(DateTimeUtil.parseDateTime(rhsStr)).toOption
) yield {
comparator(lhs, rhs)
}).getOrElse(false)
case _ =>
// パラメータが存在しないことは許容する
true
}
}
}
case class greaterThanDateTime(targetKey: String, targetValue: Any) extends
compareDateTime(targetKey, targetValue, "greaterThan", (l, r) => l.compareTo(r) > 0)
case class greaterEqualDateTime(targetKey: String, targetValue: Any) extends
compareDateTime(targetKey, targetValue, "greaterEqual", (l, r) => l.compareTo(r) >= 0)
case class lessThanDateTime(targetKey: String, targetValue: Any) extends
compareDateTime(targetKey, targetValue, "lessThan", (l, r) => l.compareTo(r) < 0)
case class lessEqualDateTime(targetKey: String, targetValue: Any) extends
compareDateTime(targetKey, targetValue, "lessEqual", (l, r) => l.compareTo(r) <= 0)
messages.conf
error {
compareDateTime="{0} は {1} {2}の日時にしてください"
}
greaterThan="超"
greaterEqual="以上"
lessThan="未満"
lessEqual="以下"
使い方は以下のように比較対象のフィールドのメッセージキーと値を渡します。
override def createForm = validation(createParams,
paramKey("begin_date") is required & dateFormat,
paramKey("end_date") is required & dateFormat &
greaterEqualDateTime("model.beginDate", createParams.getAs("begin_date"))
)
DBにアクセスして検証する
フィールドの値ががDB中でユニークかどうかを検証するバリデーションは以下の感じです。
/**
* ユニークであること
*
* @param fieldName フィールド名
* @param paramType パラメータの型
* @param id 対象モデルの主キー値
* @param model モデル
*/
case class unique[Entity](fieldName: String, paramType: ParamType, id: Option[Long],
model: SkinnyCRUDMapper[Entity]) extends ValidationRule {
def name = "unique"
def isValid(v: Any): Boolean = isEmpty(v) ||
(model.countBy(sqls.ne(model.primaryKeyField, id.getOrElse(-1)).
and.eq(model.defaultAlias.field(fieldName), paramType.unapply(v))) == 0)
}
messages.conf
error {
unique="指定の{0}は既に存在しています"
}
使用例です。
override def updateForm = validation(updateParams,
paramKey("name") is required &
unique("name", ParamType.String, params.getAs("id"), model)
)