今天使用class_exists检查是否安装yii2官方扩展yiisoft/yii2-imagine类的时候
if(class_exists('Image')){}
这样无论怎么检查都是flash
原来框架里需要使用完整命名空间路径
use yii\imagine\Image; if(class_exists('yii\imagine\Image')){}
这样才能正确检查类是否有效。
今天使用class_exists检查是否安装yii2官方扩展yiisoft/yii2-imagine类的时候
if(class_exists('Image')){}
这样无论怎么检查都是flash
原来框架里需要使用完整命名空间路径
use yii\imagine\Image; if(class_exists('yii\imagine\Image')){}
这样才能正确检查类是否有效。
今天yii2表格GridView使用kartik扩展yii2-export导出excel文档的时候需要在表格内容前面或后面加一些说明内容,结果官方文档说明也不是很清楚,查看vendor\kartik-v\yii2-export\src\ExportMenu.php源码发现有contentBefore和contentAfter两个属性可以用,尝试下果然可以,代码如下:
<?php echo ExportMenu::widget([ 'dataProvider' => $dataProvider, 'columns' => $columns, 'showColumnSelector' => false, 'asDropdown' => false, 'exportConfig' => [ ExportMenu::FORMAT_HTML => false, ExportMenu::FORMAT_CSV => false, ExportMenu::FORMAT_TEXT => false, ExportMenu::FORMAT_PDF => false, ExportMenu::FORMAT_EXCEL => false, ExportMenu::FORMAT_EXCEL_X => [ 'icon' => '', 'iconOptions' => ['class' => ''], 'label' => '<button id="download">导出</button>', 'options' => ['class' => 'btn btn-primary', 'style' => 'display:none'], ], ], //导出excel内容前面加内容 'contentBefore' => [ ['value' => 'v1'], ['value' => 'v2'], ], //导出excel内容后面加内容 'contentAfter' => [ ['value' => 'v1'], ['value' => 'v2'], ], 'filename' => date('YmdHi'), ]);
今天想起之前github的名称命名有问题需要修改,但是这样要注意,会影响之前的所有仓库项目发布,因为地址会发生改变。在Setting-Account Setting-Change username处修改用户名即可,如图:
今天发现github有个之前保存的旧项目需要删除,查看了下,如图登陆账号进入项目点击setting页面,拉到最下面点Delete this repository,弹出删除确认对话框,根据提示输入项目名称,点击提交即可。
yii2日志自动发送邮件网上已经有很多例子了,这里会把踩坑和别的说说。
同样先把基本的说说,先配置项目公用邮箱配置common/config/main-local.php,自己用qq邮箱开通smtp就可以了。
'components' => [ 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=yii2advanced', 'username' => 'root', 'password' => 'root', 'charset' => 'utf8', ], 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', 'viewPath' => '@common/mail', // send all mails to a file by default. You have to set // 'useFileTransport' to false and configure a transport // for the mailer to send real emails. //if ($this->useFileTransport) { // $isSuccessful = $this->saveMessage($message); //} else { // $isSuccessful = $this->sendMessage($message); //} 'useFileTransport' => false,//这句一定有,false发送邮件,true只是生成邮件在runtime文件夹下,不发邮件 'transport' => [ 'class' => 'Swift_SmtpTransport', 'host' => 'smtp.qq.com', //每种邮箱的host配置不一样 'username' => 'admin@netpc.com.cn', 'password' => 'xxx', 'port' => '465', 'encryption' => 'ssl', ], 'messageConfig' => [ 'charset' => 'UTF-8', 'from' => ['admin@netpc.com.cn' => 'admin'] ], ], ],
以上配置成功后就能发送邮件了,
$mail= Yii::$app->mailer->compose(); $mail->setTo('admin@netpc.com.cn'); $mail->setSubject($title); //$mail->setTextBody('text'); //发布纯文字文本 $mail->setHtmlBody("<br>商品:<a href='".$url."' target='_blank'>地址</a>"); //发布可以带html标签的文本 if($mail->send()) return "success"; else return "failse";
这样只是自己能发邮件,但是日志错误是不会自动发送的,这时候需要配置项目内容,这里用api项目举例,文件api/config/main.php。
'log' => [ 'traceLevel' => YII_DEBUG ? 3 : 0, //'flushInterval' => 1, 'targets' => [ [ //'class' => 'yii\log\EmailTarget',//默认邮件处理类 'class' => 'api\components\EmailTargetKen',//自定义日志处理类 //'levels' => ['error', 'warning', 'trace', 'info'],//各种等级区分,根据需要使用 'levels' => ['error'], 'categories' => ['email_log'], 'mailer' => 'mailer', 'message' => [ 'from' => ['admin@netpc.com.cn' => 'admin'], 'to' => ['admin@netpc.com.cn'], 'subject' => 'Log message', ], 'except' => ['yii\web\HttpException:404'], // 排除404,不然的话你会发现你的邮箱里全塞满了这些邮件 'exportInterval' => 1,//阀值一个错误的时候就执行输出 'logVars' => [], ], [ 'class' => 'yii\log\FileTarget',//默认文件处理类 'levels' => ['error', 'warning'], 'exportInterval' => 1, 'categories' => ['myinfo'], //'categories' => ['yii\*'],//$categories the message categories to filter by. If empty, it means all categories are allowed. 'logVars' => ['*'],//记录最基本的 []赋值也可以 //'logFile' => '@runtime/logs/order.log'.date('Ymd'),//用日期方式记录日志 ], ], ],
这里说说坑了,假如你配置了categories这个属性,那么只有在自己代码里面执行Yii::error这样代码才能触发文件记录和发送邮件错误日志,而且是必需程序能正常完全执行完毕才能触发,例如代码有个语法输错array(少了一个括号,有没有配置一个全局没有categories分类的日志配置,那么以下Yii::error的日志都不会被触发,除非加多一个没有categories的全局配置。
Yii::error('error_test1'); Yii::error('error_test2','myinfo');//只会记录到myinfo分类文件日志里 Yii::error('error_test3','email_log');//只会记录到email_log分类邮件日志里
我就是按照网上配置了categories这个属性,结果没有用YII:error去触发错误,一直都没办法查看到日志和邮件。
我建议如果你需要分类保存日志,也需要配置一个全局的,因为只有全局没有限制分类的存在才能记录到所有的错误,那怕你没有配置分类,也能传分类参数用分类记录日志。
接下来说说api\components\EmailTargetKen这个自定义处理类,看看源码包括数据库记录什么都可以自己搞出来加工处理整合在一起。
我为什么做处理是因为在做测试的时候,故意写错语法,界面提示{“name”:”PHP Parse Error”,”message”:”syntax error, unexpected ‘]'”,”code”:4,”type”:”yii\\base\\ErrorException”,”file”:后面省略,可是日志文件里面却记录的不一样,少了”name”:”PHP Parse Error”这句语法错误提示,翻看源码后发现记录和提示的确是不一样。所以只能自己加工了。
namespace api\components; public function export() { // moved initialization of subject here because of the following issue // https://github.com/yiisoft/yii2/issues/1446 if (empty($this->message['subject'])) { $this->message['subject'] = 'Application Log'; } $error = Yii::$app->errorHandler->exception; $messages = array_map([$this, 'formatMessage'], $this->messages); //不喜欢它70个字符截断换行的方式 //$body = wordwrap(implode("\n", $messages), 70); //如果捕获的到错误就加上错误名称 if($error){ $body = $error->getName().implode("\n", $messages); }else{ $body = implode("\n", $messages); } $message = $this->composeMessage($body); if (!$message->send($this->mailer)) { throw new LogRuntimeException('Unable to export log through email!'); } }
这样就能带上错误名称,有名称一看提示就能清楚大概是什么问题导致的。
今天有个域名的免费https证书过期了,然后重新申请更新后,谷歌浏览器上显示不安全,可是火狐没问题。
谷歌按F12,然后切换到“Security”,查看该网站使用的ssl证书情况,显示页面不安全。
This page is not secure.
Active content with certificate errors
You have recently allowed content loaded with certificate errors (such as scripts or iframes) to run on this site.
网上https过期,一般就是查看证书是否过期,电脑时间是否正确,最后我测试用一个文本文件访问都出现同样的错误提示,那样肯定没有脚本或框架。
考虑应该是证书缓存,晚上找了删除方法,还是不行。
最后很简单,什么问题都没有,就是重启下浏览器,哎,表示无语,重启重启重启,3遍。
用yii2搭建了一个restful风格api接口,想要通过配置文件直接就强制所有action直接返回json数据格式,结果发现移动只要继承use yii\rest\ActiveController;控制器配置文件bootstrap和response的配置就会失效。最后看源码发现ActiveController继承\vendor\yiisoft\yii2\rest\Controller.php控制器里面通过behaviors行为重写了返回信息的数据格式。那么如果选择继承ActiveController控制器的话就只能在当前的行为重写返回数据格式规则,这样就需要每个控制器都去写规则了,如果想全局只能从配置文件里在response里执行到最后截取要出去数据根据自己的需求定义再输出,但是这样又不够灵活,自己看着办吧。参考如下配置内容根据自己需要修改:
return [ 'id' => 'app-api', 'basePath' => dirname(__DIR__), 'controllerNamespace' => 'api\controllers', 'bootstrap' => [ 'log', [ 'class' => 'yii\filters\ContentNegotiator', 'formats' => [ 'application/json' => yii\web\Response::FORMAT_JSON, //'text/html' => yii\web\Response::FORMAT_JSON, //'application/xml' => yii\web\Response::FORMAT_XML, ], ] ], 'modules' => [ 'v1' => [ //module 与gii生成module配置的ModuleID 一致 'class' => 'api\modules\v1\Module', ], ], 'components' => [ 'request' => [ 'csrfParam' => '_csrf-api', 'parsers' => [ //返回的数据格式为json 'application/json' => 'yii\web\JsonParser', 'text/json' => 'yii\web\JsonParser', ], ], //'response' => [ // 'on beforeSend' => function($event) { // if(is_array($event->sender->data)){ // $event->sender->format = 'json'; // } // }, //], 'response' => [ 'format' => 'json',//全局controller 返回json 不包括 ActiveController 会被行为重写 //'charset' => 'UTF-8', ], 'response' => [ 'format' => 'json', 'formatters' => [ \yii\web\Response::FORMAT_JSON => [ 'class' => 'yii\web\JsonResponseFormatter', 'prettyPrint' => YII_DEBUG, // use "pretty" output in debug mode 'encodeOptions' => JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, // ... ], ], ], 'response' => [ 'class' => 'yii\web\Response', 'on beforeSend' => function ($event) { $response = $event->sender; $response->data = [ 'success' => $response->isSuccessful, 'code' => $response->getStatusCode(), 'message' => $response->statusText, 'data' => $response->data, ]; $response->statusCode = 200; }, ],
在当前控制器里重写ActiveController控制器里的行为内容,参考着用。
class DefaultController extends ActiveController { /** * Renders the test view for the module * @return string */ //public function behaviors() //{ // return [ // [ // 'class' => 'yii\filters\ContentNegotiator', // 'only' => ['view', 'index'], // in a controller // // if in a module, use the following IDs for user actions // // 'only' => ['user/view', 'user/index'] // 'formats' => [ // 'application/json' => Response::FORMAT_JSON, // ], // 'languages' => [ // 'en', // 'de', // ], // ], // ]; //} public function behaviors() { $behaviors = parent::behaviors(); $behaviors['contentNegotiator']['formats']['text/html'] = Response::FORMAT_JSON; //print_r($behaviors);exit; return $behaviors; }
今天配置了个新svn库,passwd也配置了密码,能导出版本库,提交的时候却提示svn: Commit failed (details follow): svn: Authorization failed.
提交失败,仅仅是因为配置了密码,可是你没让它用起来,所以库只有只读的权限,没有写权限。
修改svnserve.conf:
[general]
anon-access = read
auth-access = write
password-db = passwd
authz-db = authz
一般刚开始使用yii2的时候就会疑惑为什么项目有个\web\assets目录会有一些随机名称的子目录,而且一删除它还会时不时生成。
其实它就是yii2前端页面加载需要资源包,一般包括了静态的css、js、视频、图片、字体等。
一般资源包因为都是放在http无法访问的目录上,所以它才会根据组件和系统配置集中打包生成到\web\assets可访问目录下。
一切从main.php页面中使用use backend\assets\AppAsset;开始,
资源包指定为继承 yii\web\AssetBundle 的 PHP 类, 包名为可自动加载的 PHP 类名, 在资源包类中,要指定资源所在位置, 包含哪些 CSS 和 JavaScript 文件以及和其他包的依赖关系。
<?php namespace app\assets; use yii\web\AssetBundle; class AppAsset extends AssetBundle { public $basePath = '@webroot'; public $baseUrl = '@web'; public $css = [ 'css/site.css', ['css/print.css', 'media' => 'print'], ]; public $js = [ ]; public $depends = [//列出该资源包依赖的其他资源包 'yii\web\YiiAsset', 'yii\bootstrap\BootstrapAsset', ]; }
如上 AppAsset 类指定资源文件放在 @webroot 目录下,对应的 URL 为 @web,资源包中包含一个 CSS 文件 css/site.css,没有 JavaScript 文件, 依赖其他两个包 yii\web\YiiAsset 和 yii\bootstrap\BootstrapAsset。
\vendor\yiisoft\yii2\web\YiiAsset.php内容如下,YiiAsset又依赖了yii\web\JqueryAsset
class YiiAsset extends AssetBundle { public $sourcePath = '@yii/assets'; public $js = [ 'yii.js', ]; public $depends = [ 'yii\web\JqueryAsset', ]; }
\vendor\yiisoft\yii2\web\JqueryAsset.php内容如下,可以看到最终加载了\vendor\bower-asset\jquery\dist目录下的jquery.js文件,并复制生成到了\web\assets目录下。
class JqueryAsset extends AssetBundle { public $sourcePath = '@bower/jquery/dist'; public $js = [ 'jquery.js', ]; }
这里顺便说点信息,一般\web\assets会有更新问题,可以使用配置linkAssets属性来让它使用快捷方式指定到资源目录位置,而不是复制多一份方式。不使用就记得更新了文件记得删除让它重新生成。
如果默认的jquery版本不合适,就使用覆盖’yii\web\JqueryAsset’方式调用不同版本的jquery。
'components' => [ 'assetManager'=> [ 'linkAssets'=> true,//在项目/web/assets目录使用快捷方式指定到资源目录位置 'bundles' => [ //'yii\web\JqueryAsset' => false,//禁用 'yii\web\JqueryAsset' => [ /* 'js' => [ //YII_ENV_DEV ? 'jquery.js' : 'jquery.min.js', '//lib.sinaapp.com/js/jquery/2.2.4/jquery-2.2.4.min.js' ]*/ ], ], ], ],
其它具体内容可以看看官方文档:https://www.yiichina.com/doc/guide/2.0/structure-assets
最近yii2安装2.0.34最新AdminLTE后台模板和yii2-admin集成rbac管理组件。
composer require dmstr/yii2-adminlte-asset “2.*”
composer require mdmsoft/yii2-admin “2.x-dev”
发现在yii2-admin添加才当时候界面不能正常弹出下拉选择框,最后排查得知是因为yii2最新版Asset引用了最新的jquery-3.4.1.js。
前端脚本调用的时候出现Uncaught TypeError: elem.getClientRects is not a function错误提示。
该函数只能是jquery2才能正常使用,替换jquery即可。