三:Database And Gii

最后更新于:2022-04-01 23:22:32

> 原文出处:https://jellybool.com/post/programming-with-yii2-working-with-the-database-and-gii 上一篇文章我们理了一下Yii2的`MVC`,`Forms`和`Layouts`,这篇文章就直接按照约定来说说Yii2与数据库相关的一些事情,如果你觉得不够的话,不急,更具体的用法我会在后续的教程给出,并且这里也会介绍Yii2的代码生成工具:强大的`Gii`。 你可以直接到Github下载项目源码:[](https://github.com/JellyBool/helloYii)[https://github.com/JellyBool/helloYii](https://github.com/JellyBool/helloYii),这样你就可以直接跟上我的进度了,每一次我写完一个教程,我都会将代码push到Github,所以,你想偷懒的话,这是一个不错的方法。 接着上一篇文章,我们的初衷还是没有改变:创建一个可以发表状态`(status)`的web小应用,你可以看成是QQ空间的说说的mini版,只不过之前我们没有将数据存在数据库里面而已。 ## 创建一个数据库 ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb26601e.png) 由于我平时开发基本都是使用Mysql,而且数据库管理工具我比较喜欢Sequel Pro,所以,我就直接在[Sequel Pro](http://www.sequelpro.com/)里面创建一个`hello`的数据库。当然,你也可以直接用命令行来创建数据库,大概是这样的: ~~~ CREATE DATABASE hello; ~~~ 有了数据库之后,我们就可以将我们的Yii应用与数据库进行连接了,Yii2的数据库配置文件位于`/config/db.php`中,我们可以打开它来进行相应的配置,请注意根据自己的实际情况进行相应的修改: ~~~ 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=hello', 'username' => 'root', 'password' => 'password', 'charset' => 'utf8', ]; ~~~ ## 创建Migration 这里直接使用了`migration`这个单词,其实我不知道该翻译成什么才比较确切;所以本文就直接使用`migration`这个单词了,如果你知道有特别贴切的翻译,请大声对我说。其实`migration`的最大目的可能就是创建数据表了,但是我们为什么还要使用`migration`了?这可能都是受到`Rails`大法的影响,因为这样的好处其实很多,`migration`不仅可以让开发人员动态创建和更新一个数据库表的schema,还可以应对多个服务器的时候环境不同的问题,直接就避免导入sql文件的各种坑。 至于在代码中我们该怎么命名我们的数据表,我比较喜欢的是直接跟Model一样,如果是单复数问题也无所谓,这看个人,所以这里,我会选择创建一个`status`表,iTerm命令行执行: ~~~ cd Desktop/helloYii/ ./yii migrate/create create_status_table ~~~ 过程当中会询问是否创建`migration`,果断`yes`,然后完成之后大概是这样的: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb2b92e2.png) 这条命令会在项目目录下创建一个`migrations/`目录,里面就有刚刚我们创建的migration文件,名字大概是这样的:`m150804_035107_create_status_table.php`,然后我们就可以打开这个文件来一睹芳容了: ~~~ db->driverName === 'mysql') { $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; } $this->createTable('{{%status}}', [ 'id' => Schema::TYPE_PK, 'message' => Schema::TYPE_TEXT.' NOT NULL DEFAULT ""', 'permissions' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0', 'created_at' => Schema::TYPE_INTEGER . ' NOT NULL', 'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL', ], $tableOptions); } public function down() { $this->dropTable('{{%status}}'); } ~~~ 这里我们的`status`会有5个字段,`id`为主键,`message`和`permissions`就是上一篇我们的文本输入框输入的文本内容和下拉选择框的内容;这里我们还要两个`created_at`和`updated_at`字段,呃,你可以说我被Laravel洗脑了。 `down()`方法与`up()`相对应,用来删除数据表的,我希望你不会用到。 更多详细内容参考这里: [](http://www.yiiframework.com/doc-2.0/guide-db-migrations.html)[http://www.yiiframework.com/doc-2.0/guide-db-migrations.html](http://www.yiiframework.com/doc-2.0/guide-db-migrations.html) 有了表的`schema`之后,我们就可以来执行我们的migrate命令了,命令行执行: ~~~ ./yii migrate/up ~~~ 过程中还是果断`yes`,然后完成之后你就可以到到`hello`数据库去看`status`表了: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb417f75.png) 这里你还会看到一个`migration`的表,这是Yii2的migrate自动生成了,它是用来管理我们自己创建的`migration`(这里指数据表),你可以不用关心它。 使用Yii2的migrate创建完数据表之后,我们下一步就来上手一下Yii2的代码生成工具Gii了,因为我们会通过Gii来生成我们的Model和Controller等文件。 ## 使用Gii Gii作为Yii的一大特性,很多人喜欢Yii可能就是因为这个,据说底层代码写得很棒,不过我还没有仔细看过源码。 首先我们来使用Gii来为每一个数据表生成一个Model,这里也就是生成Status这个模型。 怎么进入Gii的使用面板呢?直接在浏览器地址栏输入`http://localhost:8999/gii` 访问就可以了。大概是长这个样子: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb46a3f1.png) 点击**Model Generator**的按钮,然后在`Table Name`输入框填入表名:`status` ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb4c64f8.png) 点击下方**Preview** 按钮,就可以看到Yii即将帮你生成的文件了`models/Status.php`,这里需要注意的一个地方是。因为在上一篇文章中我们手动创建了一个Status模型,所以这里请确定你将`Overwrite`这个选择框的小勾勾打上: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb523c6f.png) 然后点击**Generate**按钮,生成的结果是这样的: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb562985.png) 这时候打开`models/Status.php`,你会看到Yii会根据我们的数据表生成的验证规则和表单属性: ~~~ 'ID', 'message' => 'Message', 'permissions' => 'Permissions', 'created_at' => 'Created At', 'updated_at' => 'Updated At', ]; } } ~~~ Status模型生成好之后,该为它生成相应的视图和控制器了,这时候需要使用到的是Gii 的`CRUD Generator`了,即:`http://localhost:8999/gii/crud` ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb5954ae.png) 在这个页面,分别填上对应的数据: ~~~ Model Class : app\models\Status Search Model Class : app\models\StatusSearch Controller Class : app\controllers\StatusController View Path : 可以直接留空,默认就是 app/views/ControllerID ~~~ 然后点击**Preview**预览一下,这里还是需要把`overwrite`勾选上,因为我们上一节也创建了两个同名的视图文件`(create.php 和 view.php)`: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb609470.png) 最后还是点击生成,你会看到类似下面这个图片的内容: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb6552ae.png) 到了这里,我们基本上可以感觉到Gii的强大了,生成代码简直都不算事。这时候如果我们访问`http://localhost:8999/status` ,你会看到一个默认的Status的CRUD页面,因为我们的数据库里面还没有任何数据,所以这里看到的都是空的: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb69f9cc.png) 如果你还记得我们在上一篇在导航栏创建的`create`导航,点击`create`,你就会看到类似下面这个页面一样的内容: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb6e6d12.png) 到这里,有没有觉得Gii实在太厉害了!要是上一篇我们直接用Gii来生成这些代码,那开发效率实在不是一般高。 ## 与上一篇的结合 虽然Gii足够强大为我们生成了很多代码,但是现在有一小部分代码并不符合我们的要求,我们不用这么复杂。所以下面先来把代码先过过,以便用于满足我们自己的要求。 首先是对创建Status的表单进行改造,我们并不希望用户需要输入`created` 和`updated`这两个字段,所以注释掉`/views/Status/_form.php`中的下面的代码: ~~~ field($model, 'created_at')->textInput() ?> field($model, 'updated_at')->textInput() ?> ~~~ 然后`permissions`字段输入我们希望这是一个下拉选择框,还是在同一个文件中修改: ~~~ field($model, 'permissions')->dropDownList($model->getPermissions(), ['prompt'=>'- Choose Your Permissions -']) ?> ~~~ 我们把原来`permissions`的`textInput`换成了上面的`dropDownList`,这里的`dropDownList`使用到`getPermissions()`这个方法,但是由于刚刚在生成Status这个模型的时候我们覆盖了原谅的Status,所以我们还是需要加上`getPermissions()`这个方法: ~~~ const PERMISSIONS_PRIVATE = 10; const PERMISSIONS_PUBLIC = 20; // other codes ... public function getPermissions() { return array (self::PERMISSIONS_PRIVATE=>'Private',self::PERMISSIONS_PUBLIC=>'Public'); } public function getPermissionsLabel($permissions) { if ($permissions==self::PERMISSIONS_PUBLIC) { return 'Public'; } else { return 'Private'; } } ~~~ 像上一篇提到的一样,我们将这些代码又写到了`Status.php`这里。然后刷新一下:`http://localhost:8999/status/create` 到这里,我们的表单改造旧完成了,跟我们之前的长得差不多了。但是这还没有完,因为我们还需要对我们的`controllers/StatusController.php`做一些些小改动,主要是在`actionCreate`的改动: ~~~ public function actionCreate() { $model = new Status(); if ($model->load(Yii::$app->request->post())) { $model->created_at = time(); $model->updated_at = time(); if ($model->save()) { return $this->redirect(['view', 'id' => $model->id]); } } return $this->render('create', [ 'model' => $model, ]); } ~~~ 在这里,我们添加下面这两行来保障我们在插入数据的时候,`created_at`和`updated_at`不为空。 ~~~ $model->created_at = time(); $model->updated_at = time(); ~~~ 这里也是根据`$model->load(Yii::$app->request->post())`判断是否有post数据过来,然后如果数据成功保存到数据库,我们就使用`return $this->redirect(['view', 'id' => $model->id])`重定向到`view`方法`(controllers/StatusController.php的actionView方法)`。我们填上一些数据,然后创建一个status试试,不出意外你会看到这个可爱的页面: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb745ed7.png) 终于到了这里了,我们现在再来修改一下我们的导航,在Status这个下来菜单下,我们增加一个菜单view,修改`views/layouts/main.php`文件的`Nav::widget`部分: ~~~ [ 'label' => 'Status', 'items' => [ ['label' => 'View', 'url' => ['/status/index']], ['label' => 'Create', 'url' => ['/status/create']], ], ], ~~~ 就直接在Status的items里面加一行:`['label' => 'View', 'url' => ['/status/index']]`,然后我们的导航栏就是这样的了: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb78d804.png) 点击下拉菜单的View,然后我们就会来到:`http://localhost:8999/status/index`,这里我们可以看到下面的页面了: ![替代文字](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-15_55cf2cb7d419a.png) 这个视图文件位于`views/status/index.php`,如果你想修改一下,你可以直接修改这个文件。 啊,感觉这一篇文章的路走得好长,不过其实真正编码的时间并不过,真正可能也就几分钟而已,我们实现了对数据库的一些基本操作和领略Gii的强大。这一篇就先写到这里了,下一篇打算会写一点关于用户注册和登录的基本功能。
';