<?php
/**
 * ActionClassLoader.
 * @package magic.core
 * @subpackage internal.loader
 */
/**
 * Actionクラスのローダーです.
 * <p>
 * これは必ずコールされます。<br/>
 * アプリケーションには、最低一つ以上のActionクラスが存在しなければいけません。
 * </p>
 * @package magic.core
 * @subpackage internal.loader
 * @author T.Okumura
 * @version 1.0.0
 * @final
 */
final class ActionClassLoader {
    /**
     * コンストラクタ.
     */
    private function __construct() {
    }
    /**
     * Actionクラスをロードします.
     * @param string $className ロードするクラス名
     * @param NameConfigure $name 命名規則設定クラス
     * @param PathConfigure $path パス設定クラス
     * @return Action Actionクラスを継承したクラス
     * @throws MagicException クラスがロードできなかった時
     * @static
     */
    public static function load($className, NameConfigure $name, PathConfigure $path) {
        $className = $name->getPhpFileNamingType()->apply($className) . $path->getActionSuffix();
        $classPath = $path->getActionPath();
        $classFile = $className . '.php';
        if (!@include_once $classPath . $classFile) {
            throw new MagicException(MessageBehavior::getMessage('SYS001', $classPath . $classFile));
        }
        $className = $name->getClassNamingType()->apply($className);
        if (!class_exists($className, FALSE)) {
            throw new MagicException(MessageBehavior::getMessage('SYS004', $className));
        }
        $class = new $className();
        if ($class instanceof Action) {
            return $class;
        }
        throw new MagicException(MessageBehavior::getMessage('SYS002', array('Action', $className)));
    }
    /**
     * コールするファンクション名を取得します.
     * @param Action $action Actionクラスを継承したクラス
     * @param string $methodName エントリポイントとなるファンクション名
     * @param NameConfigure $name 命名規則設定クラス
     * @return string ファンクションが存在していればファンクション名
     * @throws MagicException ファンクションが存在しない場合
     * @static
     */
    public static function getMethod(Action $action, $methodName, NameConfigure $name) {
        $methodName = $name->getMethodNamingType()->apply($methodName);
        if (in_array($methodName, get_class_methods($action))) {
            return $methodName;
        }
        throw new MagicException(MessageBehavior::getMessage('SYS005', get_class($action) . '::' . $methodName . '()'));
    }
    /**
     * Actionクラスに存在するプロパティを取得します.
     * <p>
     * public及びprotectedの変数(プロパティ)のみを取得します。<br/>
     * フレームワークによって自動的にinjectさせるためには、
     * 必ずPHPDoc形式による(@var)で注釈してください。
     * オブジェクトの型がわからなければ、フレームワークがinjectする事はできません。
     * </p>
     * @param Action $action Actionクラスを継承したクラス
     * @param PathConfigure $path パス設定クラス
     * @return array 取得できたプロパティの配列
     * @static
     */
    public static function getProperties(Action $action, PathConfigure $path) {
        $result = array('prop' => array(), 'dao' => array(), 'dto' => array());
        $matches = array();
        $ref = new ReflectionClass(get_class($action));
        $props = $ref->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED);
        foreach ($props as $prop) {
            preg_match('/@var\s+(\w+)/', $prop->getDocComment(), $matches);
            if (StringUtil::endWith($matches[1], $path->getDaoSuffix())) {
                $result['dao'][$prop->getName()] = $matches[1];
            } elseif (StringUtil::endWith($matches[1], $path->getDtoSuffix())) {
                $result['dto'][$prop->getName()] = $matches[1];
            } else {
                $result['prop'][$prop->getName()] = $matches[1];
            }
        }
        return $result;
    }
    /**
     * Actionクラスに存在するゲッターメソッドを取得します.
     * <p>
     * ゲッターメソッドは、getまたはisで始まる必要があります。
     * </p>
     * @param Action $action Actionクラスを継承したクラス
     * @return array 取得できたゲッターメソッドの配列
     * @static
     */
    public static function getGetterMethods(Action $action) {
        $result = array();
        $methods = get_class_methods($action);
        foreach ($methods as $method) {
            if (StringUtil::startWith($method, 'get') || StringUtil::startWith($method, 'is')) {
                $result[] = $method;
            }
        }
        return $result;
    }
}
// EOF.