phalconplus Documentation v1.2.0
Class PhalconPlus App

App

    namespace PhalconPlus\App;
use Phalcon\Application as BaseApplication;
use PhalconPlus\Enum\Sys as Sys;
use PhalconPlus\App\Module\ModuleDef;
use Phalcon\DiInterface;
use Phalcon\Di;
use PhalconPlus\App\Module\AbstractModule;
use PhalconPlus\Enum\RunEnv;
use PhalconPlus\Enum\Facade;
use Phalcon\Config;
use PhalconPlus\Base\Exception as BaseException;
use Phalcon\Events\ManagerInterface;

final class App extends BaseApplication
{
    // <\Phalcon\Debug>
    protected debug = null;
    // 默认运行环境
    // 其实框架定义了<\PhalconPlus\Enum\RunEnv>,但考虑再三,此处不能做枚举限制
    // Enum: ['dev', 'test', 'pre-production', 'production']
    protected env = RunEnv::DEV;
    protected booted = false;
    // 全局配置 <\Phalcon\Config>
    protected config = null { get };
   
    public function __construct( config)
    {
        // 全局配置
        let this->config = config;
        Sys::initApp(this);
    }

    public function boot(string env = "", string runMode = "") -> 
    {
        // 获取并初始化运行环境
        if likely empty env {
            // 获取php.ini中设置的env    
            var sysEnv = trim(get_cfg_var(Sys::ENV_NAME));
            // 这里不能强约束env的值为枚举中的一个
            // 你可能会有非常多的环境,只要env值和配置文件名能对应上就行
            if !empty sysEnv { let this->env = sysEnv; }
        } else {
            let this->env = env;
        }

        // 定义全局常量
        define("APP_ENV", this->env, false); // 为了兼容, 同下
        define("APP_RUN_ENV", this->env, false);
        define("APP_ROOT_DIR", Sys::getRootDir(), false);
        define("APP_MODULE_DIR", Sys::getPrimaryModuleDir(), false); // 为了兼容, 同下
        define("APP_PRI_MODULE_DIR", Sys::getPrimaryModuleDir(), false);
        define("APP_ROOT_COMMON_DIR", Sys::getCommonDir(), false);
        define("APP_ROOT_COMMON_LOAD_DIR", Sys::getGlobalLoadDir(), false);
        define("APP_ROOT_COMMON_CONF_DIR", Sys::getGlobalConfigDir(), false);

        // 加载Facacdes
        Facade::register(this, "\\Ph\\");

        return this->bootPrimaryModule(runMode);
    }

    private function bootPrimaryModule(string runMode = "") -> 
    {
        // 初始化主模块
        var primaryModuleDef;
        let primaryModuleDef = new ModuleDef(this, Sys::getPrimaryModuleDir(), true, runMode);
        this->setDI(primaryModuleDef->newDI());
        this->getDI()->setShared("superApp", this);
        this->getDI()->setShared("config", this->config);
        this->getDI()->setShared("loader", new \Phalcon\Loader());
        // App启动成功
        let this->booted = true;
        // 注册主模块
        var module = this->registerModule(primaryModuleDef);
        if module->isWeb() {
            if !RunEnv::isInProd(this->env) {
                let this->debug = new \Phalcon\Debug();
                this->debug->listen();
            }
        }
        return this;
    }

    private function registerModule( moduleDef) -> 
    {
        if unlikely isset(this->_modules[moduleDef->getName()]) {
            return this->_modules[moduleDef->getName()];
        }
        if unlikely is_null(this->_dependencyInjector) {
            throw new BaseException("DI doesn't load yet, failed to register module " . moduleDef->getName());
        }
        if unlikely is_null(this->config) {
            throw new BaseException("Config doesn't initial yet, failed to register module " . moduleDef->getName());
        }
        // Load PrimaryModule-Related Config and Global-Script
        if moduleDef->isPrimary() {
            // 定义工作模式
            if !defined("APP_RUN_MODE") { define("APP_RUN_MODE", moduleDef->getMode(), false); }
            // 获取模块配置
            var moduleConf = moduleDef->getConfig();
            // 合并配置,Module配置优先级更高
            this->config->merge(moduleConf);
        }
        // checkout a module instance from it's defintion
        var module = moduleDef->checkout();
        if module->isPrimary() {
            let this->_defaultModule = module;
        }
        
        // Maintain a HashMap of loaded modules
        let this->_modules[moduleDef->getName()] = module;
        return module;
    }

    public function dependModule(string! moduleName) -> 
    {
        var module, moduleDef, moduleDir, moduleConf;
        let moduleDir = Sys::getModuleDirByName(moduleName);
        let moduleDef = new ModuleDef(this, moduleDir);
        // 注册模块
        let module = this->registerModule(moduleDef);
        // 参与合并的模块配置
        var tmp = Sys::load(moduleDef->getConfigPath());
        let moduleConf = new Config(tmp);
        // 全局配置文件优先级高于被依赖的模块
        moduleConf->merge(this->config);
        this->setConfig(moduleConf);
        return module;
    }

    // 传入的 Config 优先级更高
    public function setConfig( config) -> 
    {
        if is_null(this->config) {
            let this->config = new Config();
        }
        this->config->merge(config);
        // this->getDI()->setShared("config", this->config);
        return this;
    }

    public function isDebug() -> boolean
    {
        return null !== this->debug;
    }

    public function isBooted() -> boolean
    {
        return this->booted === true;
    }

    public function getDebug() -> <\Phalcon\Debug>
    {
        return this->debug;
    }

    public function getEnv() -> string
    {
        return this->env;
    }

    public function setEnv(string env) -> 
    {
        let this->env = env;
        return this;
    }

    public function handle()
    {
        if false == this->booted {
            this->bootPrimaryModule();
        }

        var eventsManager, response, params = func_get_args();

        let eventsManager =  this->_eventsManager;
        if typeof eventsManager == "object" {
            if eventsManager->fire("superapp:beforeExecModule", this, [this->_defaultModule, params]) === false {
                // 
                // error_log(var_export(params, true));
            }
        }

        let response = this->_defaultModule->exec(params);

        if typeof eventsManager == "object" {
            if eventsManager->fire("superapp:afterExecModule", this, [this->_defaultModule, response]) === false {
                // 
                // error_log(var_export(response, true));
            }
        }
        
        return response;
    }

    public function terminate()
    {
        if session_status() == PHP_SESSION_ACTIVE { 
            session_write_close(); 
        }

        // empty session id
        if !headers_sent() { session_id(""); }

        // reset global variables
        let _SESSION = [], _POST = [],  _GET = [], _SERVER = [],
            _REQUEST = [], _COOKIE = [], _FILES = [];

        let this->_modules = [];
        let this->_defaultModule = null;
        let this->booted = false;
        Di::reset();

        let this->_dependencyInjector = null;
        // let this->config = null;
        
    }

    public function getDefaultModuleDef() -> 
    {
        return this->_defaultModule->def();
    }

    public function getPrimaryModuleDef() -> 
    {
        return this->_defaultModule->def();
    }

    public function setDefaultModule(string defaultModule) -> 
    {
        // 
        return this;
    }
    
    public function getDefaultModule() -> string
    {
        return this->_defaultModule->getName();
    }

    public function getPrimaryModule() -> 
    {
        var name = this->_defaultModule->getName();
        if !isset(this->_modules[name]) {
            throw new BaseException("Module not exists: " . name);
        }
        return this->_modules[name];
    }

    public function getModule(string! name = "") -> 
    {
        if name === "" {
            return this->_defaultModule;
        }
        if !isset(this->_modules[name]) {
            throw new BaseException("Module not exists: " . name);
        }
        return this->_modules[name];
    }

    public function getModuleDef(string! name = "") -> 
    {
        if name === "" {
            return this->_defaultModule->def();
        }
        if !isset(this->_modules[name]) {
            throw new BaseException("Module not exists: " . name);
        }
        return this->_modules[name]->def();
    }

    public function config() -> 
    {
        return this->config;
    }

    public function di() -> 
    {
        return this->_dependencyInjector;
    }

    public function __call(string method, array params)
    {
        var dependencyInjector, service;
        if ! this->isBooted() {
            return null;
        }
        let dependencyInjector =  this->_dependencyInjector;
        if dependencyInjector->has(method) {
            let service = dependencyInjector->get(method, params);
            return service;
        }
        return null;
    }
}