【PHP】Yii2中事务的使用以及代码实例
- 格式:doc
- 大小:50.50 KB
- 文档页数:8
yii2之ActiveForm表单使⽤因⽬前项⽬并⾮前后端分离模式,且⽤到PHP的yii2框架(所有html代码,js较多内嵌在.php⽂件内多少采⽤同步提交【喷墨中...】),遂对于前端⾯上需要⽤到的yii2⼩组件⼀些整理(因是前端若涉及到php写法错误或者风格问题,敬请指点)使⽤场景尽量为表单 基础注册调⽤⼩组件<?php use yii\helpers\Html; use yii\widgets\ActiveForm;> //⾸先注册activeForm⼩部件,并赋值给$form(php中的声明变量⽅法⽤$ 等价于js中的var let) //begin 标志⼩部件开始 <?php $form = ActiveForm::begin([ 'id' => 'login-form', //声明⼩部件的id 即form的id //声明需要添加的属性,例如class , data-x等 'options' => ['class' => 'form-horizontal'], ]) ?> //注册完⼩部件后可以在 activeForm⼩部件声明块中调⽤⼩部件的⽅法 <?= $form->field($model, 'password')->passwordInput() ?>//::end标识⼩部件结束<?php ActiveForm::end() ?>1.⾸先就列出activeForm的⼀些基本⽅法: ⾃定义input框:input(); ⽂本框:textInput(); 密码框:passwordInput(); 单选框:radio(),radioList(); 复选框:checkbox(),checkboxList(); 下拉框:dropDownList(); 多选列表:listBox(); 隐藏域:hiddenInput(); ⽂本域:textarea(['rows'=>3]); ⽂件上传:fileInput(); widget扩展 <?= $form->field($model, 'username')->widget(\yii\widgets\MaskedInput::className(), ['mask' => '9999/99/99',]); ?>2.下⾯我就逐⼀描述下各个⽅法的基本调⽤以及如何⾃定义所需(上述各⽅法中input之前均是描述的是input标签的类型) 2.1 input ⽂本框/密码框以及各指定类型框<?php $form=ActiveForm::begin(['id'=>'login','class'=>'login'])?><!-- 简易⽤法使⽤activeForm 的 fiedld⽅法 --><!-- 其中该⽅法下有textInout/passwordInput 等⼀些常⽤input类型⽅法hint 输⼊前的提⽰内容error 错误内容//⼀般由后台⽣成label 可以更改label内的内容在hint,error,label设置class后将会重置了这些⽅法内原来属于容器上的class若需要可以原样赋回去--><!-- 这⾥的$mode为跟字段有关的数据模型,第⼆个参数为关系模型中的字段不存在将报错,第三个参数为模板内的⼀些内容的进⾏⾃定义--><?= $form->field($model, 'username',['options'=>[],//数组⾥⾯可以设置⾃需属性// template 为字符串模板可⾃定义模板,// 其中 {label} {input} {hint} {error} 存在是会调⽤对应封装好的html模板当然你也可以不写这样就不会⽣成yii2内置⼩部件模板'template' => '{label} {input} {hint} {error}',// 以下三个分别可以设置label ,input ,hint,error的属性(都是选填项)// 其中如果后⾯有使⽤->input...,label(...)等将会将这些⾥⾯的配置合并值对应的xxxOptions 内'labelOptions' => ['class'=>'需要在label上添加的类名'//....其他属性集],'inputOptions' => [],'hintOptions' => [],'errorOptions' => [],])->textInput([// 在options数组内可以设置任意属性'class'=>'testClass','value'=>'测试'])->hint(// 设置提⽰内容,当只有⼀个参数切为false(boolean)⽤于显⽰提⽰的标签'Please enter your name',[// 设置任意属性'class' => 'testHint'])->label(// 设置label显⽰内容,当只有⼀个参数切为false(boolean)label标签将不会被渲染'Name',[// 设置任意属性'class' =>'testLabel'])->error([// 任意属性,当只有⼀个参数切为false(boolean)⽤于显⽰错误的标签'class'=>'errors']) ?><!-- 可⾃定义类型input 这⾥只描述了input的参数其余参数参考上个⽰例 --><?= $form->field($model, 'username')->input(// input内只允许放置两个参数即[type ,options]'email',//该处为指定type="xxxx"的input类型['class'=>'tests','value'=>'值']//可在内部定义任何属性) ?><?php ActiveForm::end();?> 2.2 radio 单选框系列<?php $form=ActiveForm::begin(['id'=>'login','class'=>'login'])?><!--⽼实说对这个radio⽅法相当迷惑⼀个单选按钮选择⽽且⼀旦选择⽆法取消,⽆法⼀次柑橘属性放置多个值在有radioList⽅法的前提下觉得相当鸡肋第⼆个参数中false为是否开启label标签若没开启 labelOption 将⽆效,label设置的值直接显⽰在容器内--><?= $form->field($model, 'username')->radio([// 隐藏域中的值'uncheck' =>'test1',// 定义lebal的内容'label' =>'test',// label上的任意属性'labelOptions'=>['gs'=>'test']],false)?><!--单选框组若要设置默认值,则在对应控制器中将指定字段设置为需要选择的值$model->username = 1;--><?= $form->field($model, 'username')->radioList(['0'=>'a','1'=>'b','2'=>'c'],[// tag声改变 class="radio"的⽗级标签若tag设置为h3// 则 <div id="loginform-username" key="testKey" role="radiogroup" aria-required="true">// => 转为 <h3 id="loginform-username" key="testKey" role="radiogroup" aria-required="true">// <div class="form-group field-loginform-username required">// <label class="control-label">Username</label>// <input type="hidden" name="LoginForm[username]" value="">// <div id="loginform-username" key="testKey" role="radiogroup" aria-required="true">// <div class="radio"><label><input type="radio" name="LoginForm[username]" value="0"> a</label></div>// <div class="radio"><label><input type="radio" name="LoginForm[username]" value="1"> b</label></div>// <div class="radio"><label><input type="radio" name="LoginForm[username]" value="2"> c</label></div>// </div>// <p class="help-block help-block-error"></p>// </div>'tag'=>'h3',// 未选择是默认提交的值'unselect'=>'1',// 如果设置了item选项,则忽略此选项'encode'=>false,// 每个单选块之间的内容写的是什么字符串输出就什么字符串'separator'=>'',// 定义在每个input单选按钮上的属性'itemOptions'=>['tess'=>'jzq'], //可调⽤的回调,可⽤于⾃定义与$Item中单个项对应的HTML代码的⽣成。
通常情况下,要在网站中引入JS和CSS这样的静态资源,首先想到的应该是<link><script>这些标签。
它可以轻松的将静态资源引入到网页当中,也因为有这些静态资源,网站才变得生动、美观。
Yii2中的静态资源引入1.使用标签引入(<link><script)2.使用Yii2特有的方式引入。
(重点介绍)那么Yii2的静态资源引入有什么不同?默认情况下,YII2自带了一个静态资源管理器在项目的APP当中,可以使用它管理网站中需要引入的静态文件,但是这里指定的静态资源会在每一个页面都生效,也就是说,只要在静态资源管理器中加入的CSS和JS文件,所有使用了静态资源管理器的视图都会加载这些静态资源静态资源管理器1. 编辑静态资源管理器修改AppAsset.php文件代码namespace backend\assets;use yii\web\AssetBundle;/*** @author Qiang Xue <qiang.xue@>* @since 2.0*/class AppAsset extends AssetBundle{public $basePath = "@webroot";public $baseUrl = "@web";//默认自动加载样式public $css = ["css/site.css",];//默认自动加载jspublic $js = [];//依赖关系管理public $depends = ["yii\web\YiiAsset","yii\bootstrap\BootstrapAsset",];//定义按需加载JS方法,注意加载顺序在最后public static function addJs($view, $jsfile) {$view->registerJsFile($jsfile,[AppAsset::className(),"depends" => "backend\assets\AppAsset"]);}//定义按需加载css方法,注意加载顺序在最后public static function addCss($view, $cssfile) {$view->registerCssFile($cssfile,[AppAsset::className(),"depends" => "backend\assets\AppAsset"]);}}2.使用静态资源管理器。
Yii框架应⽤(Applications)操作实例详解⽬录应⽤主体¶应⽤主体配置应⽤主体属性¶必要属性重要属性实⽤属性应⽤事件EVENT_BEFORE_REQUESTEVENT_AFTER_REQUESTEVENT_BEFORE_ACTIONEVENT_AFTER_ACTION应⽤主体⽣命周期本⽂实例讲述了Yii 框架应⽤(Applications)操作。
分享给⼤家供⼤家参考,具体如下:应⽤主体¶应⽤主体是管理 Yii 应⽤系统整体结构和⽣命周期的对象。
每个Yii应⽤系统只能包含⼀个应⽤主体,应⽤主体在中创建并能通过表达式\Yii::$app全局范围内访问。
信息:当我们说"⼀个应⽤",它可能是⼀个应⽤主体对象,也可能是⼀个应⽤系统,是根据上下⽂来决定[译:中⽂为避免歧义,Application翻译为应⽤主体]。
Yii有两种应⽤主体: and ,如名称所⽰,前者主要处理⽹页请求,后者处理控制台请求。
应⽤主体配置如下所⽰,当创建了⼀个应⽤主体,它会加载⼀个⽂件并传给应⽤主体。
require __DIR__ . '/../vendor/autoload.php';require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';// 加载应⽤主体配置$config = require __DIR__ . '/../config/web.php';// 实例化应⽤主体、配置应⽤主体(new yii\web\Application($config))->run();类似其他⽂件, 应⽤主体配置⽂件标明如何设置应⽤对象初始属性。
由于应⽤主体配置⽐较复杂,⼀般保存在多个类似如上web.php的当中。
应⽤主体属性¶应⽤主体配置⽂件中有许多重要的属性要配置,这些属性指定应⽤主体的运⾏环境。
Yii2使⽤教程安装1,安装这⾥我直接下载归档⽂件,压缩包安装了。
composer各种⿇烦,国情你懂得。
Yii 2.0 需要 PHP 5.4.0 或以上版本⽀持。
解压⾄我的web⽬录 E:\wamp\www\ibrain\2,配置config/web.php 第12⾏'cookieValidationKey' => '123',//若你通过 Composer 安装,则此步骤会⾃动完成config/db.phpreturn ['class' => 'yii\db\Connection','dsn' => 'mysql:host=localhost;dbname=ibrain',//数据库配置'username' => 'root','password' => '','charset' => 'utf8', 'tablePrefix'=>'ib_',//表前缀,默认没有的,⾃⼰加上];运⾏,看到 Congratulations! 界⾯了。
header("Location:web/index.php");die;⼊门HelloWorld为了弄清楚运⾏的机制,我们跑⼀个helloworld测试。
⾸先看/web/index.php<?php// comment out the following two lines when deployed to productiondefined('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');$config = require(__DIR__ . '/../config/web.php');(new yii\web\Application($config))->run();//这种写法就是5.4以上才⽀持执⾏后的默认⾸页,是跑到/controller/SiteController.php 下的actionIndex()去了。
YII2框架中查询⽣成器Query()的使⽤⽅法⽰例本⽂实例讲述了YII2框架中查询⽣成器Query()的使⽤⽅法。
分享给⼤家供⼤家参考,具体如下:YII2中的yii\db\Query给我们提供了⾮常丰富的⽅法,⽅便我们构建复杂的SQL语句。
Query()与createCommand最⼤区别在于,后者直接使⽤我们写好的SQL语句,前者通过参数和数据库类型⽣成不同SQL,迁移性更好。
<?phpnamespace app\controllers;use YII;use yii\db\Query;use yii\web\Controller;class TestController extends Controller{public function actionTest(){//YII2的Query的使⽤//Query与createCommand的区别是createCommand是直接写⼀个SQL来执⾏。
//Query是根据参数和数据库类型⽣成不同的SQL,提升数据库可迁移性。
//通过all查询多条记录//我这⾥⽤tb_user表来进⾏演⽰$data1 = (new Query())->select(['id', 'name'])->from('{{%user}}')->all();//指定where条件查询$data2 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where('id=:id', [':id' => '2'])->all();//通过one查询单条记录$data3 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where('id=3')->one();//判断记录是否存在$exists = (new Query())->from('{{%user}}')->where('name="aaa"')->exists();if ($exists) {echo 'name=aaa 存在';}//定义字段别名//注意真实的字段名写后⾯,别名写前⾯$data4 = (new Query())->select(['ids' => 'id', 'names' => 'name'])->from('{{%user}}')->where('1=1')->all();//通过orderby排序,和limit限制条数$data5 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where('1=1')->orderBy('id desc')->limit(3)->all();//多个and条件//参数是数组,⼀个key对应⼀个value,默认以and拼接$data6 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['id' => 3, 'name' => 'aaa'])->one();//in条件$data7 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['id' => [4, 5, 6]])->all();//或者如下⽅式$data7_2 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['in', 'id', [4, 5, 6]])->all();//count统计$count = (new Query())->from('{{%user}}')->count();echo '总记录数: ', $count;//⼤于,⼤于等于,⼩于,⼩于等于where条件$data8 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['>=', 'id', 5])->all();$data9 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['<=', 'id', 3])->all();//like查询$data10 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['like', 'name', 'dd'])->all();//between筛选和group by分组//查找出age在18到24之间的,并按sex分组$data11 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['between', 'age', 18, 24])->groupBy('sex')->all();//having筛选//按sex分组,然后统计⼈数⼤于3的$data12 = (new Query())->select(['sex', 'cnt' => 'count(*)'])->from('{{%user}}')->groupBy('sex')->having('cnt > 3')->all();//or逻辑条件//查找姓名为aaa或bbb的⽤户//之前where数组是以key=>value⽅式传递的,如果要表达复杂逻辑关系,//数组第⼀个元素必须声明是什么逻辑,and还是or//第⼆个元素表⽰逻辑左边//第三个元素表⽰逻辑右边$data13 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['or', ['name' => 'aaa'], ['name' => 'bbb']])->all();//复杂的where条件//我这⾥只是作为演⽰//SELECT `id`, `name` FROM `tb_user` WHERE ((`name`='aaa') OR (`name`='bbb')) OR ((`name`='ccc') OR (`name`='ddd')) $data14 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['or',['or',['name' => 'aaa'],['name' => 'bbb'],],['or',['name' => 'ccc'],['name' => 'ddd'],],])->all();//and和or嵌套where条件//SELECT `id`, `name` FROM `tb_user` WHERE (`sex`=1) AND ((`name` LIKE '%aa%') OR (`name` LIKE '%bb%'))$data15 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['and',['sex' => 1],['or',['like', 'name', 'aa'],['like', 'name', 'bb'],],])->all();//有些时候我们需要根据⽤户传递过来的参数追加where条件//追加and条件$query = (new Query())->select(['id', 'name'])->from('{{%user}}')->where('sex=1');//追加age⼤于18的条件$query->andWhere(['>', 'age', 18]);echo $query->createCommand()->getRawSql();//追加or条件$query2 = (new Query())->select(['id', 'name'])->from('{{%user}}')->where(['like', 'name', 'aa']);//追加name相似bb的条件$query2->orWhere(['like', 'name', 'bb']);echo $query2->createCommand()->getRawSql();//表别名和连接查询//SELECT `u`.`id`, `u`.`name`, `aa`.`item_name` FROM `tb_user` `u` LEFT JOIN `tb_auth_assignment` `aa` ON er_id = u.id $data16 = (new Query())->select(['u.id', '', 'aa.item_name'])->from(['u' => '{{%user}}'])->leftJoin(['aa' => '{{%auth_assignment}}'], 'er_id = u.id')->all();}}更多关于Yii相关内容感兴趣的读者可查看本站专题:《》、《》、《》、《》、《》、《》及《》希望本⽂所述对⼤家基于Yii框架的PHP程序设计有所帮助。
【yii2框架学习】——安装yii2高级应用基本信息:□操作系统:win7 旗舰版□主机环境:phpstudy2014(apache+php7.0+mysql)□PHP版本:php7.0配置相关:本人将phpstudy安装到D盘:1、php.exe ☞添加到系统环境【我的电脑】——【属性】——【高级系统设置】——【高级】——【环境变量】系统变量列表下的Path——编辑——添加;D:\phpStudy\php70n(注意:前面要有;隔开)2、PHP开启ssh扩展修改php.ini,打开extension = php_openssl.dll在phpstudy中这样开启:点击图标——其他选项菜单——php扩展及配置——PHP扩展——找到php_openssl重启apache+mysql3、安装composer登录composer官网https:///download/下载composer.exe软件。
Composer-Setup.exe△安装composer.exe,会自动检测php版本,选择对应的php版本安装就好,例子的是△代理可以不填进入下一步,直至完成△检查是否安装成功,打开CMD窗口,输入命令:composer,出现下图表示安装成功4、下载yii2高级应用□进入项目目录,本例子项目路径为D:\butminCmd ☞cd D:\butmin□运行命令下载yii高级应用:php composer.phar create-project yiisoft/yii2-app-advanced advanced2.0.9因缺失composer.phar文件,此时运行报错:Could not open file:composer.phar解决办法:①从官网下载composer.phar文件,https:///download/☞Manual Download 我这里选择1.2.0版本,将下载好的composer.phar文件放到项目路径里面。
Yii2分页的使⽤及其扩展⽅法详解前⾔:说明下我们本篇⽂章都要讲哪些内容分页的使⽤,⼀步⼀步的教你怎么做分页类LinkPager和Pagination都可以⾃定义哪些属性分页类LinkPager如何扩展成我们所需要的第⼀步,我们来看看yii2⾃带的分页类该如何去使⽤?1、controller actionuse yii\data\Pagination;$query = Article::find()->where(['status' => 1]);$countQuery = clone $query;$pages = new Pagination(['totalCount' => $countQuery->count()]);$models = $query->offset($pages->offset)->limit($pages->limit)->all();return $this->render('index', ['models' => $models,'pages' => $pages,]);2、Viewuse yii\widgets\LinkPager;//循环展⽰数据foreach ($models as $model) {// ......}//显⽰分页页码echo LinkPager::widget(['pagination' => $pages,])代码基本上可以完全拷贝,修改部分数据即可,相信⼤多数⼈都是看得懂的。
我们接下来看第⼆步,⾃带的分页类都可以定义哪些属性⾸先我们说说LinkPager组件.pagination参数必填,这个是我们Pagination类的实例默认分页类是下⾯这个样⼦的.上下页按钮以及10个按钮⾸先,我们把上下页的按钮修改成中⽂<?= LinkPager::widget(['pagination' => $pages,'nextPageLabel' => '下⼀页','prevPageLabel' => '上⼀页',]); ?>如果你不想要显⽰上下页,可以将prevPageLabel和nextPageLabel设置为false<?= LinkPager::widget(['pagination' => $pages,'nextPageLabel' => false,'prevPageLabel' => false,]); ?>默认不显⽰⾸页也尾页,如果你需要,可以这样设置<?= LinkPager::widget(['pagination' => $pages,'firstPageLabel' => '⾸页','lastPageLabel' => '尾页',]); ?>如果你的数据过少,不够2页,默认不显⽰分页,如果你需要,设置hideOnSinglePage=false即可<?= LinkPager::widget(['pagination' => $pages,'hideOnSinglePage' => false,]); ?>默认显⽰的页码为10页,可以设置maxButtonCount为你想要展⽰的页数<?= LinkPager::widget(['pagination' => $pages,'maxButtonCount' => 5,]); ?>有些⼈不喜欢默认的样式,想要分页带上⾃⼰的样式,可以设置options,不要忘了⾃⾏实现pre,next,disabled等样式<?= LinkPager::widget(['pagination' => $pages,'options' => ['class' => 'm-pagination'],]); ?>接下来我们谈谈Pagination组件默认的分页路由是下⾯这样⼦的,我们看看能做点什么/controller/action?page=2&per-page=20⾸先,我们是必须要指定总条数totalCount的,没这个参数,分页也是没办法实现的$pages = new Pagination(['totalCount' => $totalCount,]);默认分页的数量是20,你可以设置pageSize为你想要的$pages = new Pagination(['totalCount' => $totalCount,'pageSize' => 5,]);从上⾯的分页路由我们可以看到,默认带的有每页的数量per-page 如果你不想显⽰该参数,设置pageSizeParam=false就好$pages = new Pagination(['totalCount' => $totalCount,'pageSizeParam' => false,]);我们也可以看到,默认的页⾯取决于参数page,如果你想改变该参数为p,设置pageParam=p就好$pages = new Pagination(['totalCount' => $totalCount,'pageParam' => 'p',]);如果你的分页存在于⾸页,相信你肯定想要/?p=1⽽不是/site/index?p=1,我们看看怎么隐藏掉路由$pages = new Pagination(['totalCount' => $totalCount,'route' => false,]);可能你会发现分页类Pagination有⼀个bug,假如我们只有1页的数据,但是⼿动更改地址栏的page=20的时候,也会显⽰page=1的数据?当然,这在⼤部分接⼝API中就很让⼈厌烦。
php中yii框架实例⽤法Yii2框架在⽬前⽽⾔,⽹络上好评不断,最主要的原因,不管是新的框架,还是回顾旧的框架,总是有⼀个⽆法代替的优点,就是做事快,在性能使⽤上,也是⼀般框架⽆法媲美的,在php最好⽤的框架评选了,永远都是前三,就这么⼀个属性好⽤,集结各类优点的框架,⼀定是我们在学习框架时候的⾸先,了解是不可避免的。
yii框架简单介绍快速开发web应⽤程序版本:1.1和2.0,最经常使⽤的是2.0优点:1、yii2中gii⽐较⽅便,且yii2组件的耦合性也是最强的。
2、重量级框架,可以把代码运⾏发挥到极致安装⽅法:依赖库:composer install配置库:php ./yii installyii框架可以应⽤于管理员的后台,稳定性能,以及排版样式还是⼗分好看的,不少⼤⼚的框架上都注⼊了yii框架,感兴趣的⼩伙伴可以⾃⾏试试。
PHP中Yii框架的基本⽤法Yii demo 中的 blog 例⼦drop table if exists `tbl_user`;CREATE TABLE tbl_user(`user_id` INTEGER NOT NULL AUTO_INCREMENT comment '主键',`username` VARCHAR(128) NOT NULL comment '⽤户名',`nickname` VARCHAR(128) NOT NULL comment '昵称',`password` VARCHAR(128) NOT NULL comment '密码',`email` VARCHAR(128) NOT NULL comment '邮箱',`is_delete` tinyint not null default 0 comment '删除标志',unique key(`username`),primary key (`user_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 comment='⽤户表';drop table if exists `tbl_post`;CREATE TABLE tbl_post(`post_id` INTEGER NOT NULL AUTO_INCREMENT comment '主键',`title` VARCHAR(128) NOT NULL comment '标题',`content` TEXT NOT NULL comment '⽂章内容',`tags` TEXT comment '标签',`status` INTEGER NOT NULL comment '状态,0 = 草稿,1 = 审核通过,-1 = 审核不通过,2 = 发布',`create_time` INTEGER comment '创建时间',`update_time` INTEGER comment '更新时间',`author_id` INTEGER NOT NULL comment '作者',`is_delete` tinyint not null default 0 comment '删除标志',CONSTRAINT `post_ibfk_1` FOREIGN KEY (author_id)REFERENCES tbl_user (`user_id`) ON DELETE CASCADE ON UPDATE RESTRICT,primary key (`post_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 comment='⽇志表';到此这篇关于php中yii框架实例⽤法的⽂章就介绍到这了,更多相关php中yii框架怎么⽤内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
Yii2结合Workerman的websocket⽰例详解前⾔本⽂主要给⼤家介绍了关于Yii2结合Workerman的websocket的相关内容,两者都是好东西,我就想着能不能结合起来,这样Yii2出现瓶颈的时候有些业务就可以平滑地迁移到Workerman中。
下⾯话不多说了,来随着⼩编来⼀起看看详细的介绍吧步骤如下1、安装workermancomposer require workerman/workerman2、启动workerman创建commands/WorkermanWebSocketController.php⽂件创建actionIndex()函数,⽤来启动,代码如下public function actionIndex(){if ('start' == $this->send) {try {$this->start($this->daemon);} catch (\Exception $e) {$this->stderr($e->getMessage() . "\n", Console::FG_RED);}} else if ('stop' == $this->send) {$this->stop();} else if ('restart' == $this->send) {$this->restart();} else if ('reload' == $this->send) {$this->reload();} else if ('status' == $this->send) {$this->status();} else if ('connections' == $this->send) {$this->connections();}}添加初始化模块public function initWorker(){$ip = isset($this->config['ip']) ? $this->config['ip'] : $this->ip;$port = isset($this->config['port']) ? $this->config['port'] : $this->port;$wsWorker = new Worker("websocket://{$ip}:{$port}");// 4 processes$wsWorker->count = 4;// Emitted when new connection come$wsWorker->onConnect = function ($connection) {echo "New connection\n";};// Emitted when data received$wsWorker->onMessage = function ($connection, $data) {// Send hello $data$connection->send('hello ' . $data);};// Emitted when connection closed$wsWorker->onClose = function ($connection) {echo "Connection closed\n";};}添加启动模块public function start(){$this->initWorker();// 重置参数以匹配Workerglobal $argv;$argv[0] = $argv[1];$argv[1] = 'start';if ($this->daemon) {$argv[2] = '-d';}// Run workerWorker::runAll();}添加停⽌模块/*** workman websocket stop */public function stop(){$this->initWorker();// 重置参数以匹配Workerglobal $argv;$argv[0] = $argv[1];$argv[1] = 'stop';if ($this->gracefully) {$argv[2] = '-g';}// Run workerWorker::runAll();}添加重启模块/*** workman websocket restart */public function restart(){$this->initWorker();// 重置参数以匹配Workerglobal $argv;$argv[0] = $argv[1];$argv[1] = 'restart';if ($this->daemon) {$argv[2] = '-d';}if ($this->gracefully) {$argv[2] = '-g';}// Run workerWorker::runAll();}添加重载模块/*** workman websocket reload */public function reload(){$this->initWorker();// 重置参数以匹配Workerglobal $argv;$argv[0] = $argv[1];$argv[1] = 'reload';// Run workerWorker::runAll();}添加状态模块/*** workman websocket status*/public function status(){$this->initWorker();// 重置参数以匹配Workerglobal $argv;$argv[0] = $argv[1];$argv[1] = 'status';if ($this->daemon) {$argv[2] = '-d';}// Run workerWorker::runAll();}添加链接数模块/*** workman websocket connections*/public function connections(){$this->initWorker();// 重置参数以匹配Workerglobal $argv;$argv[0] = $argv[1];$argv[1] = 'connections';// Run workerWorker::runAll();}3、前端调⽤<script>// Create WebSocket connection.const ws = new WebSocket('ws://{{ app.request.hostName }}:2347/'); // 这⾥是获取的⽹站的域名,测试的时候可以改为⾃⼰的本地的ip地址 // Connection openedws.addEventListener('open', function (event) {ws.send('Hello Server!');});// Listen for messagesws.addEventListener('message', function (event) {console.log('Message from server ', event.data);});setTimeout(function() {ws.send('ssssss');}, 10000);</script>4、config参数配置修改console.php并添加如下代码'controllerMap' => ['workerman-web-socket' => ['class' => 'app\commands\WorkermanWebSocketController','config' => [],5、nginx配置为什么会⽤ nginx,我们正常部署上线是不可能直接使⽤ip的,这个户存在安全隐患,最好是绑定⼀个域名server {charset utf-8;client_max_body_size 128M;listen 2347;server_name ; # 这⾥改为⾃⼰的域名access_log /xxx.workerman.access.log; # 换成⾃⼰服务器的nginx⽇志路径error_log /xxx.workerman.error.log; # 换成⾃⼰服务器的nginx⽇志路径location / {proxy_pass http://127.0.0.1:2346; # 代理2346 也可以根据项⽬配置为⾃⼰的端⼝proxy_set_header X-Real-IP $remote_addr;proxy_set_header Host $host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";}}重新nginxnginx -s relad 或者 sudo nginx -s reload然后将第3步的代码加⼊⾃⼰做的视图中,如果没有问题的话,websocket启动后就能正常通讯了。
【PHP】Yii2中事务的使用以及代码实例前言一般我们做业务逻辑,都不会仅仅关联一个数据表,所以,会面临事务问题。
数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。
通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。
一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。
事务是数据库运行中的一个逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。
准备数据库引擎为innodb本文使用的yii版本为2.0.5,只要是2.0以上就没有问题运行环境为PHP7.0.0,Mysql5.6Yii中的事务处理异常/*** 测试事务*/public function actionTest(){//创建事务$tr = Yii::$app->db->beginTransaction();try {for($i=1;$i<=3;$i++){$test = new Areas();$test->name = 'name'.$i;$test->sort=1;if($test->save()){echo "save $i | ";}}$test = new Areas();$test->name = 'ab'.$i;$test->sorta=1; //写入不存在的字段if(!$test->save()){"save fail"; //如果没有写入就输出}//提交$tr->commit();} catch (Exception $e) {//回滚$tr->rollBack();echo "rollback";}}运行结果save 1 | save 2 | save 3 | rollback1注意,因为最后的数据没有插入成功,触发了事务的回滚,所以数据表没有新增数据产生。
触发事务回滚的原因是代码出现了异常(Exception)。
处理数据失败一般来讲,我们的运行中的代码是不会出现这种明显的异常,这种异常会在开发测试过程中消灭掉。
而真正造成数据需要回滚的是我们的某个业务出现问题,导致没有写入部分的数据。
/*** 测试事务*/public function actionTest(){//创建事务$tr = Yii::$app->db->beginTransaction();try {for($i=1;$i<=3;$i++){$test = new Areas();$test->name = 'name'.$i;$test->sort=1;if($test->save()){echo "save $i | ";}}$test = new Areas();$test->name = null; //数据库设计name不能为空,人为造成写入失败。
$test->sort=1; //写入不存在的字段if(!$test->save()){echo "save fail"; //如果没有写入就输出}//提交$tr->commit();} catch (Exception $e) {//回滚$tr->rollBack();echo "rollback";}}运行结果如下,数据库插入了三条数据。
save 1 | save 2 | save 3 | save fail1也就是说,如果因为业务逻辑导致某个数据表没有写入数据,也没有出现对应的回滚。
改进方案如下/*** 测试事务*/public function actionTest(){//创建事务$tr = Yii::$app->db->beginTransaction();try {for($i=1;$i<=3;$i++){$test = new Areas();$test->name = 'name'.$i;$test->sort=1;if($test->save()){echo "save $i | ";}}$test = new Areas();$test->name = null; //数据库设计name不能为空,人为造成写入失败。
$test->sort=1; //写入不存在的字段if(!$test->save()){throw new \yii\db\Exception(); //手动抛出异常,再由下面捕获。
}//提交$tr->commit();} catch (Exception $e) {//回滚$tr->rollBack();echo "rollback";}}运行结果如下,数据库没有插入新数据,事务被回滚。
save 1 | save 2 | save 3 | rollback1分散的数据处理由于实际项目的复杂程度,导致我们的数据库操作分散在不同的Model中。
所以,实际项目的代码不会是上面的样子。
模拟需求接收参数:名字性别签名业务处理流程:接收参数由发号器得到用户的uid,发号器对应数据表增加一位数字把名字、性别、签名和上一步的uid写入用户信息表初始化用户余额表回滚触发时机:初始化余额表没有传入uid导出没有写入数据实际代码//Controller/*** 测试事务-注册用户*/public function actionReg(){//获取请求$request = Yii::$app->request;//设定返回格式$response = Yii::$app->response;$response->format = \yii\web\Response::FORMAT_JSON; //返回json//测试代码,去掉验证身份步骤$name = $request->get("name");$gender = $request->get("gender");$sign = $request->get("sign");//测试代码,省略参数校验步骤$tr = Yii::$app->db->beginTransaction();try {//得到uid$uid = App::getSeNo();UserProfile::add($uid, $name, $gender, 1, $sign);$user_balance = UserBalance::initUserBalance($uid);$tr->commit(); //提交数据} catch (Exception $e) {//回滚$tr->rollBack();return $e->getMessage(); //返回自定义异常信息}return $user_balance;}//UserProfile/*** 添加用户信息* @param $user_id* @param $nikename* @param $gender* @param $user_type* @param string $intro* @return UserProfile* @throws \Exception*/public static function add($user_id, $nikename, $gender,$user_type,$intro="") { $model = new UserProfile();$model->gender = $gender;$model->nikename = $nikename;$model->user_id = $user_id;$model->user_type=$user_type;$model->intro=$intro;$model->update_time = time();$insert =$model->insert();if(!$insert){throw new Exception("没有写入用户资料");}return $model;}//UserBalance/*** 初始化用户的可提现余额* @param $user_id*/public static ction initUserBalance($user_id){ $info=self::find()->where(['user_id'=>$user_id])->one();if(!$info ){$model=new UserBalance();$model->user_id = $user_id;$model->price= "0";$model->update_time=time();$insert = $model->insert();if(!$insert){throw new Exception("没有初始化用户余额");}$info=$model;}return $info->attributes;}正常的结果如下{"id":124,"user_id":1473179883,"price":"0","update_time":1473179883} 1如果把初始化用户余额部分的user_id没有传递成功,返回的结果如下"没有初始化用户余额"1我们可以针对具体情况定位到错误所在位置,及时修改。
事务(Transaction)从上面的实际代码可以看出,创建了事务,只要在范围内,就算是引入的别的Model也能把异常NG返回,完成回滚操作。
一般情况下,整个Yii应用使用了同一个数据库连接,或者说是使用了单例。
而在yii\db\Connection中,又对事务对象进行了缓存:class Connection extends Component{// 保存当前连接的有效Transaction对象private $_transaction;// 已经缓存有事务对象,且事务对象有效,则返回该事务对象// 否则返回nullpublic function getTransaction(){return $this->_transaction && $this->_transaction->getIsActive() ? $this->_transaction : null;}// 看看启用事务时,是如何使用事务对象的public function beginTransaction($isolationLevel = null){$this->open();// 缓存的事务对象有效,则使用缓存中的事务对象// 否则创建一个新的事务对象if (($transaction = $this->getTransaction()) === null) {$transaction = $this->_transaction = new Transaction(['db' => $this]);}$transaction->begin($isolationLevel);return $transaction;}}因此,可以认为整个Yii应用,使用了同一个Transaction 对象,也就是说,Transaction::_level 在整个应用的生命周期中,是有延续性的。