Home  >  Article  >  php教程  >  Yii2的相关学习记录,前后台分离及migrate使用(七) - 漫游云巅

Yii2的相关学习记录,前后台分离及migrate使用(七) - 漫游云巅

WBOY
WBOYOriginal
2016-05-20 10:14:541144browse

最近一直忙其它的(其实是懒!),将《深入理解Yii2》看了一遍,一些当初没明白的稍微明了了点,然后又看yii2的图片上传等处理、富文本、restful什么的,但由于没进行到这里,只看也不管用啊,所以还是按照步骤一步步来,先说说前后台分离。(其实普通的内容管理站点用不着下面所说的彻底分离什么的,看看也无妨)

个人感觉前后台的情况有这么几种,首先是前后台是否是用一个验证体系,其次是前后台是否共用一个数据表。一般来说下面三种比较常用吧:

A、共用一个验证体系和一个数据表。

B、两个验证体系和共用一个数据表。

C、两个验证体系和两个数据表。

Yii2高级版里面默认是A类型,即数据表一样,且一边登录/登出了,另一边也同样登录/登出,感觉这种结构比较适用于论坛这种,管理员也需要有与会员一样发帖回帖等功能,表字段也基本一致,(个人这样认为,毕竟接触的不多,网上也搜过不同的后台构建的话题,但是很少有详细讨论的),这种可以通过字段、权限等来区分前后台。而我们将要做的是C类型,像是一些电商网站,后台的管理员和前台的会员功能就相差太大了,且表字段差别也大,所以验证体系不一样,而且放两个数据表比较好。至于B类型算是C类型的简化版,C如果会设置的话,B也同理。

那我们先建立一个admin表,用来存放管理员数据,而会员仍然用原有的user表,这里用yii的migrate来创建,在Yii2初始化章节中有提到过,这里稍微详细说下:

1、yii2版本2.07以前用命令,即可在console/migrations目录下创建一个php文件,然后在此文件下编写创建表语句等等就可以了。

yii migrate/create admin

2、yii2版本2.07后,增加了更细致的分类,例如我已经创建了admin表,但少了一个status字段,那我可以直接用下面命令便会生成只增加字段的文件

yii migrate/create add_column_to_admin --fields=status:<span style="color: #0000ff;">int</span>(<span style="color: #800080;">10</span>):nontNull

生成:

<span style="color: #000000;">php
</span><span style="color: #0000ff;">use</span><span style="color: #000000;"> yii\db\Migration;

</span><span style="color: #0000ff;">class</span> m160501_053640_add_column_to_admin <span style="color: #0000ff;">extends</span><span style="color: #000000;"> Migration
{
    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> up()
    {
        </span><span style="color: #800080;">$this</span>->addColumn('admin', 'status', <span style="color: #800080;">$this</span>->int(10)-><span style="color: #000000;">nontNull());
    }

    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> down()
    {
        </span><span style="color: #800080;">$this</span>->dropColumn('admin', 'status'<span style="color: #000000;">);
    }
}</span>

具体为什么会这样,我们看下原代码,在vendor/yiisoft/yii2/console/BaseMigrateController.php文件的actionCreate方法中:

...<span style="color: #000000;">
} </span><span style="color: #0000ff;">elseif</span> (<span style="color: #008080;">preg_match</span>('/^add_(.+)_to_(.+)$/', <span style="color: #800080;">$name</span>, <span style="color: #800080;">$matches</span><span style="color: #000000;">)) {
    </span><span style="color: #800080;">$content</span> = <span style="color: #800080;">$this</span>->renderFile(Yii::getAlias(<span style="color: #800080;">$this</span>->generatorTemplateFiles['add_column']),<span style="color: #000000;"> [
        </span>'className' => <span style="color: #800080;">$className</span>,
        'table' => mb_strtolower(<span style="color: #800080;">$matches</span>[2], Yii::<span style="color: #800080;">$app</span>->charset),
        'fields' => <span style="color: #800080;">$this</span>-><span style="color: #000000;">fields
    ]);
}
</span>...

我们可以看到,这里是正则匹配add_xxx_to_xxx来确定具体是指向哪个模板,从而生成不同的样式。所以根据migrate/create后面的参数总共匹配这几种样式:

1、create_junction_表名_and_表名,用来创建联结表

2、add_xxx_to_表名,用来增加字段(可以用--fields样式指定一个字段,否则生成空的,需要自己写,当然也可以改模板添加个注释示例)

3、drop_xxx_from_表名,用来删除字段(同上)

4、create_表名,用来创建表

5、drop_表名,用来删除表

 注:可以直接在控制台用yii help migrate来查看更多的用法

模板文件可以在vendor/yiisoft/yii2/views中找到对应的,如果想更改模板,让其更适合自己的操作,可以这样:

在console文件中新建views文件夹,将上方的你想修改的模板复制到这里来修改,然后再console/config/main.php中修改

<span style="color: #0000ff;">return</span><span style="color: #000000;"> [
    </span><span style="color: #008000;">//</span><span style="color: #008000;">修改migration模板</span>
    'controllerMap' =><span style="color: #000000;"> [
        </span>'migrate' =><span style="color: #000000;"> [
            </span>'class' => 'yii\console\controllers\MigrateController',
            'templateFile'=>'@yii/views/migration.php',<span style="color: #008000;">//</span><span style="color: #008000;">默认模板,2.07后应该很少用了</span>
            'generatorTemplateFiles' =><span style="color: #000000;"> [
                </span>'create_table' => '@console/views/createTableMigration.php',<span style="color: #008000;">//</span><span style="color: #008000;">修改的</span>
                'drop_table' => '@yii/views/dropTableMigration.php',<span style="color: #008000;">//</span><span style="color: #008000;">未修改的</span>
                'add_column' => '@console/views/addColumnMigration.php',<span style="color: #008000;">//</span><span style="color: #008000;">修改的</span>
                'drop_column' => '@console/views/dropColumnMigration.php',<span style="color: #008000;">//</span><span style="color: #008000;">修改的</span>
                'create_junction' => '@yii/views/createJunctionMigration.php'<span style="color: #008000;">//</span><span style="color: #008000;">未修改的</span>
            ],<span style="color: #000000;">
        ]</span>,<span style="color: #000000;">
    ]</span>,<span style="color: #000000;">
];</span>

值得注意的是generatorTemplateFiles配置中,必须将这5个都写全了,如果不修改,则写原来的路径,原来的路径可在vendor/yiisoft/yii2/console/MigrateController.php中查看,否则你用到没写的那个命令模板的时候就会报错。

至于如何写具体的创建表、添加字段等语句,其实也有版本不同(2.06新写法)的两种写法,这里就不要看中文版的没有更新的yii2指南了,直接看英文更新的,点这里,里面包含上面说的内容加具体的写法。当初费了很多时间google搜索、顺着源码看才搞明白上面说的原理,后来一看,在人家英文版里都写了,悲剧,而且最近我在Yii英文官网api文档搜索任何关键字都不出现结果了,不知道是这边的问题还是官网问题,只能对照着中文指南和英文指南看到底是对应的哪一块。所以说如果英语更好点就好了,直接看英文文档。

目前自己修改了create_table时加表注释、段注释(这个搜索及查源码没找到类似->comment的写法,可能是为了兼容其它数据库,所以只能拼接,而写段注释的好处是,gii 生成model时attributeLabels方法可以直接根据注释来显示对应的中文名字),add_column和drop_column模板增加一个示例注释,方便忘了用法时参照注释的示例来写,而且这样就不用加--fileds参数了。呃,这里贴一下自己的模板和最终应该建立的admin表的语句吧:

模板createTableMigration.php:

<span style="color: #000000;">php
</span><span style="color: #008000;">/*</span><span style="color: #008000;">*
 * This view is used by console/controllers/MigrateController.php
 * The following variables are available in this view:
 </span><span style="color: #008000;">*/</span>
<span style="color: #008000;">/*</span><span style="color: #008000;"> @var $className string the new migration class name </span><span style="color: #008000;">*/</span>
<span style="color: #008000;">/*</span><span style="color: #008000;"> @var $table string the name table </span><span style="color: #008000;">*/</span>
<span style="color: #008000;">/*</span><span style="color: #008000;"> @var $fields array the fields </span><span style="color: #008000;">*/</span>

<span style="color: #0000ff;">echo</span> "<?php \n"<span style="color: #000000;">;
?>

<span style="color: #0000ff;">use</span><span style="color: #000000;"> yii\db\Migration;

</span><span style="color: #0000ff;">class</span> = <span style="color: #800080;">$className</span> ?> <span style="color: #0000ff;">extends</span><span style="color: #000000;"> Migration
{
    </span><span style="color: #0000ff;">const</span> TBL_NAME = '{{%=$table?>}}'<span style="color: #000000;">;
    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> up()
    {
        </span><span style="color: #800080;">$tableOptions</span> = <span style="color: #0000ff;">null</span><span style="color: #000000;">;
        </span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$this</span>->db->driverName === 'mysql'<span style="color: #000000;">) {
            </span><span style="color: #800080;">$tableOptions</span> = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB COMMENT="填写表注释"'<span style="color: #000000;">;
        }
        </span><span style="color: #800080;">$this</span>->createTable(self::TBL_NAME,<span style="color: #000000;"> [
</span><?php <span style="color: #0000ff;">foreach (<span style="color: #800080;">$fields</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$field</span>): ?>
<?php <span style="color: #0000ff;">if (<span style="color: #800080;">$field</span> == <span style="color: #008080;">end</span>(<span style="color: #800080;">$fields</span>)): ?>
            '= $field['property'] ?>' => <span style="color: #800080;">$this</span>->= <span style="color: #800080;">$field</span>['decorators'].".\" COMMENT '填写段注释'\"" . "\n"?>
<?php <span style="color: #0000ff;">else: ?>
            '= $field['property'] ?>' => <span style="color: #800080;">$this</span>->= <span style="color: #800080;">$field</span>['decorators'].".\" COMMENT '填写段注释'\"" . ",\n"?>
<?php <span style="color: #0000ff;">endif; ?>
<?php <span style="color: #0000ff;">endforeach; ?><span style="color: #000000;">
        ]</span>,<span style="color: #800080;">$tableOptions</span><span style="color: #000000;">);
    }

    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> down()
    {
        </span><span style="color: #800080;">$this</span>->dropTable(self::<span style="color: #000000;">TBL_NAME);
    }
}</span>
createTableMigration.php

 具体语句m160326_133655_create_admin.php:

<span style="color: #000000;">php

</span><span style="color: #0000ff;">use</span><span style="color: #000000;"> yii\db\Migration;

</span><span style="color: #0000ff;">class</span> m160427_133556_create_admin <span style="color: #0000ff;">extends</span><span style="color: #000000;"> Migration
{
    </span><span style="color: #0000ff;">const</span> TBL_NAME = '{{%admin}}'<span style="color: #000000;">;
    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> up()
    {
        </span><span style="color: #800080;">$tableOptions</span> = <span style="color: #0000ff;">null</span><span style="color: #000000;">;
        </span><span style="color: #0000ff;">if</span> (<span style="color: #800080;">$this</span>->db->driverName === 'mysql'<span style="color: #000000;">) {
            </span><span style="color: #800080;">$tableOptions</span> = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB COMMENT="后台管理员表"'<span style="color: #000000;">;
        }
        </span><span style="color: #800080;">$this</span>->createTable(self::TBL_NAME,<span style="color: #000000;"> [
             </span>'id' => <span style="color: #800080;">$this</span>->primaryKey(),
            'username'=><span style="color: #800080;">$this</span>-><span style="color: #0000ff;">string</span>()->notNull()->unique()." COMMENT '用户名'",
            'auth_key'=><span style="color: #800080;">$this</span>-><span style="color: #0000ff;">string</span>(32)->notNull()." COMMENT '认证Key'",
            'password_hash'=><span style="color: #800080;">$this</span>-><span style="color: #0000ff;">string</span>()->notNull()." COMMENT '密码'",
            'password_reset_token'=><span style="color: #800080;">$this</span>-><span style="color: #0000ff;">string</span>()->unique()." COMMENT '密码重置Token'",
            'email'=><span style="color: #800080;">$this</span>-><span style="color: #0000ff;">string</span>()->notNull()->unique()." COMMENT '邮箱'",
            'status'=><span style="color: #800080;">$this</span>->smallInteger()->notNull()->defaultValue(10)." COMMENT '状态'",
            'created_at' => <span style="color: #800080;">$this</span>-><span style="color: #0000ff;">integer</span>()->notNull()." COMMENT '创建时间'",
            'updated_at' => <span style="color: #800080;">$this</span>-><span style="color: #0000ff;">integer</span>()->notNull()." COMMENT '更新时间'",<span style="color: #000000;">
        ]</span>,<span style="color: #800080;">$tableOptions</span><span style="color: #000000;">);
    }

    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> down()
    {
        </span><span style="color: #800080;">$this</span>->dropTable(self::<span style="color: #000000;">TBL_NAME);
    }
}</span>
xxx_create_admin.php

继续运行下述命令行代码,即可生成admin表,由于只是做演示,所以admin和user表基本一样,不要在意这些细节。

yii migrate

 好了,生成两个表后,我们就需要将前台登录和后台登陆彻底分开了:

1、前台修改:由于已经不公用了,所以先把公用的common/models中的User.php和LoginForm.php移动到frontend/models中去,顺便将这两个文件的命名空间改为以frontend开头,将整个前台文件看一遍,把所有涉及到这两个common文件命名空间的需要都改为前台自己的命名空间。

2、后台修改:同样需要在backend/models中有这两个文件Admin.php和LoginForm.php,可以使用Gii生成(需要注意要继承IdentityInterface,实现此接口内的方法以及参照User.php来实现相关登录注册方法),也可以直接复制同样上面的两个文件(需要将User.php改名为Admin.php,且注意user表和admin表字段名称或个数是否一致,不一致则需要在Admin.php中修改)。由于我们原先创建过后台的GRUD,所以这里改动挺多的(searchModel,controller,view都需要改成admin的),建议对照着Gii生成的文件预览来改。哎,如果实际要前后台分离,本章应该放在第五章节的前面,那后台就不需要改这么多了。

现在可以登录前后台试试,等等,我们后台表虽然创建好了,但是还没有添加管理员,现在由于后台已经登陆不进去了,所以在后台内也无法创建了,并且注册功能也没有(这种分离下,后台一般没必要有注册功能),所以这里继续用console的功能来创建一个用户,控制台的功能挺多的,不仅仅是数据库管理,可以点这里了解下。

在console/controllers中新建InitController,然后如下代码:

<span style="color: #000000;">php
</span><span style="color: #008000;">/*</span><span style="color: #008000;">*
 * Application initialization
 * 参照深入理解Yii2.0视频教程
 </span><span style="color: #008000;">*/</span><span style="color: #000000;">
namespace console\controllers;

</span><span style="color: #0000ff;">use</span><span style="color: #000000;"> backend\models\Admin;

</span><span style="color: #0000ff;">class</span> InitController <span style="color: #0000ff;">extends</span><span style="color: #000000;"> \yii\console\Controller
{
    </span><span style="color: #008000;">/*</span><span style="color: #008000;">*
     * Create init admin
     </span><span style="color: #008000;">*/</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> actionAdmin()
    {
        </span><span style="color: #0000ff;">echo</span> "Create init admin ...\n";                  <span style="color: #008000;">//</span><span style="color: #008000;"> 提示当前操作</span>
        <span style="color: #800080;">$username</span> = <span style="color: #800080;">$this</span>->prompt('Admin Name:');        <span style="color: #008000;">//</span><span style="color: #008000;"> 接收用户名</span>
        <span style="color: #800080;">$email</span> = <span style="color: #800080;">$this</span>->prompt('Email:');               <span style="color: #008000;">//</span><span style="color: #008000;"> 接收Email</span>
        <span style="color: #800080;">$password</span> = <span style="color: #800080;">$this</span>->prompt('Password:');         <span style="color: #008000;">//</span><span style="color: #008000;"> 接收密码</span>
        <span style="color: #800080;">$model</span> = <span style="color: #0000ff;">new</span> Admin();                            <span style="color: #008000;">//</span><span style="color: #008000;"> 创建一个新用户</span>
        <span style="color: #800080;">$model</span>->username = <span style="color: #800080;">$username</span>;                   <span style="color: #008000;">//</span><span style="color: #008000;"> 完成赋值</span>
        <span style="color: #800080;">$model</span>->email = <span style="color: #800080;">$email</span><span style="color: #000000;">;
        </span><span style="color: #800080;">$model</span>->password = <span style="color: #800080;">$password</span>;<span style="color: #008000;">//</span><span style="color: #008000;">注意这个地方,用了Admin模型中的setPassword方法(魔术方法__set)</span>
        <span style="color: #0000ff;">if</span> (!<span style="color: #800080;">$model</span>->save())                            <span style="color: #008000;">//</span><span style="color: #008000;"> 保存新的用户</span>
<span style="color: #000000;">        {
            </span><span style="color: #0000ff;">foreach</span> (<span style="color: #800080;">$model</span>->getErrors() <span style="color: #0000ff;">as</span> <span style="color: #800080;">$error</span>)     <span style="color: #008000;">//</span><span style="color: #008000;"> 如果保存失败,说明有错误,那就输出错误信息。</span>
<span style="color: #000000;">            {
                </span><span style="color: #0000ff;">foreach</span> (<span style="color: #800080;">$error</span> <span style="color: #0000ff;">as</span> <span style="color: #800080;">$e</span><span style="color: #000000;">)
                {
                    </span><span style="color: #0000ff;">echo</span> "<span style="color: #800080;">$e</span>\n"<span style="color: #000000;">;
                }
            }
            </span><span style="color: #0000ff;">return</span> 1;                                   <span style="color: #008000;">//</span><span style="color: #008000;"> 命令行返回1表示有异常</span>
<span style="color: #000000;">        }
        </span><span style="color: #0000ff;">return</span> 0;                                       <span style="color: #008000;">//</span><span style="color: #008000;"> 返回0表示一切OK</span>
<span style="color: #000000;">    }

}

InitController</span>.php
InitController.php

然后再命令行中运行:

yii init/admin

按照提示来填写用户名密码等,便可以产生一条数据了,当我们查看这条记录时,发现我们填写的明文密码变成加密的了,而创建时间和更新和更新时间我们没填写也自动给填写了,前者是由于用了__set魔术方法,后者是用了“行为”,如果不是很理解请看《深入理解Yii2.0》,里面讲的比较详细。还有就是,可能在window下cmd运行中文乱码,大体搜了下没找到好的解决方法,不过可以试下Cygwin这个windows下可以运行linux命令的软件,挺好用的,设置成utf-8就不会乱码了,而且可以用gcc什么的。

3、现在我们前后台都能按照自己数据库里的数据来登录了,但是由于session等公用一个,所以还是退出时,前后台一起退出,需要进一步操作:可以参照这篇wiki

后台,在backend/config/main.php或者main-local.php中

'components' =><span style="color: #000000;"> [
    </span>'user' =><span style="color: #000000;"> [
        </span>'identityClass' => 'backend\models\Admin',
        'enableAutoLogin' => <span style="color: #0000ff;">true</span>,
        'identityCookie' =><span style="color: #000000;"> [
            </span>'name' => '_backendUser', <span style="color: #008000;">//</span><span style="color: #008000;"> unique for backend</span>
        ],<span style="color: #000000;">
    ]</span>,
    'session' =><span style="color: #000000;"> [
        </span>'name' => 'PHPBACKSESSID',
        'savePath' => sys_get_temp_dir(),<span style="color: #000000;">
    ]</span>,
    'request' =><span style="color: #000000;"> [
        </span>'cookieValidationKey' => 'orGkZNZvZe3-4WicYHyGMS-EyI6Tp8yi',<span style="color: #008000;">//</span><span style="color: #008000;">random string</span>
        'csrfParam' => '_backendCSRF',<span style="color: #000000;">
    ]</span>,
...

同样在前台,在frontend/config/main.php或者main-local.php中

'components' =><span style="color: #000000;"> [
    </span>'user' =><span style="color: #000000;"> [
        </span>'identityClass' => 'frontend\models\User',
        'enableAutoLogin' => <span style="color: #0000ff;">true</span>,
        'identityCookie' =><span style="color: #000000;"> [
            </span>'name' => '_frontendUser', <span style="color: #008000;">//</span><span style="color: #008000;"> unique for frontend</span>
<span style="color: #000000;">        ]
    ]</span>,
    'session' =><span style="color: #000000;"> [
        </span>'name' => 'PHPFRONTSESSID',
        'savePath' => sys_get_temp_dir(),<span style="color: #000000;">
    ]</span>,
    'request' =><span style="color: #000000;"> [
        </span>'cookieValidationKey' => '8rqO22WJ9yiAx_KuJ8SFnbKctqGDWi9J',
        'csrfParam' => '_frontendCSRF',<span style="color: #000000;">
    ]</span>,
...

这样再登陆试下,就会发现前后台完全没关联了。可以调用Yii::$app的功能,例如Yii::$app->user->id,如果是在后台的目录中,会显示后台的用户id,如果是在前台的目录中则会显示前台的用户id。可能有些强迫症患者想同Yii1那样用Yii::$app->admin->id来访问后台用户id,这个不太好实现,Yii2和Yii1相比,用户验证这块改动挺大的,web/User在Yii2框架中作为核心组件,如果要修改的话应该还要关联修改web/Application中的变量方法等,个人感觉没必要。

以上,就是所说的,其实还有很多已经集成好的yii2-user、带权限控制等的插件可以直接从composer中搜索使用。例如点击率最高的这个,可以配置B类型的验证,而且集成了更多功能。(个人只是大体看了下,没下载使用呢还)

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn