LoginSignup
4
5

More than 5 years have passed since last update.

SkinnyFrameworkのバリデーション機能の独自実装例

Posted at

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)
)
4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5