phalconplus Documentation v1.3.0-development
Class
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 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 };
        // 处理请求次数
        protected requestNumber = 0;
        // 需要手动关闭的服务，一般是有状态服务，如Mysql、Redis等
        protected finalizers = [];

        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 global constants
            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);

            return this->bootPrimaryModule(runMode);
        }

        private function bootPrimaryModule(string runMode = "") ->
        {
            // 初始化主模块
            var primaryModuleDef;
            let primaryModuleDef = new ModuleDef(this, Sys::getPrimaryModuleDir(), true, runMode);
            if this->_dependencyInjector == null {
                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;
        }

        // import exportable module
        public function import(string! moduleName) ->
        {
            return this->dependModule(moduleName, false);
        }

        public function dependModule(string! moduleName, bool force = true) ->
        {
            let moduleName = trim(moduleName);
            if unlikely isset(this->_modules[moduleName]) {
                return this->_modules[moduleName];
            }
            var moduleDef;
            let moduleDef = new ModuleDef(this, Sys::getModuleDirByName(moduleName));
            if force === false {
                if moduleDef->config()->path("application.exportable", false) == false {
                    throw new BaseException(moduleName . " can't be imported as external library.");
                }
            }

            // 参与合并的模块配置
            var moduleConf = null,
                arrayConf = Sys::load(moduleDef->getConfigPath()),
                // 注册模块
                module = this->registerModule(moduleDef);

            let moduleConf = new Config(arrayConf);

            // 全局配置文件优先级高于被依赖的模块
            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);
            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()
        {
            let this->requestNumber = this->requestNumber + 1;
            // If app booted is false, reboot it again here.
            if false == this->booted {
                this->bootPrimaryModule();
            }

            var eventsManager = null,
                response = null,
                params = func_get_args();

            let eventsManager =  this->_eventsManager;
            if typeof eventsManager == "object" {
                if eventsManager->fire("superapp:beforeExecModule", this, [this->_defaultModule, params]) === false {
                    //
                }
            }
            // Exec primary module, and get response
            let response = this->_defaultModule->exec(params);

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

        public function terminate(bool deeply = true)
        {
            // Close SESSION here
            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;

            var finalizer;
            for finalizer in this->finalizers {
                {finalizer}();
            }
            let this->finalizers = [];
            if deeply === true {
                Di::reset();
                let this->_dependencyInjector = null;
            }
        }

        public function defer(callable handler)
        {
            let this->finalizers[] = handler;
            return this;
        }

        public function getRequestNumber() -> int
        {
            return this->requestNumber;
        }

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

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

        public function setDefaultModule(string defaultModule) ->
        {
            // nothing here...
            return this;
        }

        public function getDefaultModule() -> string
        {
            // Constraited by parent class, have to return module-name as 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 = null;

            // If App not booted, return null
            if ! this->isBooted() {
                return null;
            }

            let dependencyInjector =  this->_dependencyInjector;
            if dependencyInjector->has(method) {
                return dependencyInjector->get(method, params);
            }
            return null;
        }
    }