在引入第三方包時,發現怎麼引入都不合理,也不利於擴展。同時之前一直處於邊學習邊搭建,有的地方不是很合理,所以對代碼進行了優化。
下面根據下圖順序貼出框架完整代碼。
1、public/index.php,這是web入口文件
<?php
/**
* @desc 入口文件
* @author zhaoyang
* @date 2018年5月3日 下午5:16:27
*/
use \Phalcon\Mvc\Application;
// 檢查版本,搭建用到php7一些新特性
version_compare(PHP_VERSION, '7.0.0', '>') || exit('Require PHP > 7.0.0 !');
extension_loaded('phalcon') || exit('Please open the Phalcon extension !');
// 引入自定義常量文件
require '../config/define.php';
version_compare(PHALCON_VERSION, '3.0.0', '>') || exit('Require Phalcon > 3.0.0 !');
// 設置時區
date_default_timezone_set('Asia/Shanghai');
NOW_ENV != 'dev' && error_reporting(E_ALL & ~E_NOTICE);
try {
// 引入註冊服務
$di = require BASE_PATH . 'config/services.php';
// 處理請求
$application = new Application($di);
// 組裝應用程序模塊
$modules = [ ];
foreach (MODULE_ALLOW_LIST as $v) {
$modules[$v] = [
'className' => APP_NAMESPACE . '\\' . ucfirst($v) . '\Module',
'path' => APP_PATH . $v . '/Module.php'
];
}
// 加入模塊分組配置
$application->registerModules($modules);
// 輸出請求內容
echo $application->handle()->getContent();
} catch (\Throwable $e) {
$previous = $e->getPrevious();
$applicationConfig = $application->config->application;
if ($applicationConfig->debug->state ?? false) {
if (empty($applicationConfig->debug->path)) {
echo 'Exception: <br/>', '所在文件:', $e->getFile(), '<br/>所在行:', $e->getLine(), '<br/>錯誤碼:', $e->getCode(), '<br/>錯誤消息:', $e->getMessage();
if (!is_null($previous)) {
echo '<br/>前一個Exception: <br/>', '所在文件:', $previous->getFile(), '<br/>所在行:', $previous->getLine(), '<br/>錯誤碼:', $previous->getCode(), '<br/>錯誤消息:', $previous->getMessage();
}
exit();
}
$errorType = 'debug';
} else {
$errorType = 'error';
}
$errorFile = $applicationConfig->$errorType->path;
$errorMessage = 'Exception: [所在文件:' . $e->getFile() . '] [所在行:' . $e->getLine() . '] [錯誤碼:' . $e->getCode() . '] [錯誤消息:' . $e->getMessage() . '] '/* . PHP_EOL . '[異常追蹤信息:' . $e->getTraceAsString() . ']' */;
if (!is_null($previous)) {
$errorMessage .= ' 前一個Exception: [所在文件:' . $previous->getFile() . '] [所在行:' . $previous->getLine() . '] [錯誤碼:' . $previous->getCode() . '] [錯誤消息:' . $previous->getMessage() . '] '/* . PHP_EOL . '[異常追蹤信息:' . $previous->getTraceAsString() . ']' */;
}
$application->di->get('logger', [$errorFile])->$errorType($errorMessage);
}
2、config/define.php,常量定義文件
<?php
// phalcon版本
define('PHALCON_VERSION', Phalcon\Version::get());
//重新命名文件分隔符,建議路徑後面加上分隔符
define('DS', DIRECTORY_SEPARATOR);
// 應用程序名稱(應用程序所在目錄名)
define('APP_NAME', 'app');
// 頂級命名空間
define('APP_NAMESPACE', 'App');
// 項目根目錄
define('BASE_PATH', dirname(__DIR__) . DS);
// 應用程序所在目錄
define('APP_PATH', BASE_PATH . APP_NAME . DS);
// 模塊列表
// @formatter:off
define('MODULE_ALLOW_LIST', ['home', 'admin']);
// @formatter:on
// 默認模塊
define('DEFAULT_MODULE', 'home');
// 默認模塊命名空間
define('DEFAULT_MODULE_NAMESPACE', APP_NAMESPACE . '\\Home');
// 默認使用的配置文件名
define('NOW_ENV', 'dev');
3、config/config_dev.php,全局開發版配置文件,正式版和測試版只需要拷貝這份,然後進行鍼對性配置即可。
增加了自動加載配置,默認查找文件的後綴名是php,也可以添加別的,例如class.php。
自動加載機制註冊完成會加載files裏配置的所有文件
查找類時第一步是查找classes匹配的類,
如果沒找到就會在註冊的namespaces中查找,優先匹配php後綴文件,如果extensions還設置了class.php後綴,則沒有匹配到php後綴的文件就會循環匹配一遍class.php後綴的文件。
如果還未找到就會循環在註冊的directories目錄下進行匹配。
由於directories匹配性能較低,一般建議使用命名空間註冊,儘量不要使用directories註冊。
<?php
/**
* @desc 全局配置文件
* @author zhaoyang
* @date 2018年5月3日 下午7:54:47
*/
return [
// 應用配置
'application' => [
'debug' => [
'state' => false,
'path' => BASE_PATH . 'runtime/debug/{YmdH}.log'
],
'error' => [
'path' => BASE_PATH . 'runtime/error/{YmdH}.log'
],
// 自動加載
'loader' => [
// 文件擴展名
'extensions' => [
'php'
],
'classes' => [
'Smarty' => BASE_PATH . 'library/vendors/smarty/Smarty.class.php'
],
'namespaces' => [
'Common' => BASE_PATH . 'common/',
'Library\\Adapter' => BASE_PATH . 'library/adapter/',
'Library\\Extensions' => BASE_PATH . 'library/extensions/',
'Library\\Plugins' => BASE_PATH . 'library/plugins/',
'Library\\Tools' => BASE_PATH . 'library/tools/',
'Library\\Validators' => BASE_PATH . 'library/validators/'
],
'files' => [
],
'directories' => [
]
]
],
// 服務配置
'services' => [
// mysql數據庫配置
'db' => [
// 是否記錄執行的mysql語句
'logged' => true,
// 記錄執行時間超過0秒的mysql語句
'max_execute_time' => 0,
// 比較時間到小數點後幾位
'scale' => 5,
'log_path' => BASE_PATH . 'runtime/mysql/{Y/m/d}/{YmdH}.log',
// 使用動態更新
'use_dynamic_update' => true,
// ORM選項配置
'orm_options' => [
// 是否對字段是否爲空的判斷
'not_null_validations' => false
],
'mysql' => [
'host' => 'localhost',
'port' => 3306,
'username' => 'root',
'password' => '123456',
'dbname' => 'phalcon',
'charset' => 'utf8'
]
],
// 調度器配置
'dispatcher' => [
// 處理 Not-Found錯誤配置
'notfound' => [
// 錯誤碼及錯誤提示
'status_code' => 404,
'message' => 'Not Found',
// 錯誤跳轉的頁面
'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
'controller' => 'error',
'action' => 'error404'
]
],
// volt引擎相關配置
'view_engine_volt' => [
// 編譯模板目錄
'compiled_path' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/compiled/volt' . DS,
// 是否實時編譯
'compile_always' => false,
// 附加到已編譯的PHP文件的擴展名
'compiled_extension' => '.php',
// 使用這個替換目錄分隔符
'compiled_separator' => '%%',
// 是否要檢查在模板文件和它的編譯路徑之間是否存在差異
'stat' => true,
// 模板前綴
'prefix' => '',
// 支持HTML的全局自動轉義
'autoescape' => false
],
// smarty引擎相關配置,直接配置smarty參數
'view_engine_smarty' => [
'compile_dir' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/compiled/smarty' . DS,
'caching' => false,
'cache_lifetime' => 3600,
'cache_dir' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/cache/smarty' . DS
],
// 模板相關配置
'view' => [
// 模板路徑
'view_path' => APP_PATH . DEFAULT_MODULE . '/views' . DS,
// 模板引擎,根據模板後綴自動匹配視圖引擎,不啓用則設爲false
'engines' => [
'.volt' => 'viewEngineVolt',
'.phtml' => 'viewEnginePhp',
'.html' => 'viewEngineSmarty'
],
'disable_level' => [
'level_action_view' => false,
'level_before_template' => true,
'level_layout' => true,
'level_after_template' => true,
'level_main_layout' => true
]
],
// 過濾器設置
'filter' => [
// 過濾類型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
'default_filter' => 'string,trim'
],
// 文件日誌,formatter常用line,adapter常用file
'logger' => [
'line' => [
'format' => '[%date%][%type%] %message%',
'date_format' => 'Y-m-d H:i:s'
],
'file' => [
'alert' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/alert/{Y/m/d}/{YmdH}.log',
'critical' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/critical/{Y/m/d}/{YmdH}.log',
'debug' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/debug/{Y/m/d}/{YmdH}.log',
'error' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/error/{Y/m/d}/{YmdH}.log',
'emergency' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/emergency/{Y/m/d}/{YmdH}.log',
'info' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/info/{Y/m/d}/{YmdH}.log',
'notice' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/notice/{Y/m/d}/{YmdH}.log',
'warning' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/warning/{Y/m/d}/{YmdH}.log'
]
],
// session配置
'session' => [
// 是否自動開啓 SESSION
'auto_start' => true,
'options' => [
'adapter' => 'files',
'unique_id' => DEFAULT_MODULE
]
// @formatter:off
/* // phalcon提供了四種適配器,分別是files、memcache、redis、libmemcached
'options' => [
'adapter' => 'memcache',
'unique_id' => DEFAULT_MODULE,
'prefix' => DEFAULT_MODULE,
'persistent' => true,
'lifetime' => 3600
],
'options' => [
'adapter' => 'redis',
'unique_id' => DEFAULT_MODULE,
'prefix' => DEFAULT_MODULE,
'auth' => '',
'persistent' => false,
'lifetime' => 3600,
'index' => 1
] */
// @formatter:on
],
// 加密配置
'crypt' => [
// 加密祕鑰
'key' => DEFAULT_MODULE,
// 填充方式,默認是0(PADDING_DEFAULT),1(PADDING_ANSI_X_923)、2(PADDING_PKCS7)、3(PADDING_ISO_10126)、4(PADDING_ISO_IEC_7816_4)、5(PADDING_ZERO)、6(PADDING_SPACE)
'padding' => '',
// 加密方法,默認是"aes-256-cfb"
'cipher' => ''
],
// cookies配置
'cookies' => [
// 是否使用加密,使用加密必須要設置crypt 的key值
'use_encryption' => true
],
// 緩存配置
'cache' => [
'frontend' => [
// 數據處理方式,支持data(序列化)、json、base64、none、output、igbinary、msgpack
'data' => [
'lifetime' => 172800
],
'output' => [
'lifetime' => 172800
]
],
'backend' => [
// 數據緩存方式,支持memcache、file、redis、mongo、apc、apcu、libmemcached、memory、xcache
'file' => [
'cache_dir' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/cache/',
// 對保存的鍵名進行md5加密
'safekey' => true,
'prefix' => ''
],
'memcache' => [
'host' => 'localhost',
'port' => '11211',
'persistent' => false,
'prefix' => '',
// 默認情況下禁用對緩存鍵的跟蹤
'stats_key' => ''
],
'redis' => [
'host' => '127.0.0.1',
'port' => 6379,
'auth' => '',
'persistent' => false,
'prefix' => '',
'stats_key' => '',
'index' => 0
]
]
],
// 模型元數據緩存配置
'models_metadata' => [
'options' => [
// 適配器,默認使用memory(內存),還支持apc、apcu、files、libmemcached、memcache、redis、session、xcache
'adapter' => 'files',
'meta_data_dir' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/models_metadata/'
]
// @formatter:off
/* 'options' => [
'adapter' => 'files',
'meta_data_dir' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/models_metadata/'
],
'options' => [
'adapter' => 'memcache',
'unique_id' => DEFAULT_MODULE,
'prefix' => DEFAULT_MODULE,
'persistent' => true,
'lifetime' => 3600
],
'options' => [
'adapter' => 'memory',
],
'options' => [
'adapter' => 'redis',
'unique_id' => DEFAULT_MODULE,
'prefix' => DEFAULT_MODULE,
'auth' => '',
'persistent' => false,
'lifetime' => 3600,
'index' => 1
],
'options' => [
'adapter' => 'session',
'prefix' => DEFAULT_MODULE,
] */
// @formatter:on
],
// 模型緩存配置
'models_cache' => [
'frontend' => [
'adapter' => 'data',
'lifetime' => 86400
],
'backend' => [
'adapter' => 'file',
'cache_dir' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/models_cache/'
]
],
// 視圖緩存配置
'view_cache' => [
'frontend' => [
'adapter' => 'output',
'lifetime' => 86400
],
'backend' => [
'adapter' => 'file',
'cache_dir' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/cache/view/',
'prefix' => ''
]
],
// url配置
'url' => [
'base_uri' => '/',
'static_base_uri' => '/',
'base_path' => ''
],
'flash' => [
// 消息class屬性值
'css_classes' => [
'error' => 'alert alert-danger',
'success' => 'alert alert-success',
'notice' => 'alert alert-info',
'warning' => 'alert alert-warning'
],
// 是否在生成的html中設置自動轉義模式
'autoescape' => true,
// 是否必須使用HTML隱式格式化輸出
'automatic_html' => true,
// 是否立即輸出,爲true時,調用$this->flash->message()或其他設置消息(例如success)時,消息立即輸出(echo)
// 爲false時,消息不會輸出,會保存在flash對象中並返回消息$res = $this->flash->success('my message');
'implicit_flush' => false
],
'flash_session' => [
// 消息class屬性值
'css_classes' => [
'error' => 'alert alert-danger',
'success' => 'alert alert-success',
'notice' => 'alert alert-info',
'warning' => 'alert alert-warning'
],
// 是否在生成的html中設置自動轉義模式
'autoescape' => true,
// 是否必須使用HTML隱式格式化輸出
'automatic_html' => true,
// 是否立即輸出,必須設爲true(默認爲true),否則調用->output()不輸出
'implicit_flush' => true
],
// 安全配置
'security' => [
// 設置由openssl僞隨機生成器生成的字節數
'random_bytes' => 16,
// 設置默認hash,0=7(CRYPT_BLOWFISH_Y),1(CRYPT_STD_DES),2(CRYPT_EXT_DES),3(CRYPT_MD5),4(CRYPT_BLOWFISH),5(CRYPT_BLOWFISH_A),6(CRYPT_BLOWFISH_X),8(CRYPT_SHA256),9(CRYPT_SHA512)
'default_hash' => 7,
'work_factor' => 8
]
]
];
4、config/routers.php,路由規則文件
<?php
/**
* @desc 路由規則
* @author zhaoyang
* @date 2018年5月3日 下午7:59:20
*/
$defaultRouters = [
'/' => [
'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
'module' => DEFAULT_MODULE,
'controller' => 'index',
'action' => 'index'
],
'/:controller' => [
'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
'module' => DEFAULT_MODULE,
'controller' => 1,
'action' => 'index'
],
'/:controller/:action' => [
'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
'module' => DEFAULT_MODULE,
'controller' => 1,
'action' => 2
],
'/:controller/:action/:params' => [
'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
'module' => DEFAULT_MODULE,
'controller' => 1,
'action' => 2,
'params' => 3
]
];
$routers = [ ];
foreach (MODULE_ALLOW_LIST as $v) {
$vUcfirst = ucfirst($v);
$routers['/' . $v] = [
'namespace' => APP_NAMESPACE . '\\' . $vUcfirst . '\\Controllers',
'module' => $v,
'controller' => 'Index',
'action' => 'index'
];
$routers['/' . $v . '/:controller'] = [
'namespace' => APP_NAMESPACE . '\\' . $vUcfirst . '\\Controllers',
'module' => $v,
'controller' => 1,
'action' => 'index'
];
$routers['/' . $v . '/:controller/:action'] = [
'namespace' => APP_NAMESPACE . '\\' . $vUcfirst . '\\Controllers',
'module' => $v,
'controller' => 1,
'action' => 2
];
$routers['/' . $v . '/:controller/:action/:params'] = [
'namespace' => APP_NAMESPACE . '\\' . $vUcfirst . '\\Controllers',
'module' => $v,
'controller' => 1,
'action' => 2,
'params' => 3
];
}
return array_merge($defaultRouters, $routers);
5、config/services.php,註冊服務文件
<?php
/**
* @desc 註冊服務
* @author zhaoyang
* @date 2018年5月3日 下午8:01:34
*/
// 引入配置文件
$config = require BASE_PATH . 'config/config_' . NOW_ENV . '.php';
// 引入路由規則
$routerRules = require BASE_PATH . 'config/routers.php';
use Common\Common;
use Common\Validate;
use Library\Adapter\SmartyEngine as ViewEngineSmarty;
use Library\Extensions\VoltExtension;
use Library\Plugins\DbProfilerPlugin;
use Library\Plugins\DIspatcherPlugin;
use Phalcon\Cache\Frontend\Factory as CacheFrontendFactory;
use Phalcon\Cache\Backend\Factory as CacheBackendFactory;
use Phalcon\Config;
use Phalcon\Crypt;
use Phalcon\Db\Adapter\Pdo\Mysql;
use Phalcon\Db\Profiler;
use Phalcon\DI;
use Phalcon\Di\FactoryDefault;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Flash\Direct as FlashDirect;
use Phalcon\Flash\Session as FlashSession;
use Phalcon\Http\Response\Cookies;
use Phalcon\Logger\Adapter\File as LoggerAdapterFile;
use Phalcon\Logger\Formatter\Line as LoggerFormatterLine;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\Router;
use Phalcon\Mvc\Url;
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Php as ViewEnginePhp;
use Phalcon\Mvc\View\Engine\Volt as ViewEngineVolt;
use Phalcon\Security;
use Phalcon\Session\Factory as SessionFactory;
use Phalcon\Text;
$di = new FactoryDefault();
/**
* @desc 註冊調度器服務
* @author zhaoyang
* @date 2018年5月3日 下午8:38:34
*/
$di->setShared('dispatcher', function () {
$dispatcherConfig = $this->getConfig()->services->dispatcher;
$dispatcher = new Dispatcher();
$dispatcher->setDefaultNamespace($dispatcherConfig->module_default_namespaces);
$eventsManager = new EventsManager();
$eventsManager->attach('dispatch', new DIspatcherPlugin());
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
/**
* @desc 註冊配置服務
* @author zhaoyang
* @date 2018年5月3日 下午8:38:53
*/
$di->setShared('config', function () use ($config) {
return new Config($config);
});
/**
* @desc 註冊路由服務
* @author zhaoyang
* @date 2018年5月3日 下午8:39:06
*/
$di->setShared('router', function () use ($routerRules) {
$router = new Router();
// 自動刪除末尾斜線
$router->removeExtraSlashes(true);
foreach ($routerRules as $k => $v) {
$router->add($k, $v);
}
return $router;
});
/**
* @desc 註冊視圖引擎volt服務
* @author zhaoyang
* @date 2018年5月4日 下午5:28:52
*/
$di->setShared('viewEngineVolt', function (View $view, DI $di) {
// 獲取config服務有多種方法,這是其一
$voltConfig = $di->get('config')->services->view_engine_volt->toArray();
$voltConfig = Common::convertArrKeyUnderline($voltConfig);
$viewEngineVolt = new ViewEngineVolt($view, $di);
$voltConfig['compiledPath'] = isset($voltConfig['compiledPath']) ? Common::dirFormat($voltConfig['compiledPath']) : BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/compiled/volt' . DS;
$mkdirRes = Common::mkdir($voltConfig['compiledPath']);
if (!$mkdirRes) {
throw new \Exception('創建目錄 ' . $voltConfig['compiledPath'] . ' 失敗');
}
$viewEngineVolt->setOptions($voltConfig);
// 獲取編譯器對象
$compiler = $viewEngineVolt->getCompiler();
// 添加擴展
$compiler->addExtension(new VoltExtension());
return $viewEngineVolt;
});
/**
* @desc 註冊視圖引擎php服務
* @author zhaoyang
* @date 2018年5月4日 下午5:29:15
*/
$di->setShared('viewEnginePhp', function (View $view, DI $di) {
$viewEnginePhp = new ViewEnginePhp($view, $di);
return $viewEnginePhp;
});
/**
* @desc 註冊視圖引擎smarty服務
* @author: ZhaoYang
* @date: 2018年6月21日 下午11:55:22
*/
$di->setShared('viewEngineSmarty', function (View $view, DI $di) {
$smartyConfig = $this->getConfig()->services->view_engine_smarty->toArray();
$viewEngineSmarty = new ViewEngineSmarty($view, $di);
$viewEngineSmarty->setOptions($smartyConfig);
return $viewEngineSmarty;
});
/**
* @desc 註冊視圖服務
* @author zhaoyang
* @date 2018年5月3日 下午10:52:37
*/
$di->set('view', function () {
// 獲取config服務有多種方法,這是其二
$viewConfig = $this->getConfig()->services->view;
$view = new View();
// 設置視圖路徑
$view->setViewsDir($viewConfig->view_path);
$engines = $viewConfig->engines->toArray();
foreach($engines as $k => $v){
if($v === false){
unset($engines[$k]);
}
}
// 註冊視圖引擎
$view->registerEngines($engines);
$disableLevelConfig = $viewConfig->disable_level;
// 關閉渲染級別
$disableLevel = [ ];
foreach ($disableLevelConfig as $k => $v) {
// 設置了就代表disableLevel,與設置的true無關
if($v){
switch ($k) {
case 'level_action_view':
$disableLevel[View::LEVEL_ACTION_VIEW] = true;
break;
case 'level_before_template':
$disableLevel[View::LEVEL_BEFORE_TEMPLATE] = true;
break;
case 'level_layout':
$disableLevel[View::LEVEL_LAYOUT] = true;
break;
case 'level_after_template':
$disableLevel[View::LEVEL_AFTER_TEMPLATE] = true;
break;
case 'level_main_layout':
$disableLevel[View::LEVEL_MAIN_LAYOUT] = true;
break;
}
}
}
$view->disableLevel($disableLevel);
return $view;
});
/**
* @desc 註冊驗證服務
* @author zhaoyang
* @date 2018年5月11日 下午7:26:30
*/
$di->set('validate', function () {
$validate = new Validate();
return $validate;
});
/**
* @desc 註冊性能分析組件
* @author zhaoyang
* @date 2018年5月20日 下午9:34:33
*/
$di->setShared('profiler', function () {
$profiler = new Profiler();
return $profiler;
});
/**
* @desc 註冊數據庫(連接)服務
* @author zhaoyang
* @date 2018年5月14日 下午9:01:36
*/
$di->setShared('db', function () {
$dbConfig = $this->getConfig()->services->db->mysql->toArray();
$mysql = new Mysql($dbConfig);
if ($dbConfig['logged'] ?? false) {
$eventsManager = new EventsManager();
$eventsManager->attach('db', new DbProfilerPlugin());
$mysql->setEventsManager($eventsManager);
}
return $mysql;
});
/**
* @desc 註冊日誌服務
* @author zhaoyang
* @date 2018年5月19日 下午6:20:36
*/
$di->set('logger', function (string $file = null, array $line = null) {
$config = $this->getConfig()->services->logger;
$linConfig = clone $config->line;
!is_null($line) && $linConfig = $linConfig->merge(new Config($line));
$loggerFormatterLine = new LoggerFormatterLine($linConfig->format, $linConfig->date_format);
$fileConfig = $config->file;
if (empty($file)) {
$file = $fileConfig->info;
} else if (array_key_exists($file, $fileConfig->toArray())) {
$file = $fileConfig->$file;
}
$file = Common::dirFormat($file);
$dir = dirname($file);
$mkdirRes = Common::mkdir($dir);
if (!$mkdirRes) {
throw new \Exception('創建目錄 ' . $dir . ' 失敗');
}
$loggerAdapterFile = new LoggerAdapterFile($file);
$loggerAdapterFile->setFormatter($loggerFormatterLine);
return $loggerAdapterFile;
});
/**
* @desc 註冊session服務
* @author zhaoyang
* @date 2018年5月26日 下午4:48:03
*/
$di->setShared('session', function () {
$sessionConfig = $this->getConfig()->services->session;
$backendConfig = $this->getConfig()->services->cache->backend;
$optionsArr = $sessionConfig->options->toArray();
if (!isset($optionsArr['adapter'])) {
throw new \Exception('session必須設置adapter');
}
if (array_key_exists($optionsArr['adapter'], $backendConfig->toArray())) {
$backendOption = clone $backendConfig->{$optionsArr['adapter']};
$optionsArr = $backendOption->merge(new Config($optionsArr))->toArray();
}
$optionsArr = Common::convertArrKeyUnderline($optionsArr);
if (version_compare(PHALCON_VERSION, '3.2.0', '>')) {
$session = SessionFactory::load($optionsArr);
} else {
$adapterClassName = 'Phalcon\\Session\\Adapter\\' . Text::camelize($optionsArr['adapter']);
$session = new $adapterClassName($optionsArr);
}
$sessionConfig->auto_start && $session->start();
return $session;
});
/**
* @desc 註冊加密服務
* @author zhaoyang
* @date 2018年5月28日 下午8:17:46
*/
$di->set('crypt', function (string $key = null, int $padding = null, string $cipher = null) {
$cryptConfig = $this->getConfig()->services->crypt;
$crypt = new Crypt();
if (!empty($cryptConfig->key) || !empty($padding)) {
$crypt->setKey($key ?? $cryptConfig->key);
}
if (!empty($cryptConfig->padding) || !empty($key)) {
$crypt->setPadding($padding ?? $cryptConfig->padding);
}
if (!empty($cryptConfig->cipher) || !empty($cipher)) {
$crypt->setCipher($cipher ?? $cryptConfig->cipher);
}
return $crypt;
});
/**
* @desc 註冊cookies服務
* @author zhaoyang
* @date 2018年5月29日 上午9:54:23
*/
$di->set('cookies', function () {
$cookiesConfig = $this->getConfig()->services->cookies;
$cookies = new Cookies();
isset($cookiesConfig->use_encryption) && $cookies->useEncryption((bool) $cookiesConfig->use_encryption);
return $cookies;
});
/**
* @desc 註冊緩存
* @author zhaoyang
* @date 2018年5月30日 下午10:30:29
*/
$di->set('cache', function (array $options = []) {
$cacheConfig = $this->getConfig()->services->cache;
$frontendConfig = $cacheConfig->frontend;
if (isset($options['frontend']['adapter'])) {
$frontendOption = new Config($options['frontend']);
if (array_key_exists($options['frontend']['adapter'], $frontendConfig->toArray())) {
$frontendOptionClone = clone $frontendConfig->{$options['frontend']['adapter']};
$frontendOptionClone->merge($frontendOption);
$frontendOption = $frontendOptionClone;
}
} else {
$frontendOption = clone $frontendConfig->data;
$frontendOption->adapter = 'data';
}
$frontendOption = Common::convertArrKeyUnderline($frontendOption->toArray());
if (version_compare(PHALCON_VERSION, '3.2.0', '>')) {
$frontendCache = CacheFrontendFactory::load($frontendOption);
} else {
$frontendClassName = 'Phalcon\\Cache\\Frontend\\' . Text::camelize($frontendOption['adapter']);
$frontendCache = new $frontendClassName($frontendOption);
}
$backendConfig = $cacheConfig->backend;
if (isset($options['backend']['adapter'])) {
$backendOption = new Config($options['backend']);
if (array_key_exists($options['backend']['adapter'], $backendConfig->toArray())) {
$backendOptionClone = clone $backendConfig->{$options['backend']['adapter']};
$backendOptionClone->merge($backendOption);
$backendOption = $backendOptionClone;
}
} else {
$backendOption = clone $backendConfig->file;
$backendOption->adapter = 'file';
}
if ($backendOption->adapter == 'file') {
if (empty($dir = $backendOption->cache_dir)) {
throw new \Exception('緩存目錄不能爲空');
}
$dir = Common::dirFormat($dir);
$mkdirRes = Common::mkdir($dir);
if (!$mkdirRes) {
throw new \Exception('創建目錄 ' . $dir . ' 失敗');
}
}
$backendOption = Common::convertArrKeyUnderline($backendOption->toArray());
if (version_compare(PHALCON_VERSION, '3.2.0', '>')) {
$backendOption['frontend'] = $frontendCache;
$backendCache = CacheBackendFactory::load($backendOption);
} else {
$backendClassName = 'Phalcon\\Cache\\Backend\\' . Text::camelize($backendOption['adapter']);
$backendCache = new $backendClassName($frontendCache, $backendOption);
}
return $backendCache;
});
/**
* @desc 註冊 modelsMetadata服務
* @author zhaoyang
* @date 2018年6月2日 下午10:39:43
*/
$di->setShared('modelsMetadata', function () {
$modelsMetadataConfig = $this->getConfig()->services->models_metadata;
$backendConfig = $this->getConfig()->services->cache->backend;
$optionsArr = $modelsMetadataConfig->options->toArray();
if (!isset($optionsArr['adapter'])) {
throw new \Exception('modelsMetadata必須設置adapter');
}
if (array_key_exists($optionsArr['adapter'], $backendConfig->toArray())) {
$backendOption = clone $backendConfig->{$optionsArr['adapter']};
$optionsArr = $backendOption->merge(new Config($optionsArr))->toArray();
}
if ($optionsArr['adapter'] == 'files') {
if (empty($optionsArr['meta_data_dir'])) {
throw new \Exception('緩存目錄不能爲空');
}
$dir = Common::dirFormat($optionsArr['meta_data_dir']);
$mkdirRes = Common::mkdir($dir);
if (!$mkdirRes) {
throw new \Exception('創建目錄 ' . $dir . ' 失敗');
}
}
$optionsArr = Common::convertArrKeyUnderline($optionsArr);
$modelsMetadataClassName = 'Phalcon\\Mvc\\Model\\MetaData\\' . Text::camelize($optionsArr['adapter']);
$modelsMetadata = new $modelsMetadataClassName($optionsArr);
return $modelsMetadata;
});
/**
* @desc 註冊modelsCache服務
* @author zhaoyang
* @date 2018年6月3日 下午6:22:31
*/
$di->set('modelsCache', function (array $options = []) {
$modelsCacheConfig = clone $this->getConfig()->services->models_cache;
!empty($options) && $modelsCacheConfig->merge(new Config($options));
$options = $modelsCacheConfig->toArray();
$modelsCache = $this->get('cache', [
$options
]);
return $modelsCache;
});
/**
* @desc 註冊視圖緩存
* @author zhaoyang
* @date 2018年6月4日 下午10:14:52
*/
$di->set('viewCache', function (array $options = []) {
$viewCacheConfig = clone $this->getConfig()->services->view_cache;
!empty($options) && $viewCacheConfig->merge(new Config($options));
$options = $viewCacheConfig->toArray();
$viewCache = $this->get('cache', [
$options
]);
return $viewCache;
});
/**
* @desc 註冊url服務
* @author zhaoyang
* @date 2018年6月6日 下午8:13:37
*/
$di->setShared('url', function () {
$urlConfig = $this->getConfig()->services->url;
$url = new Url();
$urlConfig->base_uri && $url->setBaseUri($urlConfig->base_uri);
$urlConfig->static_base_uri && $url->setStaticBaseUri($urlConfig->static_base_uri);
$urlConfig->base_path && $url->setBasePath($urlConfig->base_path);
return $url;
});
/**
* @desc 註冊flash服務
* @author zhaoyang
* @date 2018年6月9日 下午8:22:46
*/
$di->set('flash', function () {
$flashConfig = $this->getConfig()->services->flash;
$flashDirect = new FlashDirect($flashConfig->css_classes->toArray());
$flashDirect->setAutoescape($flashConfig->autoescape);
$flashDirect->setAutomaticHtml($flashConfig->automatic_html);
$flashDirect->setImplicitFlush($flashConfig->implicit_flush);
return $flashDirect;
});
/**
* @desc 註冊flashSession服務
* @author zhaoyang
* @date 2018年6月9日 下午8:23:45
*/
$di->set('flashSession', function () {
$flashSessionConfig = $this->getConfig()->services->flash_session;
$flashSession = new FlashSession($flashSessionConfig->css_classes->toArray());
$flashSession->setAutoescape($flashSessionConfig->autoescape);
$flashSession->setAutomaticHtml($flashSessionConfig->automatic_html);
$flashSession->setImplicitFlush($flashSessionConfig->implicit_flush);
return $flashSession;
});
/**
* @desc 註冊安全服務
* @author zhaoyang
* @date 2018年6月7日 下午9:19:07
*/
$di->set('security', function () {
$securityConfig = $this->getConfig()->services->security;
$security = new Security();
$securityConfig->random_bytes && $security->setRandomBytes($securityConfig->random_bytes);
$securityConfig->default_hash && $security->setDefaultHash($securityConfig->default_hash);
$securityConfig->work_factor && $security->setWorkFactor($securityConfig->work_factor);
return $security;
});
return $di;
6、app/home/config/config_dev.php,這是home模塊的配置文件,每個模塊都有自己的配置文件,會和全局配置文件合併。所以如果模塊有特定配置,可以對其進行單獨設置,而無需改動全局配置文件。
<?php
// 模塊名稱
define('MODULE_NAME', 'home');
// 模塊命名空間
define('MODULE_NAMESPACE', APP_NAMESPACE . '\\Home');
return [
// 應用配置
'application' => [
'debug' => [
'state' => true,
'path' => '' // BASE_PATH . 'runtime/' . MODULE_NAME . '/debug/{YmdH}.log'
],
'error' => [
'path' => BASE_PATH . 'runtime/' . MODULE_NAME . '/error/{YmdH}.log'
],
'loader' => [
'namespaces' => [
MODULE_NAMESPACE . '\\Controllers' => APP_PATH . MODULE_NAME . '/controllers' . DS,
MODULE_NAMESPACE . '\\Models' => APP_PATH . MODULE_NAME . '/models' . DS
]
]
],
// 服務配置
'services' => [
// 調度器配置
'dispatcher' => [
// 模塊默認的命名空間
'module_default_namespaces' => MODULE_NAMESPACE . '\\Controllers',
// 處理 Not-Found錯誤配置
'notfound' => [
// 錯誤碼及錯誤提示
'status_code' => 404,
'message' => 'Not Found',
// 錯誤跳轉的頁面
'namespace' => MODULE_NAMESPACE . '\\Controllers',
'controller' => 'error',
'action' => 'error404'
]
],
// volt引擎相關配置
'view_engine_volt' => [
// 編譯模板目錄
'compiled_path' => BASE_PATH . 'runtime/' . MODULE_NAME . '/compiled/volt' . DS,
// 是否實時編譯
'compile_always' => false,
// 附加到已編譯的PHP文件的擴展名
'compiled_extension' => '.php',
// 使用這個替換目錄分隔符
'compiled_separator' => '%%',
// 是否要檢查在模板文件和它的編譯路徑之間是否存在差異
'stat' => true,
// 模板前綴
'prefix' => '',
// 支持HTML的全局自動轉義
'autoescape' => false
],
// 模板相關配置
'view' => [
// 模板路徑
'view_path' => APP_PATH . MODULE_NAME . '/views' . DS,
// 模板引擎,根據模板後綴自動匹配視圖引擎,不啓用則設爲false
'engines' => [
'.volt' => 'viewEngineVolt',
'.phtml' => 'viewEnginePhp',
'.html' => 'viewEngineSmarty'
],
'disable_level' => [
'level_action_view' => false,
'level_before_template' => true,
'level_layout' => true,
'level_after_template' => true,
'level_main_layout' => true
]
],
// 過濾器設置
'filter' => [
// 過濾類型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
'default_filter' => 'string,trim'
],
// 文件日誌,formatter常用line,adapter常用file
'logger' => [
'line' => [
'format' => '[%date%][%type%] %message%',
'dateFormat' => 'Y-m-d H:i:s'
],
'file' => [
'alert' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/alert/{Y/m/d}/{YmdH}.log',
'critical' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/critical/{Y/m/d}/{YmdH}.log',
'debug' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/debug/{Y/m/d}/{YmdH}.log',
'error' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/error/{Y/m/d}/{YmdH}.log',
'emergency' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/emergency/{Y/m/d}/{YmdH}.log',
'info' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/info/{Y/m/d}/{YmdH}.log',
'notice' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/notice/{Y/m/d}/{YmdH}.log',
'warning' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/warning/{Y/m/d}/{YmdH}.log'
]
],
'session' => [
'auto_start' => true,
'options' => [
'adapter' => 'files',
'unique_id' => MODULE_NAME
]
],
// 加密配置
'crypt' => [
// 加密祕鑰
'key' => MODULE_NAME,
// 填充方式,默認是0(PADDING_DEFAULT),1(PADDING_ANSI_X_923)、2(PADDING_PKCS7)、3(PADDING_ISO_10126)、4(PADDING_ISO_IEC_7816_4)、5(PADDING_ZERO)、6(PADDING_SPACE)
'padding' => '',
// 加密方法,默認是"aes-256-cfb"
'cipher' => ''
],
// cookies配置
'cookies' => [
// 是否使用加密,使用加密必須要設置crypt 的key值
'use_encryption' => true
],
// 緩存配置
'cache' => [
'backend' => [
// 數據緩存方式,支持memcache、file、redis、mongo、apc、apcu、libmemcached、memory、xcache
'file' => [
'cache_dir' => BASE_PATH . 'runtime/' . MODULE_NAME . '/cache/'
]
]
],
// 模型元數據緩存配置
'models_metadata' => [
'options' => [
// 適配器,默認使用memory(內存),還支持apc、apcu、files、libmemcached、memcache、redis、session、xcache
'adapter' => 'files',
'meta_data_dir' => BASE_PATH . 'runtime/' . MODULE_NAME . '/models_metadata/'
]
],
// 模型緩存配置
'models_cache' => [
'frontend' => [
'adapter' => 'data',
'lifetime' => 86400
],
'backend' => [
'adapter' => 'file',
'cache_dir' => BASE_PATH . 'runtime/' . MODULE_NAME . '/models_cache/'
]
],
// 視圖緩存配置
'view_cache' => [
'frontend' => [
'adapter' => 'output',
'lifetime' => 20
],
'backend' => [
'adapter' => 'file',
'cache_dir' => BASE_PATH . 'runtime/' . MODULE_NAME . '/cache/view/',
'safekey' => false,
'prefix' => ''
]
],
// url配置
'url' => [
'base_uri' => '/' . MODULE_NAME . '/',
'static_base_uri' => '/' . MODULE_NAME . '/static/',
'base_path' => ''
],
'flash' => [
// 消息class屬性值
'css_classes' => [
'error' => 'alert alert-danger',
'success' => 'alert alert-success',
'notice' => 'alert alert-info',
'warning' => 'alert alert-warning'
],
// 是否在生成的html中設置自動轉義模式
'autoescape' => true,
// 是否必須使用HTML隱式格式化輸出
'automatic_html' => true,
// 是否立即輸出,爲true時,調用$this->flash->message()或其他設置消息(例如success)時,消息立即輸出(echo)
// 爲false時,消息不會輸出,會保存在flash對象中並返回消息$res = $this->flash->success('my message');
'implicit_flush' => false
],
'flash_session' => [
// 消息class屬性值
'css_classes' => [
'error' => 'alert alert-danger',
'success' => 'alert alert-success',
'notice' => 'alert alert-info',
'warning' => 'alert alert-warning'
],
// 是否在生成的html中設置自動轉義模式
'autoescape' => true,
// 是否必須使用HTML隱式格式化輸出
'automatic_html' => true,
// 是否立即輸出,必須設爲true,否則調用->output()不輸出
'implicit_flush' => true
],
// 安全配置
'security' => [
// 設置由openssl僞隨機生成器生成的字節數
'random_bytes' => 16,
// 設置默認hash,0=7(CRYPT_BLOWFISH_Y),1(CRYPT_STD_DES),2(CRYPT_EXT_DES),3(CRYPT_MD5),4(CRYPT_BLOWFISH),5(CRYPT_BLOWFISH_A),6(CRYPT_BLOWFISH_X),8(CRYPT_SHA256),9(CRYPT_SHA512)
'default_hash' => 7,
'work_factor' => 8
]
]
];
7、app/home/Module.php,模塊初始化文件。自動加載也在這裏完成。同時這裏可以註冊和重寫模塊特有的服務。
<?php
/**
* @desc 模塊配置
* @author zhaoyang
* @date 2018年5月3日 下午8:49:49
*/
namespace App\Home;
use Phalcon\DiInterface;
use Phalcon\Loader;
use Phalcon\Mvc\ModuleDefinitionInterface;
use Phalcon\Config\Adapter\Php as ConfigAdapterPhp;
class Module implements ModuleDefinitionInterface {
// 模塊配置文件目錄
private static $_configPath = __DIR__ . '/config/config_' . NOW_ENV . '.php';
public function registerAutoloaders(DiInterface $di = NULL) {
$this->registerConfigService($di);
$config = $di->getConfig();
$loaderConfig = $config->application->loader->toArray();
$loader = new Loader();
$loader->registerClasses($loaderConfig['classes'])
->registerNamespaces($loaderConfig['namespaces'])
->registerFiles($loaderConfig['files'])
->registerDirs($loaderConfig['directories'])
->register();
}
public function registerServices(DiInterface $di) {
// 這裏可以註冊和重寫服務
// 註冊配置文件服務,合併主配置和模塊配置
// $this->registerConfigService($di);
}
/**
* @desc 註冊配置服務
* @author zhaoyang
* @date 2018年5月3日 下午8:50:51
*/
private function registerConfigService(DiInterface $di) {
$config = $di->getConfig();
$di->setShared('config', function () use ($config) {
$moduleConfigPath = self::$_configPath;
if (is_file($moduleConfigPath)) {
$override = new ConfigAdapterPhp($moduleConfigPath);
$config->merge($override);
}
return $config;
});
}
}
至此web框架已經完成。
如果需要增加模塊,比如增加一個admin模塊,只需要複製一份home模塊,重命名爲admin,同時將模塊中的home替換成admin,Home替換成Admin即可。
主要換的地方有兩個,一個是Module.php文件,另一個是config_*.php文件
下面對cli進行改造。對於一般項目,cli腳本通常不會很多,一般使用單模塊足以。
8、cli/cli.php,cli應用入口文件
<?php
/**
* @desc 命令行入口文件
* @author: ZhaoYang
* @date: 2018年6月17日 下午5:42:16
*/
use Phalcon\Cli\Console;
use Phalcon\Loader;
// 檢查版本,搭建用到php7一些新特性
version_compare(PHP_VERSION, '7.0.0', '>') || exit('Require PHP > 7.0.0 !');
extension_loaded('phalcon') || exit('Please open the Phalcon extension !');
// 引入自定義常量文件
require '../config/define.php';
version_compare(PHALCON_VERSION, '3.0.0', '>') || exit('Require Phalcon > 3.0.0 !');
// 設置時區
date_default_timezone_set('Asia/Shanghai');
NOW_ENV != 'dev' && error_reporting(E_ALL & ~E_NOTICE);
try {
// 引入註冊服務
$di = require BASE_PATH . 'cli/config/services.php';
// 處理請求
$console = new Console($di);
$loaderConfig = $console->config->application->loader->toArray();
$loader = new Loader();
// 通常還可能用到各模塊的模型
foreach (MODULE_ALLOW_LIST as $v) {
$loaderConfig['namespaces'][APP_NAMESPACE . '\\' . ucfirst($v) . '\\Models'] = APP_PATH . $v . '/models' . DS;
}
$loader->registerClasses($loaderConfig['classes'])
->registerNamespaces($loaderConfig['namespaces'])
->registerFiles($loaderConfig['files'])
->registerDirs($loaderConfig['directories'])
->register();
// 設置選項
$console->setArgument($argv);
$arguments = [];
foreach ($argv as $k => $arg) {
if ($k === 1) {
$arguments['task'] = $arg;
} elseif ($k === 2) {
$arguments['action'] = $arg;
} elseif ($k >= 3) {
$arguments['params'][] = $arg;
}
}
// 處理請求
$console->handle($arguments);
} catch (\Throwable $e) {
$previous = $e->getPrevious();
$applicationConfig = $console->config->application;
if ($applicationConfig->debug->state ?? false) {
if (empty($applicationConfig->debug->path)) {
echo 'Exception: ', PHP_EOL, '所在文件:', $e->getFile(), PHP_EOL, '所在行:', $e->getLine(), PHP_EOL, '錯誤碼:', $e->getCode(), PHP_EOL, '錯誤消息:', $e->getMessage(), PHP_EOL, PHP_EOL;
if (!is_null($previous)) {
echo '前一個Exception: ', PHP_EOL, '所在文件:', $previous->getFile(), PHP_EOL, '所在行:', $previous->getLine(), PHP_EOL, '錯誤碼:', $previous->getCode(), PHP_EOL, '錯誤消息:', $previous->getMessage(), PHP_EOL, PHP_EOL;
}
exit();
}
$errorType = 'debug';
} else {
$errorType = 'error';
}
$errorFile = $applicationConfig->$errorType->path;
$errorMessage = 'Exception: [所在文件:' . $e->getFile() . '] [所在行:' . $e->getLine() . '] [錯誤碼:' . $e->getCode() . '] [錯誤消息:' . $e->getMessage() . '] '/* . PHP_EOL . '[異常追蹤信息:' . $e->getTraceAsString() . ']' */;
if (!is_null($previous)) {
$errorMessage .= ' 前一個Exception: [所在文件:' . $previous->getFile() . '] [所在行:' . $previous->getLine() . '] [錯誤碼:' . $previous->getCode() . '] [錯誤消息:' . $previous->getMessage() . '] '/* . PHP_EOL . '[異常追蹤信息:' . $previous->getTraceAsString() . ']' */;
}
$console->di->get('logger', [
$errorFile
])->$errorType($errorMessage);
}
9、cli/config/config_dev.php,cli程序配置文件,此文件也會和全局配置文件整合。
<?php
return [
// 應用配置
'application' => [
'debug' => [
'state' => true,
'path' => ''
],
'error' => [
'path' => BASE_PATH . 'runtime/cli/error/{YmdH}.log'
],
// 自動加載
'loader' => [
'directories' => [
BASE_PATH . 'cli/tasks/'
]
]
],
// 服務配置
'services' => [
// 過濾器設置
'filter' => [
// 過濾類型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
'default_filter' => 'string,trim'
],
// 文件日誌,formatter常用line,adapter常用file
'logger' => [
'line' => [
'format' => '[%date%][%type%] %message%',
'dateFormat' => 'Y-m-d H:i:s'
],
'file' => [
'alert' => BASE_PATH . 'runtime/cli/logs/alert/{Y/m/d}/{YmdH}.log',
'critical' => BASE_PATH . 'runtime/cli/logs/critical/{Y/m/d}/{YmdH}.log',
'debug' => BASE_PATH . 'runtime/cli/logs/debug/{Y/m/d}/{YmdH}.log',
'error' => BASE_PATH . 'runtime/cli/logs/error/{Y/m/d}/{YmdH}.log',
'emergency' => BASE_PATH . 'runtime/cli/logs/emergency/{Y/m/d}/{YmdH}.log',
'info' => BASE_PATH . 'runtime/cli/logs/info/{Y/m/d}/{YmdH}.log',
'notice' => BASE_PATH . 'runtime/cli/logs/notice/{Y/m/d}/{YmdH}.log',
'warning' => BASE_PATH . 'runtime/cli/logs/warning/{Y/m/d}/{YmdH}.log'
]
],
// 加密配置
'crypt' => [
// 加密祕鑰
'key' => 'cli',
// 填充方式,默認是0(PADDING_DEFAULT),1(PADDING_ANSI_X_923)、2(PADDING_PKCS7)、3(PADDING_ISO_10126)、4(PADDING_ISO_IEC_7816_4)、5(PADDING_ZERO)、6(PADDING_SPACE)
'padding' => '',
// 加密方法,默認是"aes-256-cfb"
'cipher' => ''
],
// 緩存配置
'cache' => [
'backend' => [
// 數據緩存方式,支持memcache、file、redis、mongo、apc、apcu、libmemcached、memory、xcache
'file' => [
'cache_dir' => BASE_PATH . 'runtime/cli/cache/'
]
]
],
// 模型元數據緩存配置
'models_metadata' => [
'options' => [
// 適配器,默認使用memory(內存),還支持apc、apcu、files、libmemcached、memcache、redis、session、xcache
'adapter' => 'files',
'meta_data_dir' => BASE_PATH . 'runtime/cli/models_metadata/'
]
],
// 模型緩存配置
'models_cache' => [
'frontend' => [
'adapter' => 'data',
'lifetime' => 86400
],
'backend' => [
'adapter' => 'file',
'cache_dir' => BASE_PATH . 'runtime/cli/models_cache/'
]
],
// 安全配置
'security' => [
// 設置由openssl僞隨機生成器生成的字節數
'random_bytes' => 16,
// 設置默認hash,0=7(CRYPT_BLOWFISH_Y),1(CRYPT_STD_DES),2(CRYPT_EXT_DES),3(CRYPT_MD5),4(CRYPT_BLOWFISH),5(CRYPT_BLOWFISH_A),6(CRYPT_BLOWFISH_X),8(CRYPT_SHA256),9(CRYPT_SHA512)
'default_hash' => 7,
'work_factor' =>8
]
]
];
10、cli/config/services.php文件。cli主要是dispatcher服務和router服務與web服務不同,單模塊cli無需對路由進行必要配置。
<?php
/**
* @desc 註冊cli服務
* @author: ZhaoYang
* @date: 2018年6月17日 下午6:51:16
*/
// 引入配置文件
$config = require BASE_PATH . 'config/config_' . NOW_ENV . '.php';
// 引入cli配置文件
$cliConfig = require BASE_PATH . 'cli/config/config_' . NOW_ENV . '.php';
use Common\Common;
use Phalcon\Cache\Backend\Factory as CacheBackendFactory;
use Phalcon\Cache\Frontend\Factory as CacheFrontendFactory;
use Phalcon\Cli\Dispatcher;
use Phalcon\Config;
use Phalcon\Crypt;
use Phalcon\Db\Adapter\Pdo\Mysql;
use Phalcon\Db\Profiler;
use Phalcon\Di\FactoryDefault\Cli;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Logger\Adapter\File as LoggerAdapterFile;
use Phalcon\Logger\Formatter\Line as LoggerFormatterLine;
use Library\Plugins\DbProfilerPlugin;
use Phalcon\Text;
$di = new Cli();
/**
* @desc 註冊配置服務
* @author: ZhaoYang
* @date: 2018年6月17日 下午6:55:44
*/
$di->setShared('config', function () use ($config, $cliConfig) {
$config = new Config($config);
$config->merge(new Config($cliConfig));
return $config;
});
/**
* @desc 註冊調度器服務
* @author: ZhaoYang
* @date: 2018年6月18日 下午4:38:04
*/
$di->setShared('dispatcher', function () {
$dispatcher = new Dispatcher();
return $dispatcher;
});
/**
* @desc 註冊性能分析組件
* @author zhaoyang
* @date 2018年5月20日 下午9:34:33
*/
$di->setShared('profiler', function () {
$profiler = new Profiler();
return $profiler;
});
/**
* @desc 註冊數據庫(連接)服務
* @author zhaoyang
* @date 2018年5月14日 下午9:01:36
*/
$di->setShared('db', function () {
$dbConfig = $this->getConfig()->services->db->toArray();
$mysql = new Mysql($dbConfig);
if ($dbConfig['logged'] ?? false) {
$eventsManager = new EventsManager();
$eventsManager->attach('db', new DbProfilerPlugin());
$mysql->setEventsManager($eventsManager);
}
return $mysql;
});
/**
* @desc 註冊日誌服務
* @author zhaoyang
* @date 2018年5月19日 下午6:20:36
*/
$di->set('logger', function (string $file = null, array $line = null) {
$config = $this->getConfig()->services->logger;
$linConfig = clone $config->line;
!is_null($line) && $linConfig = $linConfig->merge(new Config($line));
$loggerFormatterLine = new LoggerFormatterLine($linConfig->format, $linConfig->date_format);
$fileConfig = $config->file;
if (empty($file)) {
$file = $fileConfig->info;
} else if (array_key_exists($file, $fileConfig->toArray())) {
$file = $fileConfig->$file;
}
$file = Common::dirFormat($file);
$dir = dirname($file);
$mkdirRes = Common::mkdir($dir);
if (!$mkdirRes) {
throw new \Exception('創建目錄 ' . $dir . ' 失敗');
}
$loggerAdapterFile = new LoggerAdapterFile($file);
$loggerAdapterFile->setFormatter($loggerFormatterLine);
return $loggerAdapterFile;
});
/**
* @desc 註冊加密服務
* @author zhaoyang
* @date 2018年5月28日 下午8:17:46
*/
$di->set('crypt', function (string $key = null, int $padding = null, string $cipher = null) {
$cryptConfig = $this->getConfig()->services->crypt;
$crypt = new Crypt();
if (!empty($cryptConfig->key) || !empty($padding)) {
$crypt->setKey($key ?? $cryptConfig->key);
}
if (!empty($cryptConfig->padding) || !empty($key)) {
$crypt->setPadding($padding ?? $cryptConfig->padding);
}
if (!empty($cryptConfig->cipher) || !empty($cipher)) {
$crypt->setCipher($cipher ?? $cryptConfig->cipher);
}
return $crypt;
});
/**
* @desc 註冊緩存
* @author zhaoyang
* @date 2018年5月30日 下午10:30:29
*/
$di->set('cache', function (array $options = []) {
$cacheConfig = $this->getConfig()->services->cache;
$frontendConfig = $cacheConfig->frontend;
if (isset($options['frontend']['adapter'])) {
$frontendOption = new Config($options['frontend']);
if (array_key_exists($options['frontend']['adapter'], $frontendConfig->toArray())) {
$frontendOptionClone = clone $frontendConfig->{$options['frontend']['adapter']};
$frontendOptionClone->merge($frontendOption);
$frontendOption = $frontendOptionClone;
}
} else {
$frontendOption = clone $frontendConfig->data;
$frontendOption->adapter = 'data';
}
$frontendOption = Common::convertArrKeyUnderline($frontendOption->toArray());
if (version_compare(PHALCON_VERSION, '3.2.0', '>')) {
$frontendCache = CacheFrontendFactory::load($frontendOption);
} else {
$frontendClassName = 'Phalcon\\Cache\\Frontend\\' . Text::camelize($frontendOption['adapter']);
$frontendCache = new $frontendClassName($frontendOption);
}
$backendConfig = $cacheConfig->backend;
if (isset($options['backend']['adapter'])) {
$backendOption = new Config($options['backend']);
if (array_key_exists($options['backend']['adapter'], $backendConfig->toArray())) {
$backendOptionClone = clone $backendConfig->{$options['backend']['adapter']};
$backendOptionClone->merge($backendOption);
$backendOption = $backendOptionClone;
}
} else {
$backendOption = clone $backendConfig->file;
$backendOption->adapter = 'file';
}
if ($backendOption->adapter == 'file') {
if (empty($dir = $backendOption->cache_dir)) {
throw new \Exception('緩存目錄不能爲空');
}
$dir = Common::dirFormat($dir);
$mkdirRes = Common::mkdir($dir);
if (!$mkdirRes) {
throw new \Exception('創建目錄 ' . $dir . ' 失敗');
}
}
$backendOption = Common::convertArrKeyUnderline($backendOption->toArray());
if (version_compare(PHALCON_VERSION, '3.2.0', '>')) {
$backendOption['frontend'] = $frontendCache;
$backendCache = CacheBackendFactory::load($backendOption);
} else {
$backendClassName = 'Phalcon\\Cache\\Backend\\' . Text::camelize($backendOption['adapter']);
$backendCache = new $backendClassName($frontendCache, $backendOption);
}
return $backendCache;
});
/**
* @desc 註冊 modelsMetadata服務
* @author zhaoyang
* @date 2018年6月2日 下午10:39:43
*/
$di->setShared('modelsMetadata', function () {
$modelsMetadataConfig = $this->getConfig()->services->models_metadata;
$backendConfig = $this->getConfig()->services->cache->backend;
$optionsArr = $modelsMetadataConfig->options->toArray();
if (!isset($optionsArr['adapter'])) {
throw new \Exception('modelsMetadata必須設置adapter');
}
if (array_key_exists($optionsArr['adapter'], $backendConfig->toArray())) {
$backendOption = clone $backendConfig->{$optionsArr['adapter']};
$optionsArr = $backendOption->merge(new Config($optionsArr))->toArray();
}
if ($optionsArr['adapter'] == 'files') {
if (empty($optionsArr['meta_data_dir'])) {
throw new \Exception('緩存目錄不能爲空');
}
$dir = Common::dirFormat($optionsArr['meta_data_dir']);
$mkdirRes = Common::mkdir($dir);
if (!$mkdirRes) {
throw new \Exception('創建目錄 ' . $dir . ' 失敗');
}
}
$optionsArr = Common::convertArrKeyUnderline($optionsArr);
$modelsMetadataClassName = 'Phalcon\\Mvc\\Model\\MetaData\\' . Text::camelize($optionsArr['adapter']);
$modelsMetadata = new $modelsMetadataClassName($optionsArr);
return $modelsMetadata;
});
/**
* @desc 註冊modelsCache服務
* @author zhaoyang
* @date 2018年6月3日 下午6:22:31
*/
$di->set('modelsCache', function (array $options = []) {
$modelsCacheConfig = clone $this->getConfig()->services->models_cache;
!empty($options) && $modelsCacheConfig->merge(new Config($options));
$options = $modelsCacheConfig->toArray();
$modelsCache = $this->get('cache', [
$options
]);
return $modelsCache;
});
return $di;
至此全部完成。至於怎麼使用,可以看之前的文章
碼雲地址:https://gitee.com/zhao_yang/phalcon_multi_module_framework