Procházet zdrojové kódy

Add namespace配置文件及bigpipe.js

Zhu Jinhui před 7 roky
rodič
revize
a5d235e3dd
5 změnil soubory, kde provedl 507 přidání a 68 odebrání
  1. 7 3
      src/Application.php
  2. 37 2
      src/Autoloader/Psr4.php
  3. 53 0
      src/Conf/namespace.php
  4. 375 0
      src/Library/BigPipe/bigpipe.js
  5. 35 63
      src/Qii.php

+ 7 - 3
src/Application.php

@@ -153,12 +153,11 @@ class Application
     }
     /**
      * 获取网站的配置文件
-     * @return Mix
+     * @return Config\Mix
      */
     public function getAppIniFile()
     {
         return Register::get(Consts::APP_INI_FILE);
-        return $this;
     }
 
     /**
@@ -363,7 +362,12 @@ class Application
     {
         return call_user_func_array(array('\Qii\Exceptions\Errors', 'e'), func_get_args());
     }
-	
+
+    /**
+     * 执行
+     * @return $this
+     * @throws \Exception
+     */
 	public function run()
 	{
         $this->helper->load(self::$workspace);

+ 37 - 2
src/Autoloader/Psr4.php

@@ -69,14 +69,32 @@ class Psr4
     /**
      * 注册自动加载类
      *
-     * @return void
+     * @return $this
      */
     public function register()
     {
         spl_autoload_register(array($this, 'loadFileByClass'));
         return $this;
     }
-
+    /**
+     * Setting is use namespaces for class
+     *
+     * @param $prefix 以prefix前缀开头的使用namespace
+     * @param bool $useNamespace
+     * @return object $this
+     */
+    public function setUseNamespaces($arr)
+    {
+        if(!is_array($arr))
+        {
+            return $this;
+        }
+        foreach($arr as $namespace)
+        {
+            call_user_func_array(array($this, 'setUseNamespace'), $namespace);
+        }
+        return $this;
+    }
     /**
      * Setting is use namespace for class
      *
@@ -90,6 +108,23 @@ class Psr4
         return $this;
     }
 
+    /**
+     * Adds a base directory for namespace prefix
+     * @param $arr
+     * @return $this
+     */
+    public function addNamespaces($arr)
+    {
+        if(!is_array($arr))
+        {
+            return $this;
+        }
+        foreach ($arr as $namespace)
+        {
+            call_user_func_array(array($this, 'addNamespace'), $namespace);
+        }
+        return $this;
+    }
     /**
      * Adds a base directory for a namespace prefix.
      *

+ 53 - 0
src/Conf/namespace.php

@@ -0,0 +1,53 @@
+<?php
+/**
+ * Qii 名称空间配置
+ * @author zjh
+ * @version 1.3
+ */
+return [
+    //设置是否使用名称空间
+    'setUseNamespace' => [
+        ['Qii\\', true],
+        ['Qii\Action', true],
+        ['Qii\Autoloader', true],
+        ['Qii\Bootstrap', true],
+        ['Qii\Config', true],
+        ['Qii\Consts', true],
+        ['Qii\Controller', true],
+        ['Qii\Exceptions', true],
+        ['Qii\Language', true],
+        ['Qii\Library', true],
+        ['Qii\Loger', true],
+        ['Qii\Plugin', true],
+        ['Qii\Request', false],
+        ['Qii\Router', true],
+        ['Qii\View', true],
+        ['WhichBrowser', true],
+        ['BigPipe', true],
+        ['Smarty\\', false],
+        ['Smarty\\Internal', false],
+    ],
+    //设置指定名称空间的文件路径,如按照namespace的不用指定
+    'addNamespace' => [
+        ['Qii\\', Qii_DIR . DS],
+        ['Qii\Action', Qii_DIR . DS . 'Action'],
+        ['Qii\Autoloader', Qii_DIR . DS . 'Autoloader'],
+        ['Qii\Controller', Qii_DIR . DS . 'Controller'],
+        ['Qii\Bootstrap', Qii_DIR . DS . 'Bootstrap'],
+        ['Qii\Config', Qii_DIR . DS . 'Config'],
+        ['Qii\Consts', Qii_DIR . DS . 'Consts'],
+        ['Qii\Exceptions', Qii_DIR . DS . 'Exceptions'],
+        ['Qii\Language', Qii_DIR . DS . 'Language'],
+        ['Qii\Library', Qii_DIR . DS . 'Library'],
+        ['Qii\Loger', Qii_DIR . DS . 'Loger'],
+        ['Qii\Plugin', Qii_DIR . DS . 'Plugin'],
+        ['Qii\Request', Qii_DIR . DS . 'Request'],
+        ['Qii\Response', Qii_DIR . DS . 'Response'],
+        ['Qii\Router', Qii_DIR . DS . 'Router'],
+        ['Qii\View', Qii_DIR . DS . 'View'],
+        ['Smarty', Qii_DIR . DS . 'View' . DS . 'smarty'],
+        ['Smarty', Qii_DIR . DS . 'View' . DS . 'smarty' . DS . 'sysplugins'],
+        ['WhichBrowser', Qii_DIR . DS . 'Library'. DS . 'Third'. DS . 'WhichBrowser'],
+        ['BigPipe', Qii_DIR . DS . 'Library'. DS .'BigPipe'. DS .'BigPipe']
+    ]
+];

+ 375 - 0
src/Library/BigPipe/bigpipe.js

@@ -0,0 +1,375 @@
+//==============================================================================
+// BigPipe Module
+//==============================================================================
+BigPipe = (function() {
+	"use strict";
+
+	//==============================================================================
+	// PhaseDoneJS: Responsible for Pagelet and Resource
+	//==============================================================================
+	const PhaseDoneJS = {
+		//==============================================================================
+		// Increase phase and execute callbacks
+		//==============================================================================
+		handler(context, phase) {
+			for(let currentPhase = context.phase; currentPhase <= phase; ++currentPhase) {
+				this.execute(context, currentPhase);
+			}
+
+			return context.phase = ++phase;
+		},
+
+		//==============================================================================
+		// Execute callbacks of the given phase
+		//==============================================================================
+		execute(context, phase) {
+			context.phaseDoneJS[phase].forEach(function(code) {
+				try {
+					window.eval.call(window, code);
+				} catch(e) {
+					console.error("PhaseDoneJS: " + e);
+				}
+			});
+		}
+	};
+
+	//==============================================================================
+	// Resource: Represents a resource
+	//==============================================================================
+	class Resource {
+		constructor(data, type) {
+			this.ID   = data.ID;
+			this.HREF = data.HREF;
+			this.callbacks = [];
+			this.node = false;
+			this.done = false;
+			this.type = type;
+
+			this.phaseDoneJS = data.PHASE;
+			this.phase = 0;
+
+			PhaseDoneJS.handler(this, Resource.PHASE_INIT);
+		}
+
+		//==============================================================================
+		// Resource types
+		//==============================================================================
+		static get TYPE_STYLESHEET() { return 0; }
+		static get TYPE_JAVASCRIPT() { return 1; }
+
+		//==============================================================================
+		// Phase numbers for PhaseDoneJS
+		//==============================================================================
+		static get PHASE_INIT() { return 0; }
+		static get PHASE_LOAD() { return 1; }
+		static get PHASE_DONE() { return 2; }
+
+		//==============================================================================
+		// Loading the resource
+		//==============================================================================
+		execute() {
+			switch(this.type) {
+				case Resource.TYPE_STYLESHEET:
+					this.node = document.createElement("link");
+					this.node.setAttribute("rel", "stylesheet");
+					this.node.setAttribute("href", this.HREF);
+					break;
+				case Resource.TYPE_JAVASCRIPT:
+					this.node = document.createElement("script");
+					this.node.setAttribute("src", this.HREF);
+					this.node.setAttribute("async", "async");
+					break;
+				default:
+					return false;
+			}
+
+			const callback = () => {
+				PhaseDoneJS.handler(this, Resource.PHASE_DONE);
+				this.executeCallbacks();
+			};
+
+			this.node.onload  = callback;
+			this.node.onerror = callback;
+
+			document.head.appendChild(this.node);
+
+			PhaseDoneJS.handler(this, Resource.PHASE_LOAD);
+		}
+
+		//==============================================================================
+		// Register a new callback
+		//==============================================================================
+		registerCallback(callback) {
+			return this.callbacks.push(callback);
+		}
+
+		//==============================================================================
+		// Executes all registered callbacks
+		//==============================================================================
+		executeCallbacks() {
+			if(!this.done && (this.done = true)) {
+				this.callbacks.forEach(function(callback) {
+					callback();
+				});
+			}
+		}
+
+		//==============================================================================
+		// Remove callbacks after abort of loading the resource
+		//==============================================================================
+		abortLoading() {
+			if(this.node) {
+				this.node.onload  = null;
+				this.node.onerror = null;
+
+				// Remove element from DOM
+				let parentNode = this.node.parentNode;
+				return parentNode.removeChild(this.node);
+			}
+		}
+	}
+
+	//==============================================================================
+	// Pagelet: Represents a pagelet
+	//==============================================================================
+	class Pagelet {
+		constructor(data, HTML) {
+			this.ID   = data.ID;
+			this.NEED = data.NEED;
+			this.HTML = HTML;
+			this.JSCode = data.CODE;
+			this.phaseDoneJS = data.PHASE;
+			this.stylesheets = data.RSRC[Resource.TYPE_STYLESHEET];
+			this.javascripts = data.RSRC[Resource.TYPE_JAVASCRIPT];
+
+			this.phase = 0;
+			this.resources = [[], []];
+
+			PhaseDoneJS.handler(this, Pagelet.PHASE_INIT);
+		}
+
+		//==============================================================================
+		// Phase numbers for PhaseDoneJS
+		//==============================================================================
+		static get PHASE_INIT()    { return 0; }
+		static get PHASE_LOADCSS() { return 1; }
+		static get PHASE_HTML()    { return 2; }
+		static get PHASE_LOADJS()  { return 3; }
+		static get PHASE_DONE()    { return 4; }
+
+		//==============================================================================
+		// Initialize and execute the CSS resources
+		//==============================================================================
+		execute() {
+			this.initializeResources();
+
+			if(!this.executeResources(Resource.TYPE_STYLESHEET)) {
+				this.replaceHTML();
+			}
+		}
+
+		//==============================================================================
+		// Initialize the pagelet resources
+		//==============================================================================
+		initializeResources() {
+			this.stylesheets.forEach(data => {
+				this.attachResource(new Resource(data, Resource.TYPE_STYLESHEET));
+			});
+
+			this.javascripts.forEach(data => {
+				this.attachResource(new Resource(data, Resource.TYPE_JAVASCRIPT));
+			});
+		}
+
+		//==============================================================================
+		// Executes all resources of the specific type
+		//==============================================================================
+		executeResources(type) {
+			let somethingExecuted = false;
+
+			this.resources[type].forEach(function(resource) {
+				somethingExecuted = true;
+				resource.execute();
+			});
+
+			return somethingExecuted;
+		}
+
+		//==============================================================================
+		// Attach a new resource to the pagelet
+		//==============================================================================
+		attachResource(resource) {
+			switch(resource.type) {
+				case Resource.TYPE_STYLESHEET:
+					resource.registerCallback(() => this.onStylesheetLoaded());
+					break;
+
+				case Resource.TYPE_JAVASCRIPT:
+					resource.registerCallback(() => this.onJavascriptLoaded());
+					break;
+			}
+
+			return this.resources[resource.type].push(resource);
+		}
+
+		//==============================================================================
+		// Replaces the placeholder node HTML
+		//==============================================================================
+		replaceHTML() {
+			document.getElementById(this.ID).innerHTML = this.HTML;
+
+			PhaseDoneJS.handler(this, Pagelet.PHASE_HTML);
+
+			BigPipe.onPageletHTMLreplaced(this.ID);
+		}
+
+		//==============================================================================
+		// Executes the inline javascript code of the pagelet
+		//==============================================================================
+		executeInlineJavascript() {
+			this.JSCode.forEach(code => {
+				try {
+					window.eval.call(window, code);
+				} catch(e) {
+					console.error(this.ID + ": " + e);
+				}
+			});
+			PhaseDoneJS.handler(this, Pagelet.PHASE_DONE);
+		}
+
+		//==============================================================================
+		// Executed each time when a stylesheet resource has been loaded
+		//==============================================================================
+		onStylesheetLoaded() {
+			if(this.resources[Resource.TYPE_STYLESHEET].every(function(resource){
+					return resource.done;
+				})) {
+				PhaseDoneJS.handler(this, Pagelet.PHASE_LOADCSS);
+				this.replaceHTML();
+			}
+		}
+
+		//==============================================================================
+		// Executed each time when a javascript resource has been loaded
+		//==============================================================================
+		onJavascriptLoaded() {
+			if(this.resources[Resource.TYPE_JAVASCRIPT].every(function(resource){
+					return resource.done;
+				})) {
+				PhaseDoneJS.handler(this, Pagelet.PHASE_LOADJS);
+				this.executeInlineJavascript();
+			}
+		}
+	}
+
+	//==============================================================================
+	// BigPipe
+	//==============================================================================
+	const BigPipe = {
+		pagelets: [],
+		phase: 0,
+		done: [],
+		wait: [],
+		interval: null,
+
+		onPageletArrive(data, codeContainer) {
+			let pageletHTML = codeContainer.innerHTML;
+			pageletHTML = pageletHTML.substring(5, pageletHTML.length - 4);
+			codeContainer.parentNode.removeChild(codeContainer);
+
+			let pagelet = new Pagelet(data, pageletHTML);
+
+			this.pagelets.push(pagelet);
+
+			if(this.phase === 0) {
+				this.phase = 1;
+			}
+
+			if(pagelet.NEED.length === 0 || pagelet.NEED.every(function(needID) {
+					return BigPipe.done.indexOf(needID) !== -1;
+				})) {
+				pagelet.execute();
+			}
+
+			else {
+				this.wait.push(pagelet);
+			}
+		},
+
+		onLastPageletArrived() {
+			this.phase = 2;
+
+			this.interval = setInterval(() => {
+				if(this.done.length === this.pagelets.length) {
+					clearInterval(this.interval);
+					this.executeJavascriptResources();
+				}
+			}, 50);
+		},
+
+		onPageletHTMLreplaced(pageletID) {
+			BigPipe.done.push(pageletID);
+
+			for(let i = 0; i < this.wait.length; ++i) {
+				let pagelet = this.wait[i];
+
+				// Check if all IDs from NEED exists within BigPipe.done
+				// If this is true, then all required dependencies are satisfied.
+				if(pagelet.NEED.every(function(needID){
+						return BigPipe.done.indexOf(needID) !== -1;
+					})) {
+					BigPipe.wait.splice(i--, 1); // remove THIS pagelet from wait list
+					pagelet.execute();
+				}
+			}
+		},
+
+		executeJavascriptResources() {
+			this.phase = 3;
+
+			this.pagelets.forEach(function(pagelet) {
+				if(!pagelet.executeResources(Resource.TYPE_JAVASCRIPT)) {
+					pagelet.onJavascriptLoaded();
+				}
+			});
+		}
+	};
+
+	//==============================================================================
+	// Public-Access
+	//==============================================================================
+	return {
+		onPageletArrive(data, codeContainer) {
+			BigPipe.onPageletArrive(data, codeContainer);
+		},
+
+		onLastPageletArrived() {
+			BigPipe.onLastPageletArrived();
+		},
+
+		reset() {
+			BigPipe.pagelets.forEach(function(pagelet) {
+				pagelet.resources[Resource.TYPE_STYLESHEET].forEach(function(resource) {
+					resource.abortLoading();
+				});
+
+				pagelet.resources[Resource.TYPE_JAVASCRIPT].forEach(function(resource) {
+					resource.abortLoading();
+				});
+			});
+
+			try {
+				window.stop();
+			} catch(e) {
+				document.execCommand('Stop');
+			}
+
+			clearInterval(BigPipe.interval);
+
+			BigPipe.pagelets = [];
+			BigPipe.phase = 0;
+			BigPipe.wait = [];
+			BigPipe.done = [];
+		}
+	};
+})();

+ 35 - 63
src/Qii.php

@@ -17,9 +17,9 @@ define('PS', PATH_SEPARATOR);
 define('OS', strtoupper(substr(PHP_OS, 0, 3)));
 
 define('IS_CLI', php_sapi_name() == 'cli' ? true : false);
-if(IS_CLI) {
+if (IS_CLI) {
     define('PATH_INFO', array_pop($argv));
-}else{
+} else {
     define('PATH_INFO', isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '');
 }
 
@@ -32,13 +32,13 @@ define('QII_SPACE', IS_CLI ? ' ' : '&nbsp;');
 require Qii_DIR . DS . 'Autoloader' . DS . 'Import.php';
 \Qii\Autoloader\Import::setFileLoaded(Qii_DIR . DS . 'Autoloader' . DS . 'Import.php');
 
-\Qii\Autoloader\Import::requires(array(Qii_DIR . DS .'Consts'. DS . 'Config.php',
-                                Qii_DIR . DS . 'Functions'. DS . 'Funcs.php',
-                                Qii_DIR . DS .'Autoloader'. DS . 'Factory.php',
-                                Qii_DIR . DS . 'Application.php',
-                                Qii_DIR . DS .'Autoloader'. DS . 'Psr4.php',
-                                Qii_DIR . DS .'Config'. DS . 'Arrays.php',
-                                )
+\Qii\Autoloader\Import::requires(array(Qii_DIR . DS . 'Consts' . DS . 'Config.php',
+        Qii_DIR . DS . 'Functions' . DS . 'Funcs.php',
+        Qii_DIR . DS . 'Autoloader' . DS . 'Factory.php',
+        Qii_DIR . DS . 'Application.php',
+        Qii_DIR . DS . 'Autoloader' . DS . 'Psr4.php',
+        Qii_DIR . DS . 'Config' . DS . 'Arrays.php',
+    )
 );
 
 use \Qii\Application;
@@ -54,19 +54,20 @@ class Qii extends Application
     {
         parent::__construct();
     }
+
     /**
      * Instance func
-     * 
+     *
      **/
     public static function getInstance()
     {
-        if(func_num_args() > 0)
-        {
+        if (func_num_args() > 0) {
             $args = func_get_args();
-            return call_user_func_array(array('\Qii\Autoloader\Factory', 'getInstance'), $args);    
+            return call_user_func_array(array('\Qii\Autoloader\Factory', 'getInstance'), $args);
         }
-	    return Factory::getInstance('\Qii');
+        return Factory::getInstance('\Qii');
     }
+
     /**
      * 设置private 属性
      *
@@ -93,14 +94,20 @@ class Qii extends Application
         }
         if (isset($private[$key])) return $private[$key];
     }
-    
-	public static function i()
+
+    /**
+     * 获取语言包内容指定的内容
+     *
+     * @return mixed
+     */
+    public static function i()
     {
         return call_user_func_array(array(
             Psr4::getInstance()->loadClass('\Qii\Language\Loader'), 'i'),
             func_get_args()
         );
     }
+
     /**
      * 错误设置,如果满足给定的条件就直接返回false,否则在设置了错误页面的情况下返回true
      * 如果出错后要终止的话,需要自行处理,此方法不错停止不执行
@@ -115,6 +122,7 @@ class Qii extends Application
     {
         return call_user_func_array(array('\Qii\Exceptions\Error', 'setError'), func_get_args());
     }
+
     /**
      * 抛出异常
      *
@@ -124,6 +132,7 @@ class Qii extends Application
     {
         return call_user_func_array(array('\Qii\Exceptions\Errors', 'e'), func_get_args());
     }
+
     /**
      * 返回当前app的配置
      * @param string $key 如果需要返回单独的某一个key就指定一下这个值
@@ -133,7 +142,7 @@ class Qii extends Application
     {
         return Register::getAppConfigure(\Qii::getInstance()->getAppIniFile(), $key);
     }
-    
+
     /**
      * 当调用Qii不存在的方法的时候,试图通过Autoload去加载对应的类
      * 示例:
@@ -144,6 +153,7 @@ class Qii extends Application
     {
         return call_user_func_array(array(Psr4::getInstance(), 'loadClass'), $args);
     }
+
     /**
      * 当调用不存在的静态方法的时候会试图执行对应的类和静态方法
      * 示例:
@@ -157,6 +167,7 @@ class Qii extends Application
         return call_user_func_array($className . '::' . $method, $args);
     }
 }
+
 if (!function_exists('catch_fatal_error')) {
     function catch_fatal_error()
     {
@@ -169,11 +180,11 @@ if (!function_exists('catch_fatal_error')) {
             $message[] = 'Error file : ' . ltrim($error['file'], Psr4::realpath($_SERVER['DOCUMENT_ROOT']));
             $message[] = 'Error line : ' . $error['line'] . ' on ' . \Qii\Exceptions\Errors::getLineMessage($error['file'], $error['line']);
             $message[] = 'Error description : ' . $error['message'];
-            if(IS_CLI) {
+            if (IS_CLI) {
                 return (new \Qii\Response\Cli())->stdout(
                     str_replace("&nbsp;"
-                                , " "
-                                , strip_tags(join(PHP_EOL, preg_replace("/[\n|\r\n]/", PHP_EOL, $message)))
+                        , " "
+                        , strip_tags(join(PHP_EOL, preg_replace("/[\n|\r\n]/", PHP_EOL, $message)))
                     )
                 );
             }
@@ -182,51 +193,12 @@ if (!function_exists('catch_fatal_error')) {
     }
 }
 
+//注册名称空间
+$namespace = _include(Qii_DIR . DS . 'Conf' . DS . 'namespace.php');
 \Qii\Autoloader\Psr4::getInstance()
     ->register()
-    ->setUseNamespace('Qii\\', true)
-    ->setUseNamespace('Qii\Action', true)
-    ->setUseNamespace('Qii\Autoloader', true)
-    ->setUseNamespace('Qii\Bootstrap', true)
-    ->setUseNamespace('Qii\Config', true)
-    ->setUseNamespace('Qii\Consts', true)
-    ->setUseNamespace('Qii\Controller', true)
-    ->setUseNamespace('Qii\Exceptions', true)
-    ->setUseNamespace('Qii\Language', true)
-    ->setUseNamespace('Qii\Library', true)
-    ->setUseNamespace('Qii\Loger', true)
-    ->setUseNamespace('Qii\Plugin', true)
-    ->setUseNamespace('Qii\Request', false)
-    ->setUseNamespace('Qii\Router', true)
-    ->setUseNamespace('Qii\View', true)
-    ->setUseNamespace('WhichBrowser', true)
-    ->setUseNamespace('BigPipe', true)
-    ->setUseNamespace('Smarty\\', false)
-    ->setUseNamespace('Smarty\\Internal', false);
-
-
-\Qii\Autoloader\Psr4::getInstance()
-    ->addNamespace('Qii\\', Qii_DIR . DS)
-    ->addNamespace('Qii\Action', Qii_DIR . DS . 'Action')
-    ->addNamespace('Qii\Autoloader', Qii_DIR . DS . 'Autoloader')
-    ->addNamespace('Qii\Controller', Qii_DIR . DS . 'Controller')
-    ->addNamespace('Qii\Bootstrap', Qii_DIR . DS . 'Bootstrap')
-    ->addNamespace('Qii\Config', Qii_DIR . DS . 'Config')
-    ->addNamespace('Qii\Consts', Qii_DIR . DS . 'Consts')
-    ->addNamespace('Qii\Exceptions', Qii_DIR . DS . 'Exceptions')
-    ->addNamespace('Qii\Language', Qii_DIR . DS . 'Language')
-    ->addNamespace('Qii\Library', Qii_DIR . DS . 'Library')
-    ->addNamespace('Qii\Loger', Qii_DIR . DS . 'Loger')
-    ->addNamespace('Qii\Plugin', Qii_DIR . DS . 'Plugin')
-    ->addNamespace('Qii\Request', Qii_DIR . DS . 'Request')
-    ->addNamespace('Qii\Response', Qii_DIR . DS . 'Response')
-    ->addNamespace('Qii\Router', Qii_DIR . DS . 'Router')
-    ->addNamespace('Qii\View', Qii_DIR . DS . 'View')
-    ->addNamespace('Smarty', Qii_DIR . DS . 'View' . DS . 'smarty')
-    ->addNamespace('Smarty', Qii_DIR . DS . 'View' . DS . 'smarty' . DS . 'sysplugins')
-    ->addNamespace('WhichBrowser', Qii_DIR . DS . 'Library'. DS . 'Third'. DS . 'WhichBrowser')
-    ->addNamespace('BigPipe', Qii_DIR . DS . 'Library'. DS .'BigPipe'. DS .'BigPipe')
-;
+    ->setUseNamespaces($namespace['setUseNamespace'] ?? [])
+    ->addNamespaces($namespace['addNamespace'] ?? []);
 
 //加载默认语言包
 \Qii\Autoloader\Factory::getInstance('\Qii\Language\Loader')->load('error', Qii_DIR . DS . 'Language');