置顶 讨论
说明 课程简介 素材及源码 纠错 课程简介 本课程主要内容是如何通过使用 yii2 框架,快速打造个人博客系统。 博客系统主要分两个部分: 后台管理系统(backend) 相关内容:yii2-admin扩展, RBAC基于角色的权限管理,基于Markdown的富文本编辑器,上传图片到七牛,Gii生成代码,自定义Gii模版 前台内容展示(frontend) 相关内容:挂件的应用(widget),博客首页界面排版,文章内容呈现,博客时间史 素材及源码 为了方便大家学习 yii2 相关的知识并应用于实践中,本次教程会提供学习素材。什么是素材呢?就是基于 hyii2 后台管理系统添加了学习教程时所需要的样式文件,js文件,界面排版等。让大家免去在学习后端框架的过程中,去写前端的页面和js。更加精确的掌握 yii2 框架的实战应用。通过教程的学习可以开发出相应的一套完整的博客系统。详情查看 应用搭建 一章 为了保证课程的高品质,我们需要对素材进行收费,购买链接。购买后请联系 391430388 获取素材和源码 前台界面预览:http://hyblog.itdocs.org 管理后台地址:http://hyblog-admin.itdocs.org 账户:test 密码:123456 作者会提供完整的开发素材和成品源码,希望不要借此传播,尊重原创,万分感谢。 纠错 教程中遇到的问题,可以先自己尝试解决,培养自身的问题排查能力是一个程序员基本的要求。 本地环境问题(本站统一环境教程:PHP开发环境部署)。 代码书写错误,引起的报错。 搜索本教程错误集锦(开发中) 若仍不能解决,请联系 QQ:391430388 当然人无完人,也许教程中也存在一些不可避免的疏漏,如果发现可以联系作者,先行致谢!
精华贴
12天前 喜欢(1) 浏览(296) 评论(1)
置顶 博客
概念 把一个大型的单个应用程序和服务拆分为数个甚至数十个的支持微服务,它可扩展单个组件而不是整个的应用程序堆栈,从而满足服务等级协议。 传统的开发模式就是把所有功能都放在一个包里,基本不存在依赖,这样的优势在于开发简单,集中式管理,功能都在本地,不存在分布式的管理和调度消耗。但缺点也很明显:效率低,开发都在同一个项目改代码,相互等待,冲突不断。稳定性差,一个微小的问题,都可能导致整个应用挂掉。另外在资源利用上表现出明显的劣势,比如电商双11大促场景,下单压力非常大,评价的压力相对较少,那么我们希望临时增配应对双11的大流程,只能全部增配,而不能定点只对订单服务增配。所以微服务的架构开始慢慢流行并应用于大型的网站平台。 那么引入今天的主题,Yii 如何做微服务?Yii 可以轻松使用,而不需要基本和高级模板中包含的功能。换句话说,Yii 已经是一个微框架。不需要由模板提供的目录结构与 Yii 一起工作。 安装 Yii 为您的项目创建一个目录并将工作目录更改为该路径。示例中使用的命令是基于 Unix 的,但在 Windows 中也存在类似的命令。 mkdir micro-app cd micro-app Note:需要一些 Composer 的知识才能继续。如果您还不知道如何使用 composer,请花些时间阅读 Composer 指南。 使用您最喜爱的编辑器在 micro-app 目录下创建 composer.json 文件并添加以下内容: { "require": { "yiisoft/yii2": "~2.0.0" }, "repositories": [ { "type": "composer", "url": "https://asset-packagist.org" } ] } 保存文件并运行 composer install 命令。这将安装框架及其所有依赖项。 创建项目结构 安装框架之后,需要为此应用程序创建一个入口点。入口点是您尝试打开应用程序时将执行的第一个文件。出于安全原因,建议将入口点文件放在一个单独的目录中,并将其设置为Web根目录。 创建一个 web 目录并将 index.php 放入其中,内容如下: <?php // comment out the following two lines when deployed to production 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'); $config = require __DIR__ . '/../config.php'; (new yii\web\Application($config))->run(); 还要创建一个名为 config.php 的文件,它将包含所有的应用程序配置: <?php return [ 'id' => 'micro-app', //设置`micro-app`的根目录 'basePath' => __DIR__, // 控制器所在目录。 'controllerNamespace' => 'micro\controllers', // 设置命名空间为 micro 'aliases' => [ '@micro' => __DIR__, ], //默认访问地址 'defaultRoute' => 'home/index', 'components' => [ //请求配置 'request' => [ 'cookieValidationKey' => 'test&123456', 'parsers' => [ 'application/json' => 'yii\web\JsonParser', ] ], //Url 美化 'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'enableStrictParsing' => false, 'rules' => [ '<controller:\w+>/<action:\w+>/<id:\w+>' => '<controller>/<action>', ], ], //数据库配置 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=micro', 'username' => 'root', 'password' => '数据库密码', 'charset' => 'utf8', ], ], ]; Info:尽管配置可以保存在 index.php 文件中,建议单独使用它。 这样它也可以用于控制台应用程序,如下所示。 您的项目现在已经准备进行编码了。尽管由您决定项目目录结构,只要您遵守命名空间即可。 创建第一个控制器 在创建控制器之前,创建一个 controllers/base 目录并创建一个基础控制器 BaseController。 <?php namespace micro\controllers\base; use yii\web\Controller; class BaseController extends Controller { //关闭 csrf 验证 public $enableCsrfValidation = false; } 然后在 controller 文件夹下面 新建一个 SiteController.php,这是默认的 控制器将处理没有路径信息的请求。 <?php namespace micro\controllers; use yii\web\Controller; class HomeController extends BaseController { public function actionIndex() { return '欢迎来到 Yii2.0 微服务!'; } } 如果您想为此控制器使用不同的名称,则可以配置 yii\base\Application::$defaultRoute 进行更改。 例如,对于 HomeController 将会是 'defaultRoute' => 'home/index'。 在这一点上,项目结构应该如下所示: micro-app/ ├── composer.json ├── config.php ├── web/ └── index.php └── controllers/ └── base └── BaseController.php └── HomeController.php └── vendor 如果您尚未设置 Web 服务器,则可能需要查看Web服务器配置文件示例。 另一种选择是使用 yii serve 命令,它将使用 PHP 内置 web 服务器。 您可以通过以下方式从 micro-app / 目录运行它: vendor/bin/yii serve --docroot=./web 在浏览器中打开应用程序URL现在应该打印出“欢迎来到 Yii2.0 微服务!”,它已经在 HomeController::actionIndex() 中返回。 Info:在我们的示例中,我们已将默认应用程序名称空间 app 更改为 micro, 以表明您不受此名称的限制(如果您是这样认为), 然后调整 controllers namespace 并设置正确的别名。
精华贴
10天前 喜欢(1) 浏览(201) 评论(0)
讨论
在提问的时候,适当使用一些小技巧,会让老师快速get到你的问题在哪里,这样会使问题更快被解答喔~ 提问技巧 标题:简洁、易懂,完整表达主题;避免无意义、模糊、口语化标题。 提问内容: 客观描述问题:中性客观描述问题,保证问题的可读性,避免过于简单或模糊; 提供编程环境:问题描述注明编程环境信息,包括操作系统、语言、使用的软件版本等; 输出报错信息:过程中出现异常的话,需提供重现异常的步骤; 输出错误信息:编码过程中的技术问题出现错误应该输出日志或控制台的全部信息,以便更好排查错误; 注明课程时间:针对课程的问题,请在问题描述中注明出现时间,便于及时解答; 排版规范合理:注意文本,代码,标点、语法使用规范,排版合理。 提倡有偿问答:对于有能力的学者,可以提供有偿提问,勾引大神们快速响应(提问者自愿为主,答题者不可强求) 注意: 不要在提问内容框里长篇粘入代码,只需粘出关键代码并加以描述即可 标题不等于提问内容,标题应简明扼要,提问内容应详细描述,二者尽量不要重复。 提问尽量以 PHP/Yii2.0 的内容为主。 千万不要贴一段业务报错代码,问为什么这里报错了,代码调试可以帮您解决大部分的问题。 学员和老师要互相尊重,尊重是有效解决问题的前提,对于人身攻击的问题管理员是有权隐藏的哦~ 说完了如何提问,那么大!神!般!的你在问答区看到了其他小伙伴提出的问题,想要回答时需要注意些什么呢?^_^ 回答建议: 回答保证内容的准确性,不模糊,能实际解决提问者疑问; 回答保证内容通俗易懂,语句通顺、有条理,排版利于阅读; 回答保证内容全面,避免过于简单,可对回答做详细阐释、扩展和引导; 回答保证内容与问题相关,避免所问非所答和过多的重复内容; 添加图片或代码应附上说明,代码用对应代码块包裹并合理排版; 核心思想:要持着“授人以鱼不如授人以渔”的心来回答提问者的问题~
1月前 喜欢(3) 浏览(257) 评论(4)
博客
YII2可以在命令行执行php命令,作为半路出家的撩妹君可谓是抠脚福音。作为一个屌丝级的程序员必须要有智能提示代码的IDE,比如PHPstorm。至于如何免费使用嘛。。。。。 首先明白YII2自带的command示列 \app\commands\HelloController class HelloController extends Controller { /** * This command echoes what you have entered as the message. * @param string $message the message to be echoed. * @return int Exit code */ public function actionIndex($message = 'hello world') { echo $message . "\n"; return ExitCode::OK; } } 首先CD到工程的根目录,目录下有一个 yii文件,我们执行yii hello/index控制台打印了hello world 因此我们可以知道 命令格式如下 yii 控制器名称/动作名称。actionIndex($message = 'hello world')有一个参数,并且有一个默认值,很多时候我们也需要这样的操作。所有我们执行yii hello/index helloYii 将会打印出 helloYii。因此我们可以得知 命令格式如下 yii 控制器名称/动作名称 参数1 参数2... 而action方法中 actionName($parameter1,$parameter...)。如果需要操作数据库则需要在config/console.php配置db因为web上的配置和command是不同的。YII2有了这个后我们可以实现快速插入测试数据,快速执行一些不明白的函数,快速的对自己写的代码进行测试,如果需要配置定时任务给服务器运行也是可以的。如果是Linux系统的话得给yii文件执行权限 并且命令格式如下./yii 控制器名称/动作名称。 很多人也喜欢写到一个web的action,然后用来请求,但是web的action是执行完毕才能看见结果而command里面是可以实时echo出结果的,所有一些小动作都可以写一个command,比如说请求一个api一万次,并且每次都显示出结果来。这样有了command就能很方便的满足上面的需求了
24天前 喜欢(0) 浏览(196) 评论(3)
Wiki
本教程基于主从服务器数据库同步完成之后,在 yii2 中配置如下,即可实现 Yii2.0 的数据库读写分离 1.打开我们的数据库配置文件common\config\main-local.php在db属性中做如下配置 'db' => [ 'class' => 'yii\db\Connection', // 配置主服务器 'dsn' => 'mysql:host=192.168.0.1;dbname=hyii2', 'username' => 'root', 'password' => 'root', 'charset' => 'utf8', // 配置从服务器 'slaveConfig' => [ 'username' => 'root', 'password' => 'root', 'attributes' => [ // use a smaller connection timeout PDO::ATTR_TIMEOUT => 10, ], 'charset' => 'utf8', ], // 配置从服务器组 'slaves' => [ ['dsn' => 'mysql:host=192.168.0.2;dbname=hyii2'], ], ], 如上配置就能实现yii2数据库读写分离的操作,很简单,只要一个配置就ok了,读写分离的功能由后台代码自动完成.调用者无须关心。 上面只是一个1主1从的配置,如果要一主多从,或者多主多从,参考此例以及官方文档即可完成。
25天前 喜欢(0) 浏览(263) 评论(3)
博客
我们在使用YII2的时候,经常会遇到需要定义config里各种参数,某些时候我们需要进行一些参数的修改。比如需要一个邮件发送功能,但是发送邮件的参数保存在数据库里面,所以我们就需要自定义发送邮件的各项参数了。 我们通常会进行以下配置 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', 'useFileTransport' => false, 'transport' => [ 'class' => 'Swift_SmtpTransport', 'host' => 'smtp.qq.com', 'username' => '888888@qq.com', 'password' => '8888', 'port' => '25', 'encryption' => 'tls', ], 'messageConfig'=>[ 'charset'=>'UTF-8', 'from'=>['88888@qq.com'=>'admin'] ], ], 获取到mailer对象如下,Yii::$app->mailer,YII2 的设计Yii::$app下的对象 刚好components里配置的对象, 通过上面的components的配置结构我们知道mailer对象是由yii\swiftmailer\Mailer类生成的,并且mailer还有一个transport对象由Swift_SmtpTransport类生产,通过以下操作 我们就得到了$mAiler实列: $mAiler->setTo($to);//收件人 $mAiler->setSubject($subject);//主题 $mAiler->setTextBody($text);//内容 $mAiler->send(); 我们也可以通过Yii::$app->mailer 拿到 mailer->对象,然后mailer->transport->host...等等进行变量的定义,但是 PHPstorm 没有对代码进行提示,所以不太喜欢,如果你不慌倒是可以使用。 如果需要临时改变以下db的属性你也可以有以下操作,至于效果嘛。。。我还没去试,估计是对当前一次的http请求生效吧
29天前 喜欢(0) 浏览(224) 评论(3)
博客
打开配置文件将下面代码添加到 components => [...]中(例:高级版默认配置在/common/config/main-local.php) 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', 'viewPath' => '@common/mail', 'useFileTransport' => false, //这里一定要改成false,不然邮件不会发送 'transport' => [ 'class' => 'Swift_SmtpTransport', 'host' => 'smtp.163.com', 'username' => 'xianan_huang@163.com', 'password' => '*********', //如果是163邮箱,此处要填授权码 'port' => '25', 'encryption' => 'tls', ], ], 在控制器中调用: $mail = \Yii::$app->mailer->compose() ->setFrom(['xianan_huang@163.com' => 'Yii 中文网']) ->setTo('391430388@qq.com') ->setSubject('邮件发送配置') //->setTextBody('Yii中文网教程真好 www.yii-china.com') //发布纯文字文本 ->setHtmlBody("<br>Yii中文网教程真好!www.yii-china.com") //发布可以带html标签的文本 ->send(); if($mail) echo 'success'; else echo 'fail'; 注意:很多报错原因都是因为163邮箱的smtp没有开,进入邮箱设置一下 默认不开启smtp要绑定手机之后才能开启
29天前 喜欢(2) 浏览(172) 评论(3)
Wiki
在页面中添加 Modal 组件 <?php use yii\bootstrap\Modal; Modal::begin([ 'id' => 'page-modal', 'header' => '<h5>这里是标题</h5>', 'toggleButton' => ['label' => 'click me'], ]); echo '这里是模态内容...'; Modal::end(); ?> 添加出发按钮 <?= Html::a('点击按钮', '#', [ 'class' => 'btn btn-success', 'data-toggle' => 'modal', 'data-target' => '#page-modal' //此处对应Modal组件中设置的id ]) ?>
1月前 喜欢(1) 浏览(199) 评论(3)
博客
有些旧版的cms是asp.net做的,而我们现在需要把用到它使用的数据库,那么问题来了,目前yii2支持sql只到2008,如何使用mssql连接更早版本的sql呢,这时候我我们就需要对yii2的mssql里的schema进行修改,使他支持2000的sql。开始我们的教程吧: 1.首先找到yii2解析mssql的scheme: vendor/yiisoft/yii2/db/mssql/Schema.php 2.更改解析代码: 1> 找到findColumns 的函数 大概在232行左右 2>替代解析 代码如下 : /** * Collects the metadata of table columns. * @param TableSchema $table the table metadata * @return boolean whether the table exists in the database */ protected function findColumns($table) { $pdo = $this->db->getSlavePdo(); $version = explode('.', $pdo->getAttribute(\PDO::ATTR_SERVER_VERSION)); //var_dump($version);exit; if (intval($version[0]<9)) { $sql = <<<SQL2000 SELECT column_name = a.name, is_identity = case when exists(SELECT 1 FROM sysobjects where xtype='PK' and parent_obj=a.id and name in ( SELECT name FROM sysindexes WHERE indid in( SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid))) then 1 else 0 end, data_type = case when b.name in ('ntext','datetime') then b.name when isnull(COLUMNPROPERTY(a.id,a.name,'Scale'),0)>0 then b.name + '(' + convert(varchar(20), COLUMNPROPERTY(a.id,a.name,'PRECISION')) + ','+convert(varchar(10), COLUMNPROPERTY(a.id,a.name,'Scale'))+')' else b.name + '(' + convert(varchar(20), COLUMNPROPERTY(a.id,a.name,'PRECISION')) + ')' end , is_nullable = case when a.isnullable=1 then 'Yes' else 'No' end, column_default = isnull(e.text,''), comment = isnull(g.[value],'') FROM syscolumns a left join systypes b on a.xusertype=b.xusertype inner join sysobjects d on a.id=d.id and d.xtype='U' and d.name<>'dtproperties' left join syscomments e on a.cdefault=e.id left join sysproperties g on a.id=g.id and a.colid=g.smallid left join sysproperties f on d.id=f.id and f.smallid=0 where d.name='{$table->fullName}' order by a.id,a.colorder SQL2000; } else { $columnsTableName = 'INFORMATION_SCHEMA.COLUMNS'; $whereSql = "[t1].[table_name] = '{$table->name}'"; if ($table->catalogName !== null) { $columnsTableName = "{$table->catalogName}.{$columnsTableName}"; $whereSql .= " AND [t1].[table_catalog] = '{$table->catalogName}'"; } if ($table->schemaName !== null) { $whereSql .= " AND [t1].[table_schema] = '{$table->schemaName}'"; } $columnsTableName = $this->quoteTableName($columnsTableName); $sql = <<<SQL SELECT [t1].[column_name], [t1].[is_nullable], [t1].[data_type], [t1].[column_default], COLUMNPROPERTY(OBJECT_ID([t1].[table_schema] + '.' + [t1].[table_name]), [t1].[column_name], 'IsIdentity') AS is_identity, CONVERT(VARCHAR, [t2].[value]) AS comment FROM {$columnsTableName} AS [t1] LEFT OUTER JOIN [sys].[extended_properties] AS [t2] ON [t2].[minor_id] = COLUMNPROPERTY(OBJECT_ID([t1].[TABLE_SCHEMA] + '.' + [t1].[TABLE_NAME]), [t1].[COLUMN_NAME], 'ColumnID') AND OBJECT_NAME([t2].[major_id]) = [t1].[table_name] AND [t2].[class] = 1 AND [t2].[class_desc] = 'OBJECT_OR_COLUMN' AND [t2].[name] = 'MS_Description' WHERE {$whereSql} SQL; } try { $columns = $this->db->createCommand($sql)->queryAll(); if (empty($columns)) { return false; } } catch (\Exception $e) { return false; } foreach ($columns as $column) { $column = $this->loadColumnSchema($column); foreach ($table->primaryKey as $primaryKey) { if (strcasecmp($column->name, $primaryKey) === 0) { $column->isPrimaryKey = true; break; } } if ($column->isPrimaryKey && $column->autoIncrement) { $table->sequenceName = ''; } $table->columns[$column->name] = $column; } return true; } 3.分析这段代码: 1>获取数据库的版本: $pdo = $this->db->getSlavePdo(); $version = explode('.', $pdo->getAttribute(\PDO::ATTR_SERVER_VERSION)); 2>根据版本解析: if (intval($version[0]<9)) { }else{} 3> 解析sql2000: $sql = <<<SQL2000 SELECT column_name = a.name, is_identity = case when exists(SELECT 1 FROM sysobjects where xtype='PK' and parent_obj=a.id and name in ( SELECT name FROM sysindexes WHERE indid in( SELECT indid FROM sysindexkeys WHERE id = a.id AND colid=a.colid))) then 1 else 0 end, data_type = case when b.name in ('ntext','datetime') then b.name when isnull(COLUMNPROPERTY(a.id,a.name,'Scale'),0)>0 then b.name + '(' + convert(varchar(20), COLUMNPROPERTY(a.id,a.name,'PRECISION')) + ','+convert(varchar(10), COLUMNPROPERTY(a.id,a.name,'Scale'))+')' else b.name + '(' + convert(varchar(20), COLUMNPROPERTY(a.id,a.name,'PRECISION')) + ')' end , is_nullable = case when a.isnullable=1 then 'Yes' else 'No' end, column_default = isnull(e.text,''), comment = isnull(g.[value],'') FROM syscolumns a left join systypes b on a.xusertype=b.xusertype inner join sysobjects d on a.id=d.id and d.xtype='U' and d.name<>'dtproperties' left join syscomments e on a.cdefault=e.id left join sysproperties g on a.id=g.id and a.colid=g.smallid left join sysproperties f on d.id=f.id and f.smallid=0 where d.name='{$table->fullName}' order by a.id,a.colorder SQL2000; 4> else 就是原来的解析方式 3.打开sql的数据库scheme的缓存,在db.php文件中添加 :'enableSchemaCache'=>true 既可以 这样我们就能使用sql2000数据库了,快去试试吧
3天前 喜欢(0) 浏览(37) 评论(2)
Wiki
如何在yii2表单中添加验证码?非常简单,只需要在yii2项目中做几个简单的配置就可以完成验证码的应用,yii2默认封装了许多扩展,验证码就是其中之一,那么下面就来为大家演示一下如何配置yii2的验证码 先看下验证码效果: 配置 首先,在要实用验证码的控制器(Controller)中添加下面的代码 public function actions() { return [ 'captcha' => [ 'class' => 'yii\captcha\CaptchaAction', 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, ], ]; } 然后在对应的form中添加rules规则,如下图
4天前 喜欢(0) 浏览(55) 评论(2)
问题
如图: 1. 先分类,按模块分类 2. 将文档放入属于得分类或子分类,文档有目录和章节 3. 文章和章节分成两个表,章节关联目录,文章关联分类 - 这样得想法如何呢?大神们是怎样实现得呢?求解!! -- 分类表 DROP TABLE IF EXISTS `jm_category`; CREATE TABLE IF NOT EXISTS `jm_category` ( `cateid` int unsigned not null AUTO_INCREMENT PRIMARY KEY COMMENT '分类id', `title` varchar(20) not null DEFAULT '' COMMENT '标题', `parentid` int unsigned not null DEFAULT '0' COMMENT '父级分类id', `createtime` int unsigned not null DEFAULT '0' COMMENT '创建时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '分类表'; -- 创建文档 DROP TABLE IF EXISTS `jm_doc`; CREATE TABLE IF NOT EXISTS `jm_doc` ( `docid` int unsigned not null AUTO_INCREMENT PRIMARY KEY COMMENT '文档id', `docname` varchar(20) not null DEFAULT '' COMMENT '文档名', `author` varchar(20) not null DEFAULT '' COMMENT '作者', `labelimg` varchar(200) not null DEFAULT '' COMMENT '文档标签图', `description` varchar(200) not null DEFAULT '' COMMENT '描述', `version` varchar(6) not null DEFAULT '' COMMENT '文档版本', `num` int unsigned not null DEFAULT '0' COMMENT '文档阅读量', `cateid` int unsigned not null DEFAULT '0' COMMENT '文档分类id', `createtime` int unsigned not null DEFAULT '0' COMMENT '创建时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '文档表'; -- 创建目录 DROP TABLE IF EXISTS `jm_catalog`; CREATE TABLE IF NOT EXISTS `jm_catalog` ( `catalogid` int unsigned not null AUTO_INCREMENT PRIMARY KEY COMMENT '目录id', `title` varchar(50) not null DEFAULT '' COMMENT '标题', `parentid` int unsigned not null DEFAULT '0' COMMENT '父级目录', `docid` int unsigned not null DEFAULT '0' COMMENT '文档id', `createtime` int unsigned not null DEFAULT '0' COMMENT '创建时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '文档目录表'; -- 章节表 DROP TABLE IF EXISTS `jm_chapter`; CREATE TABLE IF NOT EXISTS `jm_chapter` ( `chapterid` int unsigned not null AUTO_INCREMENT PRIMARY KEY COMMENT '章节id', `title` varchar(50) not null DEFAULT '' COMMENT '标题', `content` text COMMENT '内容', `order` int not null DEFAULT '0' COMMENT '排序', `status` enum('0', '1') DEFAULT '0' COMMENT '0-整理中,1-已完成', `num` int unsigned not null DEFAULT '0' COMMENT '阅读量', `catalogid` int unsigned not null DEFAULT '0' COMMENT '目录id', `createtime` int unsigned not null DEFAULT '0' COMMENT '创建时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '章节表'; -- 文章表 DROP TABLE IF EXISTS `jm_article`; CREATE TABLE IF NOT EXISTS `jm_article` ( `articleid` int unsigned not null AUTO_INCREMENT PRIMARY KEY COMMENT '文章id', `title` varchar(50) not null DEFAULT '' COMMENT '文章标题', `author` varchar(20) not null DEFAULT '' COMMENT '作者', `summary` varchar(250) not null DEFAULT '' COMMENT '文章摘要', `content` text COMMENT '内容', `labelimg` varchar(200) not null DEFAULT '' COMMENT '文章标签图', `status` enum('0', '1') not null DEFAULT '0' COMMENT '0-未发布,1-发布', `cateid` int unsigned not null DEFAULT '0' COMMENT '分类id', `createtime` int unsigned not null DEFAULT '0' COMMENT '创建时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '文章表'; 联系方式:957770846@qq.com
21天前 喜欢(0) 浏览(195) 评论(2)
博客
required : 必须值验证属性||CRequiredValidator 的别名, 确保了特性不为空. [['字段名1','字段名2'],required] //字段1 2 必填 [['字段名'],required,'requiredValue'=>'必填值','message'=>'提示信息']; email : 邮箱验证||CEmailValidator 的别名,确保了特性的值是一个有效的电邮地址. ['email', 'email']; match : 正则验证||CRegularExpressionValidator 的别名, 确保了特性匹配一个正则表达式. [['字段名'],'match','pattern'=>'正则表达式','message'=>'提示信息']; [['字段名'],'match','not'=>ture,'pattern'=>'正则表达式','message'=>'提示信息']; /*正则取反*/ url : 网址||CUrlValidator 的别名, 确保了特性是一个有效的路径. ['website', 'url', 'defaultScheme' => 'http']; captcha(验证码)||CCaptchaValidator 的别名,确保了特性的值等于 CAPTCHA 显示出来的验证码. ['verificationCode', 'captcha']; safe : 安全 ['description', 'safe']; compare :(比较) CCompareValidator 的别名, 确保了特性的值等于另一个特性或常量. ['repassword', 'compare', 'compareAttribute' => 'password','message'=>'两次输入的密码不一致!'], //compareValue:比较常量值 operator:比较操作符 ['age', 'compare', 'compareValue' => 30, 'operator' => '>=']; default : 默认值||CDefaultValueValidator 的别名, 为特性指派了一个默认值. ['age', 'default', 'value' => null]; exist : 存在||CExistValidator 的别名, 确保属性值存在于指定的数据表字段中. ['字段名', 'exist']; file : 文件||CFileValidator 的别名, 确保了特性包含了一个上传文件的名称. ['primaryImage', 'file', 'extensions' => ['png', 'jpg', 'gif'], 'maxSize' => 1024*1024*1024] filter : 滤镜||CFilterValidator 的别名, 使用一个filter转换属性. //'skipOnArray' => true 非必填 [['username', 'email'], 'filter', 'filter' => 'trim', 'skipOnArray' => true]; in : 范围||CRangeValidator 的别名, 确保了特性出现在一个预订的值列表里. ['level', 'in', 'range' => [1, 2, 3]]; unique : 唯一性||CUniqueValidator 的别名, 确保了特性在数据表字段中是唯一的. ['字段名', 'unique'] 补充:联合唯一索引rule规则 [ ['app_id', 'group_id'], 'unique', 'targetAttribute' => ['app_id', 'group_id'], 'message' => 'app_id和group_id已经被占用!' ], integer : 整数 ['age', 'integer']; number : 数字 ['salary', 'number']; double : 双精度浮点型 ['salary', 'double']; date : (日期) [['from', 'to'], 'date']; string : 字符串 ['username', 'string', 'length' => [4, 24]]; boolean : 是否为一个布尔值||CBooleanValidator 的别名 ['字段名', 'boolean', 'trueValue' => true, 'falseValue' => false, 'strict' => true]; image :是否为有效的图片文件 [ 'primaryImage', 'image', 'extensions' => 'png, jpg', 'minWidth' => 100, 'maxWidth' => 1000, 'minHeight' => 100, 'maxHeight' => 1000 ] each:遍历,ids 和 product_ids 是数字的集合 [['ids', 'product_ids'], 'each', 'rule' => ['integer']], 自定义rules: ['password', 'validatePassword'], /** * Validates the password. * This method serves as the inline validation for password. * * @param string $attribute the attribute currently being validated * @param array $params the additional name-value pairs given in the rule */ public function validatePassword($attribute, $params) { if (!$this->hasErrors()) { $user = $this->getUser(); if (!$user || !$user->validatePassword($this->password)) { $this->addError($attribute, '账号或者密码错误!'); } } }
29天前 喜欢(3) 浏览(185) 评论(2)
博客
基础 Gridview 插件被应用于数据呈现,它提供了很多功能,如浏览、排序、分页和数据过滤。 下面是一个简单的 Gridview 应用实例: <?= GridView::widget([ 'dataProvider' => $dataProvider, 'columns' => [ 'id', 'name', 'created_at:datetime', // ... ], ]) ?> 用法示例 1.在例头添加排序,在cloumns中加入以下代码 ['class' => 'yii\grid\SerialColumn'] 2.列表勾选框,在cloumns中加入以下代码 ['class' => 'yii\grid\CheckboxColumn'], 3.列数据快速格式化:时间戳转化为时间格式显示 'created_at:datetime', 4.显示关联表数据:前提是在model中有关联关系,例如:getAuthor() 'author.name', //获取关联表author的name的值 5.列表中显示图片:显示一张50*100的图片,label_img为图片地址 'label_img'=>[ 'label' => '标签图', 'format' => [ 'image', [ 'height' =>50, 'width' => 100 ] ], 'value' => function($model){ return $model->label_img; } ], 6.显示状态,且带过滤 [ 'attribute' => 'is_valid', 'label' => '发布状态', 'value' => function($model) { return $model->is_valid == 0 ? '未发布' : '发布'; }, 'filter' => [ 0 => '未发布', 1 => '发布' ] ], 7.显示带html标签的例值:正常情况下是过滤html标签的 [ 'attribute' => 'content', 'format' => 'raw', 'value' => function ($model) { return $model->content; }, ], 8.自定义按钮:{view} {update} {delete} 为默认,可以不填显示默认,也可以覆盖重新定义 [ 'class' => 'yii\grid\ActionColumn', 'template' => '{test} {view} {update} {delete}', 'header' => '操作', 'buttons' => [ 'test' => function ($url, $model, $key) { return Html::a('测试按钮', $url, ['data-method' => 'post','data-pjax'=>'0'] ); }, 'delete'=> function ($url, $model, $key){ return Html::a('删除', ['delete', 'id'=>$model->id],[ 'data-method'=>'post', //POST传值 'data-confirm' => '确定删除该项?', //添加确认框 ] ) ; } ], ], 9.修改列表顶部分页信息 //{begin}:当前列的第一个元素序号 //{end}:当前页的最后一个元素序号 //{count}:当前页的元素总数 //{totalCount}:所有元素总数 //{page}:当前页 //{pageCount}:总页数 <?= GridView::widget([ 'dataProvider' => $dataProvider, 'summary' => '第{begin}-{end}页,共计{totalCount}篇文章', ... 以上为gridview的一些基本操作,当然还有很多其他情景,但要活学活用,举一反三
1月前 喜欢(3) 浏览(233) 评论(2)
问题
需求: 我给用户发送一个链接,当用户点击之后链接失效,重点需求:如果用户不点击,则3分钟再次发送,5分钟再次发送,7分钟再次发送,还是不点击,那么就发送给客服。 在 yii2.0 框架中如何实现这个功能?给点思路也行
26天前 喜欢(0) 浏览(175) 评论(1)
博客
通过一个例子简单说一下Yii2 模型中的场景(scenario)应用,现在在 文章表里面有 title image content 三个的字段,当我创建一个文章 的时候,我想三个字段全部是必填项,但是你修改的时候,title content 两个字段是必填的, iamge 可以不填写。正常的情况下, [['title', 'content', 'image'], 'required',], 但是我们更改的时候 只需要 [['title', 'content'], 'required'], 就可以了,但是少了 image 字段,我们的表单就无法提交,这种问题怎么办啊?? 场景可以帮你解决这种问题,下面是一个简单的场景实例。 1.首先我们在 model 里面定义一下场景 类名必须是 scenarios() public function scenarios() { return [ 'create' => ['title', 'image', 'content'], 'update' => ['title', 'content'], ]; } 2.好的,如上所示,场景的基本设置我们就已经完成一部分了,下面我们设置 rules() ,调用场景我们用 on 关键字 [['title', 'content'], 'required', 'on' => ['create', 'update']], [['image'], 'required', 'on' => 'create'], [ ['image'], 'image', 'enableClientValidation' => true, 'maxSize' => 1024, 'message' => '您上传的文件过大', 'on' => ['create', 'update'] ], on 指定的就是场景,一个场景用字符串,多个场景用数组 3.好的,model 里面我们就设置完毕了 现在开始调用吧 Controller里面 $model = $this->findModel($id); $model->setScenario('update'); //或者 $model->scenario = 'update'; 都可以 上面的意思就是 调用 update 场景。
1天前 喜欢(0) 浏览(20) 评论(0)
博客
在处理一个文章内容时,需要在指定标签后面插入 指定内容 1.查找到指定位置(例如 我要在第三个标签<\p>后插入广告代码): /** * 选择到标签指定位置后 字节长度 * $find 标签名字 * $number 第几个标签位置 * $body 被查找的内容 * @param unknown $number * @param unknown $find * @param unknown $body * @return number * @author kangjy */ public function position($number,$find,$body) { //获取标签长度 $findLen = strlen($find); //初始化位置 $position =0; for ($number=1; $number<=3; $number++) { $position = stripos($body, $find, $position); //var_dump('第'.$number.'个 位置'.$position); $position += $findLen; // var_dump('第'.$number.'个 位置加寻找词的长度'); } return $position ; } 2.插入指定字符串代码 /** * 指定位置插入字符串 * @param $str 原字符串 * @param $i 插入位置 * @param $substr 插入字符串 * @return string 处理后的字符串 * @author kangjy */ public function insertToStr($str, $i,$substr){ //指定插入位置前的字符串 $startstr=""; for($j=0; $j<$i; $j++){ $startstr .= $str[$j]; } //指定插入位置后的字符串 $laststr=""; for ($j=$i; $j<strlen($str); $j++){ $laststr .= $str[$j]; } //将插入位置前,要插入的,插入位置后三个字符串拼接起来 $str = $startstr . $substr . $laststr; //返回结果 return $str; } 这样就可以了
3天前 喜欢(0) 浏览(24) 评论(0)
博客
如果做API的话,如何使别人再调用你的接口时能够有一个统一标准的json或者jsonp格式,然而 json响应的格式和内容,每个人的约定都是有差异的,所以我们必须再数据出去之前做一定的处理。 1.首先我们需要初始化去调用beforeSend,因为我们需要对beforesend做一些处理,以下是init初始化处理代码: /** * (non-PHPdoc) * @see \yii\base\Object::init() */ public function init() { parent::init(); //绑定beforeSend事件,更改数据输出格式 Yii::$app->getResponse()->on(Response::EVENT_BEFORE_SEND, [$this, 'beforeSend']); } 2.然后我们就需要对beforesend进行处理,处理点有下面几个重点: 1>更改数据输出格式 2>默认情况下输出Json数据 3>如果客户端请求时有传递$_GET['callback']参数,输出Jsonp格式 4>请求正确时数据为 {"success":true,"data":{...}} 5>请求错误时数据为 {"success":false,"data":{"name":"Not Found","message":"页面未找到。","code":0,"status":404}} 6>具体代码如下: /** * 更改数据输出格式 * 默认情况下输出Json数据 * 如果客户端请求时有传递$_GET['callback']参数,输入Jsonp格式 * 请求正确时数据为 {"success":true,"data":{...}} * 请求错误时数据为 {"success":false,"data":{"name":"Not Found","message":"页面未找到。","code":0,"status":404}} * @param \yii\base\Event $event */ public function beforeSend($event) { /* @var $response \yii\web\Response */ $response = $event->sender; $isSuccessful = $response->isSuccessful; if ($response->statusCode>=400) { //异常处理 if (true && $exception = Yii::$app->getErrorHandler()->exception) { $response->data = $this->convertExceptionToArray($exception); } //Model出错了 if ($response->statusCode==422) { $messages=[]; foreach ($response->data as $v) { $messages[] = $v['message']; } //请求错误时数据为 {"success":false,"data":{"name":"Not Found","message":"页面未找到。","code":0,"status":404}} $response->data = [ 'name'=> 'valide error', 'message'=> implode(" ", $messages), 'info'=>$response->data ]; } $response->statusCode = 200; } elseif ($response->statusCode>=300) { $response->statusCode = 200; $response->data = $this->convertExceptionToArray(new ForbiddenHttpException(Yii::t('yii', 'Login Required'))); } //请求正确时数据为 {"success":true,"data":{...}} $response->data = [ 'success' => $isSuccessful, 'data' => $response->data, ]; $response->format = Response::FORMAT_JSON; \Yii::$app->getResponse()->getHeaders()->set('Access-Control-Allow-Origin', '*'); \Yii::$app->getResponse()->getHeaders()->set('Access-Control-Allow-Credentials', 'true'); //jsonp 格式输出 if (isset($_GET['callback'])) { $response->format = Response::FORMAT_JSONP; $response->data = [ 'callback' => $_GET['callback'], 'data'=>$response->data, ]; } } 3.针对请求可能会发生一些异常,同样我们也需要对异常进行一些标准化处理,将异常转换为array输出,具体代码如下: /** * 将异常转换为array输出 * @see \yii\web\ErrorHandle * @param \Exception $exception * @return multitype:string NULL Ambigous <string, \yii\base\string> \yii\web\integer \yii\db\array multitype:string NULL Ambigous <string, \yii\base\string> \yii\web\integer \yii\db\array */ protected function convertExceptionToArray($exception) { if (!YII_DEBUG && !$exception instanceof UserException && !$exception instanceof HttpException) { $exception = new HttpException(500, Yii::t('yii', 'An internal server error occurred.')); } $array = [ 'name' => ($exception instanceof Exception || $exception instanceof ErrorException) ? $exception->getName() : 'Exception', 'message' => $exception->getMessage(), 'code' => $exception->getCode(), ]; if ($exception instanceof HttpException) { $array['status'] = $exception->statusCode; } if (YII_DEBUG) { $array['type'] = get_class($exception); if (!$exception instanceof UserException) { $array['file'] = $exception->getFile(); $array['line'] = $exception->getLine(); $array['stack-trace'] = explode("\n", $exception->getTraceAsString()); if ($exception instanceof \yii\db\Exception) { $array['error-info'] = $exception->errorInfo; } } } if (($prev = $exception->getPrevious()) !== null) { $array['previous'] = $this->convertExceptionToArray($prev); } return $array; } 好了,这样我们就有了标准同一个的api接口返回数据格式了,在调用接口的人员也不用为了格式不统一感到烦恼
3天前 喜欢(1) 浏览(30) 评论(0)
博客
yii2是一个快速开发的框架,其中gii扩展不得不说是一个很大的助力,通过gii自动生成代码,把一些通用的代码交给程序去生成,很大程度上减少开发者的时间成本。但gii也有一些弊端,那就是生成的代码是yii2自带的模板,每次生成的代码并不是我们想要的,因而每次都要去对应的做调整。 那么如何才能让程序生成我们想要的代码呢?没错,yii2的gii扩展是支持自定义模板的,通过自定义模板我们就可以让gii生成我们想要的代码,又一次节约了去修改生成模板的时间成本。 配置 gii生成器所用到的模板文件位于目录 vendor\yiisoft\yii2-gii\generators\crud\default,我们既然要自定义模板,最好是在原有的模板基础下做调整。 1.复制一份模板,拷贝default目录,放在任意位置,此处我们放置在根目录 /backend/giitpl/crud 中。 2.修改模板(本文为教程不做细说,此处自行修改即可) 3.打开配置文件 /backend/config/main-local.php 修改$config['modules']['gii']的配置(如下): $config['modules']['gii'] = [ 'class' => 'yii\gii\Module', 'allowedIPs' => ['127.0.0.1', '::1'], 'generators' => [ 'crud' => [ //生成器名称 'class' => 'yii\gii\generators\crud\Generator', 'templates' => [ //设置我们自己的模板 //模板名 => 模板路径 'myCrud' => '@backend/giitpl/crud/default', ] ] ], ]; 4.通过gii生成代码,打开gii界面,使用crud generator生成代码(注:此处配置要修改code template模板) 选择我们自定义的模板,然后点击生成,那么gii自定义的模板代码就生成好了。 总结 通过自定义gii模板,我们能够更加灵活快速的完成需要的功能,把许多相似度高,应用场景多,功能类似(比如:列表页,详情页等)的代码做成gii的模板,通过程序去生成。还是那句话yii2就是一个快速开发的框架。
8天前 喜欢(0) 浏览(57) 评论(0)
博客
Gii 这个扩展无疑是 yii2 快速开发的一大助力,通过使用gii生成代码很大程序上节约了开发的时间成本,那么如何使用gii这个组件呢?本文为你们简单介绍一下yii2中gii的一些常用功能。 生成模型(Model) 在数据库新建一张test的测试表 CREATE TABLE `test` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID', `name` varchar(255) DEFAULT NULL COMMENT '名称', `desc` varchar(255) DEFAULT NULL COMMENT '描述', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 1.打开gii的界面 /index.php?r=gii或者 /gii(url美化之后) 2.创建Model 首先,点击Model generator下面的start按钮,进入model生成界面,输入数据表名test,输入model class(一般会自动生成一个,也可以自定义model class名称) 然后,点击下方的preview,会列出要生成的模型 最后,点击generate生成model文件,如下提示测生成成功 生成CRUD 同样,点击CRUD Generator,去创建CRUD也就是增删改查的操作界面及功能,输入对应的参数(注:view path 不填,即生成在默认的位置) 然后,点击preview,查看要生成的文件列表(注:如果已经存在对应的控制会显示下方diff,可以选择覆盖或者保留) 最后点击Generate生成相应的CRUD文件,然后就可以查看对应的页面了,如此简单就完成了一个数据表的增删改成
11天前 喜欢(0) 浏览(94) 评论(0)
Wiki
1.视图页面直接加载 $css = <<<CSS p {text-indent:5em;} div{width: 500px;} CSS; $this->registerCss($css,['type'=>'text/css'],'test'); $js = <<<JS // console.log('sss'); JS; $this->registerJs($js); 视图页面直接加载css,js文件 $this->registerJsFile('@web/assets/js/site.js'); $this->registerCssFile('@web/assets/css/site.css');
12天前 喜欢(0) 浏览(92) 评论(0)
社区公告
[公告] Yii中文网为优化用户体验进行大版本升级,老版网站会维持一段时间,可以点击顶部"旧版"链接访问旧版网站。
沟通交流

:492175201(技术1群)

:183620600(技术2群)

:291010569(技术3群)