phalconplus Documentation v1.1.0
Class
Class PhalconPlus

# Bootstrap

        //
        protected config = null;
        // 全局DI容器 <\Phalcon\Di>
        protected di = null {
            set, get
        };
        // 应用实例 <\Phalcon\Application> | <\Yar_Server>
        protected application = null;
        // 模块实例 <\PhalconPlus\Base\ModuleDef>
        protected primaryModuleDef = null;
        // 加载的模块实例列表 <\PhalconPlus\Base\ModuleDef>[]
        protected activeModules = [];
        // <\Phalcon\Debug>
        protected debug = null;
        // 默认运行环境
        // 其实框架定义了<\PhalconPlus\Enum\RunEnv>，但考虑再三，此处不能做枚举限制
        // Enum: ['dev', 'test', 'pre-production', 'production']
        protected env = \PhalconPlus\Enum\RunEnv::DEV;
        // 自动处理应用
        protected autoHandle = true {
            set, get
        };

        protected loadedFiles = [] {
            get
        };

        public function __construct(string! moduleDir, string env = "")
        {
            // 模块目录, PrimaryModule Dir
            Sys::init(moduleDir);
            // 获取并初始化运行环境
            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;
            }

            // 如果不是生产环境，打开Debug
            // 这里我们假设生产环境的env值会以"product"开头
            if substr(PHP_SAPI, 0, 3) != "cli" && !\PhalconPlus\Enum\RunEnv::isInProd(this->env) {
                let this->debug = new \Phalcon\Debug();
                this->debug->listen();
            }

            // 定义全局常量
            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);

            // 加载Composer库
            if likely is_file(Sys::getComposerAutoloadPath()) {
                require Sys::getComposerAutoloadPath();
            }
        }

        private function registerModule(<\PhalconPlus\Base\ModuleDef> moduleDef) -> <\PhalconPlus\Base\AbstractModule>
        {
            if unlikely isset(this->activeModules[moduleDef->getName()]) {
                return this->activeModules[moduleDef->getName()];
            }
            if unlikely is_null(this->di) {
                throw new \PhalconPlus\Base\Exception("DI doesn't load yet, failed to register module " . moduleDef->getName());
            }
            if unlikely is_null(this->config) {
                throw new \PhalconPlus\Base\Exception("Config doesn't initial yet, failed to register module " . moduleDef->getName());
            }
            // Load PrimaryModule-Related Config and Global-Script
            if moduleDef->getIsPrimary() {
                // 定义工作模式
                if !defined("APP_RUN_MODE") { define("APP_RUN_MODE", moduleDef->getMode(), false); }
                // 获取模块配置
                var moduleConf = moduleDef->getConfig();
                // 合并配置，Module配置优先级更高
                this->config->merge(moduleConf);
                // 装载全局服务初始化文件
                this->load(moduleDef->getRunMode()->getScriptPath());
            }
            // Implement a module from it's defintion
            var module = moduleDef->impl(this->di);

            // Register autoloaders and di-services
            module->registerAutoloaders();
            module->registerServices();

            // Maintain a list of loaded modules
            let this->activeModules[moduleDef->getName()] = module;
            return module;
        }

        public function initConf() -> <\PhalconPlus\Bootstrap>
        {
            // 全局配置
            var globalConfPath = Sys::getGlobalConfigPath();
            if unlikely !is_file(globalConfPath) {
                // throw new \Phalcon\Config\Exception("Global config file not exist, file position: " . globalConfPath);
                // Make a warning here
                error_log("PHP Notice:  PhalconPlus\\Bootstrap Global config file not exists: " . globalConfPath);
                let this->config = new \Phalcon\Config([]);
            } else {
                let this->config = new \Phalcon\Config(this->load(globalConfPath));
            }
            // 初始化主模块
            if empty this->primaryModuleDef {
                let this->primaryModuleDef = new \PhalconPlus\Base\ModuleDef(this, APP_MODULE_DIR, true);
            }
            // 返回对象本身
            return this;
        }

        public function setApp(object app, boolean autoHandle = false) -> <\PhalconPlus\Bootstrap>
        {
            if likely empty(this->application) {
                if likely (app instanceof \Phalcon\Application) || (app instanceof \Yar_Server) {
                    let this->application = app;
                    let this->autoHandle = autoHandle;
                } else {
                    throw new \PhalconPlus\Base\Exception("Application must be instance of phalcon\\appliction or yar_server");
                }
            }
            return this;
        }

        // return object | null
        public function getApp() -> object | null
        {
            if unlikely empty(this->application) {
                throw new \PhalconPlus\Base\Exception("Sorry, empty application in bootstrap");
            }
            return this->application;
        }

        // 统一入口，也可分别调用各模式入口
        public function exec()
        {
            // 初始化配置
            this->initConf();
            // 主执行方法入口
            var handleMethod = "exec";
            let handleMethod .= this->primaryModuleDef->getMapClassName();
            return call_user_func_array([this, handleMethod], func_get_args());
        }

        public function terminate()
        {
            if session_status() == PHP_SESSION_ACTIVE { session_write_close(); }
            if !headers_sent() { session_id(""); }

            session_unset();

            let _SESSION = [];
            let _POST = [];
            let _GET = [];
            let _SERVER = [];
            let _REQUEST = [];
            let _COOKIE = [];
            let _FILES = [];

            \Phalcon\Di::reset();
            let this->di = null;
            let this->config = null;
            let this->application = null;
            let this->loadedFiles = [];
            let this->primaryModuleDef = null;
            let this->activeModules = [];
        }

        public function __destruct()
        {
            this->terminate();
        }

        /**
         * @request a uri string (for \Phalcon\Mvc\Application) or Psr\Http\Message\Request
         */
        public function execModule(var request = null) -> <\PhalconPlus\Bootstrap> | <\Phalcon\Http\Response>
        {
            // 如果此方法被直接调用需要自己加载配置
            if empty this->config { this->initConf(); }
            // 初始化容器
            if empty this->di {
                let this->di = new \Phalcon\DI\FactoryDefault();
                // 把自己注入di
                this->di->setShared("bootstrap", this);
            }

            // Phalcon Mvc Application
            if unlikely empty(this->application) {
                let this->application = new \Phalcon\Mvc\Application();
            }
            this->application->setDI(this->di);

            // 注册模块
            this->registerModule(this->primaryModuleDef);
            // 如果不需要handle，则直接返回
            if !this->autoHandle { return this; }

            // Handle
            return this->application->handle(request);
        }

        public function execSrv() -> <\Phalcon\Http\Response> | <\PhalconPlus\Bootstrap>
        {
            // 如果此方法被直接调用需要自己加载配置
            if empty this->config { this->initConf(); }
            // 初始化容器
            if empty this->di {
                let this->di = new \Phalcon\DI\FactoryDefault();
                this->di->setShared("bootstrap", this);
            }

            // 注册模块
            this->registerModule(this->primaryModuleDef);

            var backendSrv = null;
            // Backend Server, Default is SimpleServer
            if unlikely this->di->has("backendSrv") {
                let backendSrv = this->di->get("backendSrv");
                if ! (backendSrv instanceof \PhalconPlus\Rpc\Server\AbstractServer) {
                    throw new \PhalconPlus\Base\Exception("Service object(DI[\"backendSrv\"]) must be type of \\PhalconPlus\\Rpc\\Server\\AbstractServer");
                }
            } else {
                let backendSrv = new \PhalconPlus\Rpc\Server\SimpleServer(this->di);
                this->di->setShared("backendSrv", backendSrv);
            }

            // Yar Server
            if unlikely empty(this->application) {
                let this->application = new \Yar_Server(backendSrv);
            }

            // 如果不需要handle，则直接返回
            if !this->autoHandle { return this; }

            // Handle
            ob_start();
            this->application->handle();
            var content = ob_get_clean();

            var response;
            let response = new \Phalcon\Http\Response();
            response->setStatusCode(200, "OK");
            response->setContent(content);
            return response;
        }

        public function execTask(array argv, <\Phalcon\DI\FactoryDefault> di = null)
        {
            // 如果此方法被直接调用需要自己加载配置
            if empty this->config { this->initConf(); }
            if empty this->di {
                if likely is_null(di) || ! (di instanceof \Phalcon\DI\FactoryDefault\CLI) {
                    let this->di = new \Phalcon\DI\FactoryDefault\CLI();
                } else {
                    let this->di = di;
                }
                this->di->setShared("bootstrap", this);
            }

            // Phalcon Cli Application
            if unlikely empty(this->application) {
                let this->application = new \Phalcon\CLI\Console();
            }
            this->application->setDI(this->di);

            // 注册模块
            this->registerModule(this->primaryModuleDef);

            // 如果不需要handle，则直接返回
            if !this->autoHandle { return this; }

            // Handle
            return this->application->handle(argv);
        }

        public function getPrimaryModuleDef() -> <\PhalconPlus\Base\ModuleDef>
        {
            return this->primaryModuleDef;
        }

        public function getPrimaryModule() -> <\PhalconPlus\Base\AbstractModule>
        {
            var name = this->primaryModuleDef->getName();
            if !isset(this->activeModules[name]) {
                throw new \PhalconPlus\Base\Exception("Module not exists: " . name);
            }
            return this->activeModules[name];
        }

        public function getModule(string! name) -> <\PhalconPlus\Base\AbstractModule>
        {
            if !isset(this->activeModules[name]) {
                throw new \PhalconPlus\Base\Exception("Module not exists: " . name);
            }
            return this->activeModules[name];
        }

        public function getModuleDef(string! name) -> <\PhalconPlus\Base\ModuleDef>
        {
            if !isset(this->activeModules[name]) {
                throw new \PhalconPlus\Base\Exception("Module not exists: " . name);
            }
            return this->activeModules[name]->getDef();
        }

        public function dependModule(string! moduleName) -> <\PhalconPlus\Base\AbstractModule>
        {
            var module, moduleDef, moduleDir, moduleConf;
            let moduleDir = Sys::getModuleDirByName(moduleName);
            let moduleDef = new \PhalconPlus\Base\ModuleDef(this, moduleDir);
            // 注册模块
            let module = this->registerModule(moduleDef);

            // 保留被依赖的模块的配置, 已经移除
            // this->di->set("moduleConfig", moduleDef->getConfig());
            // Use `$bootstrap->getModuleDef($moduleName)->getConfig()` instead

            // 参与合并的模块配置
            let moduleConf = new \Phalcon\Config(this->load(moduleDef->getConfigPath()));
            // 全局配置文件优先级高于被依赖的模块
            moduleConf->merge(this->config);
            this->setConfig(moduleConf);
            return module;
        }

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

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

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

        public function getConfig() -> <\Phalcon\Config>
        {
            return this->config;
        }

        // 传入的 Config 优先级更高
        public function setConfig(<\Phalcon\Config> config)
        {
            var globalConf;
            if ! this->di->has("config") {
                let globalConf = new \Phalcon\Config();
            } else {
                let globalConf = this->di->getConfig();
            }
            globalConf->merge(config);
            let this->config = globalConf;
            this->di->set("config", this->config);
            return this;
        }

        public function load(var filePath)
        {
            if unlikely !is_string(filePath) {
                return false;
            }

            if unlikely !is_file(filePath) {
                throw new \PhalconPlus\Base\Exception("The file you try to load is not exists. file position: " . filePath);
            }

            var loader, config, application, di;
            var bootstrap, rootPath, fileRet;

            if fetch fileRet, this->loadedFiles[filePath] {
                return fileRet;
            }

            let
              rootPath = "rootPath",
              loader = "loader",
              config = "config",
              application = "application",
              bootstrap = "bootstrap",
              di = "di";

            let {rootPath} = Sys::getRootDir();
            let {loader} = new \Phalcon\Loader();
            let {config} = this->config;
            let {application} = this->application;
            let {bootstrap} = this;
            let {di} = this->di;

            /* PHP 7.1 and later version, forbid dynamic calls to scope introspection functions
            extract(["rootPath": APP_ROOT_DIR,
                     "loader": new \Phalcon\Loader(),
                     "config": this->config,
                     "application": this->application,
                     "bootstrap": this,
                     "di": this->di
            ]);
            */

            let fileRet = require filePath;
            let this->loadedFiles[filePath] = fileRet;
            return fileRet;
        }
    }