Entityのvalidation

ちょっとちらっと考えたことをメモ。

例えばnot nullなcolumnを持つtableのEntity(S2DaoでいうところのEntity)があったとして、
このEntityに対してユーザが任意にデータ入力をするとします。
すると当然not nullなプロパティに値が入ってないなんてことはよくあることで
こういうところはUIのvalidatorとかで制御する・・・んでしょうね、きっと一般的に。
(前に使ったJSF+Spring+Hibernateではそうでした。)
とすると、たくさんUIがあると当然漏れとか、あるいはtableの仕様変更があったりすると、さぁ大変ですよね。
validationをすり抜けてnullのままinsertやupdateがかかったとしても、
実行時例外がでて、それはそれで終了ではありますけど。

こういうvalidationってインテグレーション層で行ったほうがいいんじゃないかな、と思ったわけです。
ここはZipCodeじゃないと、とかメールアドレスじゃないととかいうのは上位でvalidationすればいいわけですし
そういうことなら手を煩わせるのは仕方ないと思います。
S2Baseを使えばDaoやEntityは自動生成されます。
ここでEntityに対して、このプロパティはnot nullですよAnnotationを自動的に付加してあげれば
(仮にプロパティ名_REQUIREDというオブジェクト定数を自動生成するとします。)
こんなInterceptorを使えば、例外を投げることができますよね。

 
<?php
/**
 * Validate required property of entity  
 *
 */
class EntityValueValidatorInterceptor extends S2Container_AbstractInterceptor {
 
    /**
     * column annotation sufix
     *
     */
    const COLUMN_ANNOTATION_SURFIX = "_COLUMN";
 
    /**
     * value required surfix
     * @var string
     */
    const REQUIRED_ANNOTATION_SURFIX = "_REQUIRED";
 
    /**
     * Getter name prefix
     * @var string
     */
    const GETTER_PREFIX = "get";
 
    /**
     * invoke Interceptor
     * @param S2Container_MethodInvocation $methodInvocation
     * @return mixed Method result
     */
 
    public function invoke(S2Container_MethodInvocation $methodInvocation) {
        $args = $methodInvocation->getArguments();
        $className = null;
        $reflectionClass = null;
        $getterName = null;
        $getterMethod = null;
        $getterResult = null;
        foreach($args as $arg) {
            $className = get_class($arg);
            if ($className != false) {
                $reflectionClass  = new ReflectionClass($className);
                //is entity?
                if(strpos($reflectionClass->getFileName(), S2BASE_PHP5_ENTITY_DIR) !== false) {
                    //get props
                    foreach($reflectionClass->getProperties() as $prop) {
                        //is column of table?
                        if($reflectionClass->hasConstant($prop->getName() . self::COLUMN_ANNOTATION_SURFIX)) {
                            //getter exist?
                            $getterName = self::GETTER_PREFIX . $prop->getName();
                            if($reflectionClass->hasMethod($getterName)) {
                                $getterMethod = $reflectionClass->getMethod($getterName);
                                if($getterMethod->isPublic()) {
                                    //value required?
                                    if($reflectionClass->hasConstant($prop->getName() . self::REQUIRED_ANNOTATION_SURFIX)) {
                                        $getterResult = $getterMethod->invoke($arg);
                                        //value exist?
                                        if($getterResult !== 0 && $getterResult == null) {
                                             throw new Exception($prop->getName() . "is required.");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
 
        $ret = $methodInvocation->proceed();
        return $ret;
    }
}
 
後はUI側でS2BaseValueRequiredExceptionをcatchした場合にエラーメッセージなりを出すようにしてあげればよいですよね。
AOPの設定もS2Base2.0系のApplicationContextを使えば、楽ちんです。
 
S2ContainerApplicationContext::registerAspect('/Dao$/', 'EntityValueValidatorInterceptor', 'insert,update');
 
こんなのがあれば、少なくともUIレベルでここで値がいりますよvalidationを書く手間は省けますよね。
varcharの長さとかそういうのも対称にすれば、もう少しちゃんとしたvalidationもできそうです。

・・・というか実際のnot nullチェックとかってみなさんどうしてるんでしょ?^^;

Category: PHP | Posted on: 2007/10/19 12:10 | Viewed: 1900

Comments

No comments yet

Add Comment

:

:
:

TrackBacks

このエントリにトラックバックはありません

TrackBack URL

http://www.azul.systems-noel.jp/trackback/item_73.html