yii2框架实现引导安装功能
2017-07-05 20:41
501 查看
最近有在学习yii框架,想着做一个小型的cms。
一个cms最开始的动作当然时安装引导,参考lulucms的代码,学习实现的结果如下。
2.前台的入口文件判断是否已经安装,通过文件锁进行标识,如果没有安装过则执行安装应用的入口文件install.php,已经安装则正常进入FrontApplication应用
3.进入了应用分几步依次进行,先进行环境判断,再进行数据库信息填写,最后安装数据库文件,如果安装成功,则创建一个安装锁文件install.lock,代表已经安装过程序.
显然,应用是通过配置文件进行初始化的,因为自带的backend的入口文件位于 backend/web/index.php,所以它的配置文件位置就是
打开backend的主配置文件main.php 可以看到如下代码
其中返回的数组中
‘id’ => ‘app-backend’ //作用是指定全局唯一的应用id号,
‘basePath’ => dirname(__DIR__) //指定backend应用的目录位置
‘controllerNamespace’ => ‘backend\controllers’ //指定控制器命名空间
‘bootstrap’ => [‘log’] //指定随应用启动而启用的组件
‘modules’ => [], //指定应用的子模块 可理解为应用中的应用
‘components’ => …. //往应用注册组件
‘params’ => $parms //用户本地的一些配置参数
到这里答案就很明显了,假设现在需要自定义一个新的独立的安装引导应用,也就是需要在根目录中建立一个文件夹 命名为install,在install下新建一个main.php,保存应用的关键配置信息
main.php 配置信息如下
同时,公共配置 根目录/data/config/main.php 代码如下
入口文件 install.php存放在根目录下
可以看到,除了添加公共配置文件外,还添加了应用主配置文作为应用最终的配置信息。
在上方包含的bootstrap.php文件中,它的作用是起别名,因为yii框架自身的类加载机制依赖别名,所以在bootstrap.php中需要给新增的install应用添加别名,指定install的目录路径,bootstrap最终代码如下
假设已经给install建立好了默认的控制器文件,那么此时访问index.php,不出意外的话就会跳转到index.php?r=install/index,如果成功,就说明应用成功的跑起来了。
解决方法: 通过Yii::$classMap 改变类与路径的映射关系,在入口文件中引入以下文件,命名为overwrite.php
原理: 因为在Yii2源码 yii2\BaseYii中,自动加载机制如下
3.关于PHP函数的收获
一个cms最开始的动作当然时安装引导,参考lulucms的代码,学习实现的结果如下。
第一步 安装介绍 (install.php?r=install/step_one)
第二步 环境检查 (install.php?r=install/step_two)
第三步 数据库配置 (install.php?r=install/step_three)
第四步 安装数据库表 (install.php?r=install/step_processing)
第五步 结果显示 (install.php?r=install/finish)
其它 已经安装提示 (install.php?r=install/stop)
实现思路:
1.安装模块独立出来,命名为install,目录结构和正常的backend应用差不多.2.前台的入口文件判断是否已经安装,通过文件锁进行标识,如果没有安装过则执行安装应用的入口文件install.php,已经安装则正常进入FrontApplication应用
3.进入了应用分几步依次进行,先进行环境判断,再进行数据库信息填写,最后安装数据库文件,如果安装成功,则创建一个安装锁文件install.lock,代表已经安装过程序.
记录笔记
1.yii2如何创建一个install应用?
如果使用yii advanced高级模板,以backend应用的入口文件举栗子,代码是长这样子的<?php defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); require(__DIR__ . '/../../vendor/autoload.php'); require(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php'); require(__DIR__ . '/../../common/config/bootstrap.php'); require(__DIR__ . '/../config/bootstrap.php'); $config = yii\helpers\ArrayHelper::merge( require(__DIR__ . '/../../common/config/main.php'), require(__DIR__ . '/../../common/config/main-local.php'), require(__DIR__ . '/../config/main.php'), require(__DIR__ . '/../config/main-local.php') ); (new yii\web\Application($config))->run();
显然,应用是通过配置文件进行初始化的,因为自带的backend的入口文件位于 backend/web/index.php,所以它的配置文件位置就是
/../config/main.php
打开backend的主配置文件main.php 可以看到如下代码
<?php $params = array_merge( require(__DIR__ . '/../../common/config/params.php'), require(__DIR__ . '/../../common/config/params-local.php'), require(__DIR__ . '/params.php'), require(__DIR__ . '/params-local.php') ); return [ 'id' => 'app-backend', 'basePath' => dirname(__DIR__), 'controllerNamespace' => 'backend\controllers', 'bootstrap' => ['log'], 'modules' => [], 'components' => [ 'request' => [ 'csrfParam' => '_csrf-backend', ], 'user' => [ 'identityClass' => 'common\models\User', 'enableAutoLogin' => true, 'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true], ], 'session' => [ // this is the name of the session cookie used for login on 4000 the backend 'name' => 'advanced-backend', ], 'log' => [ 'traceLevel' => YII_DEBUG ? 3 : 0, 'targets' => [ [ 'class' => 'yii\log\FileTarget', 'levels' => ['error', 'warning'], ], ], ], 'errorHandler' => [ 'errorAction' => 'site/error', ], /* 'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'rules' => [ ], ], */ ], 'params' => $params, ];
其中返回的数组中
‘id’ => ‘app-backend’ //作用是指定全局唯一的应用id号,
‘basePath’ => dirname(__DIR__) //指定backend应用的目录位置
‘controllerNamespace’ => ‘backend\controllers’ //指定控制器命名空间
‘bootstrap’ => [‘log’] //指定随应用启动而启用的组件
‘modules’ => [], //指定应用的子模块 可理解为应用中的应用
‘components’ => …. //往应用注册组件
‘params’ => $parms //用户本地的一些配置参数
到这里答案就很明显了,假设现在需要自定义一个新的独立的安装引导应用,也就是需要在根目录中建立一个文件夹 命名为install,在install下新建一个main.php,保存应用的关键配置信息
main.php 配置信息如下
<?php return [ 'id' => 'app-install',//指定模块名称 'language' => 'zh-CN', 'basePath' => dirname(__DIR__), //指定模块路径 'bootstrap' => ['log'], 'controllerNamespace' => 'install\controllers',//指定命名空间 'defaultRoute' => 'install/index', //默认路由 'components' => [ //错误处理 'errorHandler' => [ 'errorAction' => 'install/index', ], ], ];
同时,公共配置 根目录/data/config/main.php 代码如下
<?php return [ //第三方库加载路径 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', //运行缓存文件路径 'runtimePath' => dirname(dirname(__DIR__)) . '/data/runtime', //组件配置 'components' => [ //缓存组件 'cache' => [ 'class' => 'yii\caching\FileCache', ], //session组件 'session' => [ // this is the name of the session cookie used for login on the frontend 'name' => 'advanced-frontend', ], //日志组件 'log' => [ 'traceLevel' => YII_DEBUG ? 3 : 0, 'targets' => [ [ 'class' => 'yii\log\FileTarget', 'levels' => ['error', 'warning'], ], ], ], //错误处理组件 'errorHandler' => [ 'errorAction' => 'site/error', ], //资源管理组件 'assetManager' => [ 'basePath' => '@webroot/frontend/assets', 'baseUrl'=>'@web/frontend/assets', 'bundles' => [ // you can override AssetBundle configs here ], 'linkAssets' => true, // ... ], 'request' => [ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 'cookieValidationKey' => '6_NpujNa4RDqhQsB9IfERWwD4F9GWbls', ], ], ];
入口文件 install.php存放在根目录下
<?php use yii\web\Application; use source\libs\Common; defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); require(__DIR__ . '/vendor/autoload.php'); require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php'); require(__DIR__ . '/common/config/bootstrap.php'); require (__DIR__. '/source/config/overwrite.php'); $config = yii\helpers\ArrayHelper::merge( //公共组件 require(__DIR__ . '/data/config/main.php'), //模块独立组件 require(__DIR__ . '/install/config/main.php') ); (new Application($config))->run();
可以看到,除了添加公共配置文件外,还添加了应用主配置文作为应用最终的配置信息。
在上方包含的bootstrap.php文件中,它的作用是起别名,因为yii框架自身的类加载机制依赖别名,所以在bootstrap.php中需要给新增的install应用添加别名,指定install的目录路径,bootstrap最终代码如下
<?php Yii::setAlias('@common', dirname(__DIR__)); Yii::setAlias('@frontend', dirname(dirname(__DIR__)) . '/frontend'); Yii::setAlias('@backend', dirname(dirname(__DIR__)) . '/backend'); Yii::setAlias('@console', dirname(dirname(__DIR__)) . '/console'); Yii::setAlias('@source', dirname(dirname(__DIR__)).'/source'); Yii::setAlias("@install",dirname(dirname(__DIR__)).'/install'); Yii::setAlias("@data",dirname(dirname(__DIR__)).'/data');
假设已经给install建立好了默认的控制器文件,那么此时访问index.php,不出意外的话就会跳转到index.php?r=install/index,如果成功,就说明应用成功的跑起来了。
2.如何不改动yii框架源码的情况下重载yii的类
场景:install模块检查用户系统环境时需要使用到yii2的FileHelper类,来检测文件夹的可读可写,需要重载此类,而又不想直接改Yii的源代码。解决方法: 通过Yii::$classMap 改变类与路径的映射关系,在入口文件中引入以下文件,命名为overwrite.php
<?php $alias = '@source/helpers/FileHelper.php'; Yii::$classMap['yii\helpers\FileHelper'] = $alias ;
原理: 因为在Yii2源码 yii2\BaseYii中,自动加载机制如下
public static function autoload($className) { //先判断映射中是否存在 if (isset(static::$classMap[$className])) { $classFile = static::$classMap[$className]; if ($classFile[0] === '@') { $classFile = static::getAlias($classFile); } //判断是否指定命名空间 } elseif (strpos($className, '\\') !== false) { $classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false); if ($classFile === false || !is_file($classFile)) { return; } } else { return; } include($classFile); //抛出异常 if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) { throw new UnknownClassException("Unable to find '$className' in file: $classFile. Namespace missing?"); } }
3.关于PHP函数的收获
a.获取运行PHP当前系统
PHP_OS,是常量
b.获取php.ini的配置信息 如获取最大上传空间限制
get_cfg_var('upload_max_filesize')
c.获取磁盘剩余空间
disk_free_space()函数
d.判断是否可写
is_writable(filename)
e.获取PHP版本号
PHP_VERSION 常量
f.判断某个类是否存在
class_exists()
g.判断某个扩展是否加载
extension_loaded()
h.把变量打印处理 其返回的表示是合法的PHP代码
var_export($var)
用在用户填写了数据库配置信息,然后把数组变为合法的php代码,把这些代码写入文件中.
[b]4.如何绑定事件 ?[/b]
在填写完数据库信息后,点击下一步,先渲染出界面,同时动态的输出安装过程的信息,而不是程序执行到最后一步才渲染页面,这样等待的时间长。这就使用到yii2的绑定.
InstallController
继承的控制器是BaseController
,而BaseController
继承的是yii\web\Controller;
在BaseController中的init初始化方法中,进行对EVENT_AFTER_SEND
事件的绑定,EVENT_AFTER_SEND
是指在动作完成后才会被触发的动作。
Response是yii2框架中的HTTP响应组件,
public function init()
{
parent::init();
//绑定yii EVENT_AFTER_SEND事件
Yii::$app->response->on(Response::EVENT_AFTER_SEND,[$this,'afterResponse']);
}
所有的子类继承BaseController后,通过建立afterResponse方法就能在方法执行后触发一些自定义的行为动作.在InstallController中
//绑定了EVENT_AFTER_SEND事件
public function afterResponse()
{
//如果当前的请求方法为processing
if (Yii::$app->requestedAction->id == 'processing') {
//那么这个方法执行后 就执行下面的_installing方法
$this->_installing();
}
}
[b]5.yii2如何检测数据库是否连接成功 ?[/b]
//$this->InstallForm是表单模型
$config = [
'dsn'=>"mysql:host={$this->InstallForm->dbHost};dbname={$this->InstallForm->dbName}",
'username' => $this->InstallForm->dbUser,
'password' => $this->InstallForm->dbPassword
];
$db = new Connection($config);
try {
$db->open();
$result = $db->isActive? ['status'=>true,'msg'=>'数据库连接成功']:['status'=>false,'msg'=>'数据库连接失败'];
}catch (Exception $e) {
$db->close();
$result = ['status'=>false,'msg'=>$this->getDbError($e->getMessage(),[
'dbHost'=>$this->InstallForm->dbHost,
'dbName'=>$this->InstallForm->dbName
])];
}
6.如何使用yii\db\Connection执行sql语句
//Connection为yii\db\Connection try { $db = new Connection($dbConfig); Lychee::getApp()->set('db',$db); $db->createCommand("USE {$this->InstallForm->dbName}")->execute(); $db->createCommand("SET NAMES 'utf8'")->execute(); self::_showLog("准备初始化数据库",true); return $db; } catch(\Exception $e) { var_dump($e->getMessage()); $error = self::getDbError($e->getMessage(),[ 'dbHost' => $this->InstallForm->dbHost, 'dbName' => $this->InstallForm->dbName ]); self::_showLog($error,false); return false; }
7.如何利用缓冲动态输出安装过程
$str = "安装过程数据"; echo $str; ob_flush(); flush();
8.如果已经安装过 如何防止再进入页面进行安装
//使用beforeAction进行检查 $action->id为当前的动作名称 public function beforeAction($action) { if ($action->id == 'stop' || $action->id == 'finish') { return parent::beforeAction($action); } if (file_exists(Yii::getAlias('@data/install.lock'))) { return $this->redirect(['stop']); } return parent::beforeAction($action); }
9.如何使用数据库操作事务
//任何一个语句失败将会回滚 $db = Yii::$app->get('db'); $transaction = $db->beginTransaction(); try { $db->createCommand($sql)->execute(); $transaction->commit(); return true; }catch(\Exception $e) { $transaction->rollBack(); echo $e->getMessage(); $this->_showLog("建立数据库表时出错",false); return false; }
9.如果还有的话 再来补充
长风破浪会有时,直挂云帆济沧海相关文章推荐
- 使用YII2框架实现微信公众号中表单提交功能
- Yii2框架实现登陆添加验证码功能示例
- Yii2框架实现登录、退出及自动登录功能的方法详解
- vs2005安装程序的制作、.Net框架、数据库打包、卸载功能实现
- 设计模式2思考——web框架中—页面功能设计的实现
- 企业级服务器设计与实现经验之系统框架(二)--功能/应用服务器主体框架
- 企业级服务器设计与实现经验之系统框架(二)--功能/应用服务器主体框架
- 本人用SPRING 框架自己写DAO实现LIMIT功能
- SSH集成框架下真正实现Spring AOP拦截功能
- 罗技mx5000驱动安装,实现所有功能(不用罗技原装接收器)
- cxxtest单元测试框架源码分析(二):所有对外功能实现分析
- 如何用VS里的部署实现在Duwamish7安装时的自动创建数据功能
- 【原创】SSH开发框架中,实现系统启动加载类,读取数据库常用数据进入内存,利用Spring托管,并完成reload功能
- Ajax分页功能的无框架实现方法
- JAVA应用XFire框架来实现WebServie的大文件传输功能之二(上传)
- 通过bboss persistent框架实现数据库分页查询功能
- 多框架 跨页面调用jsp过程,实现功能导航树的隐藏
- 一个使用监听器模式实现的J2ME网络编程框架,包括一个简单的登录功能实现(含源代码)
- 在SDI框架下实现关闭文档而不退出程序的功能
- 框架页面查询功能的实现