Yii系列最佳实践之后台业务框架

Posted 枫爷

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Yii系列最佳实践之后台业务框架相关的知识,希望对你有一定的参考价值。

缘起

上面的几章都讲概念了,没有怎么讲到实践的东西,可能会有些枯燥,这很正常的,概念还是需要慢慢啃的,尤其是官网其他的部分,需要狠狠的啃。

什么,你啃不动了?看看官网旁边的那个在线用户吧。

你不啃的时候可是有这么多人在啃知识,如果不想以后被这打击,赶紧学!!!一如当年大学的我,每天夜里都抱着一本《算法导论》在啃一样,自律相当重要。

这一章我就带大伙了解一下前两章的概念有啥用,应用到实际,这是临门一脚,但是,我总是觉得概念的重要性至少要占70%,临门的一脚实践只占30%,望君能体会~

环境

操作系统:OS X EI Capitan

php版本:PHP 5.6.30

Yii版本:Yii 2.0

编辑器:PHPStorm

整体框架

首先,我们做这个框架的目的不是给我们自己看的,而是给广大以后会在这套框架中学习工作的人看的,所以,千万不能融入自己的思想,要尽可能的通俗易懂,符合一般的逻辑设计。

这张图是Yii提供给我们的源代码,首先,为了能够更能适合我们的业务框架,我决定来简单的修改一下这个文件结构。

首先,增加业务模块文件夹modules。用以区分每个不同的业务线。

增加全局基础类文件夹commons。用以定义application需要使用到的基础类。

在刚刚创建的Commons文件夹下面创建环境配置文件Config.php和全局方法文件Common.php

Config.php文件用以配置环境和获取相应环境的配置常量。

Common方法用以定义全局使用到的一些function。【注意,这边的Common只是用于保存全局的方法,不用做namespace】

 

Common里面比较重要的一个方法就是获取配置常量方法,后面在很多配置文件中会用到这个方法。

/**
 * 获取配置文件
 * @param $key string min;
 * @param string $env $string dev:开发环境
 * @return mixed
 */
function Config($key, $val = null)
{
    return \\app\\commons\\Config::get($key, $val);
}

这边的Config就是我们刚才创建的Config.php文件,具体代码如下:

<?php
namespace app\\commons;

/**
 * 主要实现不同文件配置查找扩展 file.param.param1
 *
 * 文件.数组变量.变量
 */
class Config
{
    const ENV_SIT = \'sit\';

    const ENV_PRE = \'pre\';

    const ENV_PRD  = \'prd\';

    private static $_config = null;

    /**
     * 初始化配置,永远加载prd, 默认加载sit
     * @param type $configPath
     * @param type $env
     * @throws \\Exception
     */
    public static function init($configPath = null, $env = self::ENV_SIT)
    {
        if (!is_dir($configPath)) {
            die(\'配置目录不存在\');
        }

        $paths[] = $configPath . DIRECTORY_SEPARATOR . self::ENV_PRD;

        switch ($env) {
            case self::ENV_PRE:
                $paths[] = $devconfig = $configPath . DIRECTORY_SEPARATOR . self::ENV_PRE;
                break;
            case self::ENV_SIT:
                if (is_dir($configPath . DIRECTORY_SEPARATOR . self::ENV_SIT)) {
                    $paths[] = $configPath . DIRECTORY_SEPARATOR . self::ENV_SIT;
                }
                break;

            default:
                break;
        }

        static::$_config = \\Noodlehaus\\Config::load($paths);
    }

    public static function get($key, $default = null)
    {
        return static::$_config->get($key, $default);
    }

    public static function set($key, $value)
    {
        return static::$_config->set($key, $value);
    }
}

另外,我们需要在config文件夹中新增几个文件,用以区分线上环境【prd】,线上测试环境【pre】,本地开发环境【sit】的配置文件,具体的区分是在config这个文件夹中建立三个对应的目录,我们来先创建一下。

每个目录下面建立一个app.php的文件,用以存放app的相关配置常量。

那么,我们如何区分是哪个环境呢,以及如何对应到相应的环境配置常量中去呢。

这边,我给大伙带来了一个非常好用的配置第三方组件。Noodlehaus。

github地址:https://github.com/hassankhan/config

我们可以通过composer去下载和自动加载它。

$ composer require hassankhan/config

这里面有个问题,不知道是我学识不足,还是因为这个自动配置文件有问题,这个配置文件加载器始终不让我来按照文件名去区分配置变量,没办法,我暴力的修改了它的一行源代码。

打开Config的源代码,vendor/hassankhan/config/src/Config.php

修改构造函数里面的一行代码

// Try and load file
$this->data = array_replace_recursive($this->data, array($info[\'filename\'] => (array) $parser->parse($path)));

将原本的(array) $parser->parse($path)修改为:array($info[\'filename\'] => (array) $parser->parse($path))即可。

那么,为了保证这边的代码能够在第一时间被加载,以便于配置好环境常量,方便下面的操作,我们需要在入口脚本index.php处加上如下代码:

//我们每个环境的域名都会在nginx虚拟配置里面设置,和环境有关
if (empty(getenv(\'ENV\'))) {
    $hostInfo = $_SERVER[\'HTTP_HOST\'];
    $environment = \'prd\';
    if (strpos($hostInfo, \'sit\') !== false) {
        $environment = \'sit\';
    }

    if (strpos($hostInfo, \'pre\') !== false) {
        $environment = \'pre\';
    }
} else {
    $environment = in_array(getenv(\'ENV\'), array(\'sit\', \'pre\', \'prd\')) ?
        getenv(\'ENV\') : \'sit\';
}

\\app\\commons\\Config::init(__DIR__, $environment);

这段代码的意思是如果没有设置环境,我们就根据_SERVER魔术变量中关于HTTP_HOST的值,去判断我们处理的应用主体处于哪个环境,这是一个灵活的配置,希望大家多思考思考这里面的思想。

但是,这样一来,我们的入口脚本就会变得很冗长,这是我们不愿意看到的,之前也和大家讲过,如果觉得在脚本中有过长的代码该如何,我们在config文件中新建一个bootstrap.php文件来存放上面的代码,包括include需要的两个文件,那么整体bootstrap.php的代码就如下所述:

<?php

ini_set(\'memory_limit\', \'128M\');

//初始化全局函数
include dirname(__DIR__) . \'/Commons/Common.php\';
//初始化环境配置
include dirname(__DIR__) . \'/Commons/Config.php\';

... ... // 上面的代码

$getDebug = empty($_GET[\'debug\']) ? \'\' : $_GET[\'debug\'];

bootstrap.php撸完了,我们需要在入口脚本里面做一些小的改变,具体改变如下:

<?php

require(__DIR__ . \'/../vendor/autoload.php\');
require(__DIR__ . \'/../config/bootstrap.php\');

// comment out the following two lines when deployed to production
defined(\'YII_DEBUG\') or define(\'YII_DEBUG\', Config(\'app.debug\'));
defined(\'YII_ENV\') or define(\'YII_ENV\', Config(\'app.env\'));

require(__DIR__ . \'/../vendor/yiisoft/yii2/Yii.php\');

$config = require(__DIR__ . \'/../config/web.php\');

(new yii\\web\\Application($config))->run();

上面这边已经使用了Config,这个方法是Common.php里面的一个方法,调用的就是Config.php里面的get方法,上面已经给大伙演示过啦,如果使用编辑器,应该会直接带出来,非常方便。

好的,到这边,我们对整个环境的区分配置就已经完成。现在就可以在app.php里面放置一些变量了~

示例为prd目录下app.php的配置代码。

<?php
/**
 * app.php 线上环境项目配置
 */

return [
    \'name\' => \'fengye-prd\',
    \'env\' => \'prd\',
    \'debug\' => false,
    \'log\' => [
        \'traceLevel\' => YII_DEBUG ? 3 : 0,
        \'targets\' => [
            [
                \'class\' => \'yii\\log\\FileTarget\',
                \'levels\' => [\'error\', \'warning\'],
            ],
            [
                \'class\' => \'yii\\log\\FileTarget\',
                \'categories\' => [\'fengye.info.*\'],
                \'levels\' => [\'info\'],
                \'logVars\' => [],
            ]
        ],

    ]
];

其实吧,prd,pre,sit这三个目录下面还需要配置两个文件,一个是数据库配置文件,三个环境要予以区分;还有一个是缓存配置文件,redis,memcache的配置需要三个环境的区分。这会在后面讲完数据库和缓存再和大伙聊聊这边的配置的事。

对于MVC里的一些在commons里的基类,我们会放在模块中的MVC一节去讲解,看完了整体的一个需要改动的结构,我们再来看看配置文件的改动吧。

配置相关

在Yii系列基础框架中我们提到过一些基础的配置,至于如何实施,在那一章节中我们没有细讲,今天,在这一节中,我们来好好看下应用配置有哪些是必要的,哪些是不必要的。

上一节讲到,哪些配置是需要区分环境的,下面来讲的是通用配置,不需要区分环境的配置。

首先,我们打开配置文件,web.php。

<?php
$params = require(__DIR__ . \'/params.php\');

之前的章节中提到过,如果配置项中有太多的属性,需要列举到一个文件中,使整个代码结构更清晰。

这边,我们有几个配置项需要写到文件中。

在这段代码后新增

$rules = require(__DIR__ . \'/rules.php\');
$aliases = require(__DIR__ . \'/aliases.php\');
$modules = require(__DIR__.\'/modules.php\');

顺带在当前目录中【config】新增几个php文件:rules.php,aliases.php,modules.php

配置rules:

在Yii系列请求处理那一章中我们讲到一个路由规则,在具体的配置中,解析规则一节中我们提到一个rules配置项,使用正则去解析。

\'<module:\\w+>/<controller:\\w+>/<action:\\w+>\' => \'<module>/<controller>/<action>\', //模块相关规则

前面使用户的URL,后面是解析到对应的路径,后面是路径哟,分别是modules、controller、action。

这边涉及到一个概念,接口版本的区分,比方说之前的老接口不能支持现在的新业务了,建议在接口action名称后面新增一个版本号,没有版本号的为默认版本,并在注释中使用注明,关于接口文档的修改,我觉得并没有那么麻烦,使用swagger自动生成在线文档即可,在修改接口版本的时候,去旧版本注释里面将旧街口标识为过期即可。

关于swagger的相关内容,我会在后面,Yii系列,第三方工具中详细讲解。

这条规则能满足大部分的情况,如果每个module下面有很多的子文件夹,就需要来重新定义一些规则啦。具体的看我到时候发布到github的源码吧。

aliases.php用于配置路径别名,这边我们先放一放,以后需要用到的时候再讲,这边暂时用不到。

modules.php文件用于配置各个业务模块,用以区分业务模块的代码区域。

<?php
/**
 * 配置业务模块
 */
return [
    // 用户模块
    \'user\' => [
        \'class\' => \'app\\modules\\user\\User\',
    ],
    // 商品模块
    \'goods\' => [
        \'class\' => \'app\\modules\\goods\\Goods\',
    ],
    // 订单模块
    \'order\' => [
        \'class\' => \'app\\modules\\order\\Order\',
    ],
    // 库存模块
    \'stock\' => [
        \'class\' => \'app\\modules\\stock\\Stock\',
    ],
    // 支付模块
    \'pay\' => [
        \'class\' => \'app\\modules\\pay\\Pay\',
    ],
    // 消息模块
    \'message\' => [
        \'class\' => \'app\\modules\\message\\Message\',
    ],
];

这是全局配置,如果后面有新增模块,再往这里面加即可,新增了这几个文件,我们需要先完善这些代码。

首先,rules.php文件里面的配置项并无需要新增的代码。

modules里面定义了每个module的class,这边需要新增所有模块的基础模块类。

在modules文件夹里面新增定义好的几个module,并采用mvc结构初始化models,views,controllers,以及模块内的配置文件configs。

这边以Goods为例,我们建立商品模块。

第一步,在modules下面建立goods文件夹。并在goods目录下面创建对应的文件和mvc文件夹。

Goods.php文件为上面modules.php配置文件中goods模块的基类。用以引导goods模块,具体代码如下:

<?php

namespace app\\modules\\goods;

use Yii;

class Goods extends \\yii\\base\\Module
{
    public $controllerNamespace = \'app\\modules\\goods\\controllers\';

    public function init()
    {
        parent::init();

        Yii::configure($this, require(__DIR__ . \'/config.php\'));
    }
}

两个功能,指定controller namespace,加载配置文件。

config.php文件代码如下:

<?php
return [
    \'components\' => [
        // list of component configurations
    ],
    \'params\' => [
        // list of goods params
    ],
];

用以配置goods模块需要用到的配置项。

其他模块类似goods可以都创建一套相应的模板。

到此为止,相应的modules配置大功告成,以后撸代码就经常在这里面了。

回到配置文件,我们继续往下讲。加载了这么多文件,如何配置进去呢,不急,慢慢来。

首先,我们配置一下appid

这边我们是这么去配置的

\'id\' => Config(\'app.name\'),

Config方法来源于Common.php文件定义的全局函数。

设置语言

\'language\' => \'zh-CN\',

配置modules

\'modules\' => $modules,

配置别名

\'aliases\' => $aliases,

配置components,记得,这边已经到components里面啦。

配置urlManager,将上面的规则引到这边的配置项中

\'urlManager\' => [
            \'showScriptName\' => false,
            \'enablePrettyUrl\' => true,
            \'rules\' => $rules
        ],

配置log,按照我们上节讲到的区分环境配置。

\'log\' => [
            \'traceLevel\' => Config(\'app.log.traceLevel\'),
            \'targets\' => Config(\'app.log.targets\'),
        ],

关于cache和db的配置,我们会到对应的章节中再做详解。

最后,需要将web/assets文件夹的权限设为可写,将runtime文件夹的权限设为可写。

至此,所有关于入口脚本的配置文件项和基础框架均已搭建完毕。

再次访问你的那个远程ip地址,出现下面这个页面表示成功。

创建接口

搭好了上面的框架,下面我们就先来创建一个接口试验一下吧。

首先,在User这个module下面的controller里面新建一个InfoController.php,用以获取用户的基本信息。

在InfoController.php里面,我们新建一个action,叫actionBaseInfo()。

具体代码如下:

<?php
namespace app\\modules\\user\\controllers;

use Yii;
use yii\\web\\Controller;

class InfoController extends Controller
{
    public function actionBaseInfo()
    {
        echo \'hello world!\';
    }
}

Nginx虚拟主机配置

到这边,所有的准备工作都完成啦,现在,我们需要在Nginx里面配置一个可供远程访问的host。

首先,我们来到nginx的安装目录

#cd /usr/www/nginx/

进入配置文件夹

#cd conf

新建一个文件夹,用以存放vhost虚拟主机配置文件。

#mkdir vhosts

进入vhosts目录,新增sit.fengye.conf虚拟主机配置文件。

编辑一下内容到该文件里。

server {
        charset utf-8;
        client_max_body_size 128M;

        listen       80;
        server_name  www.sit.fengye.com;

        index index.php;
        root /usr/www/app/yii-basic/web;
        location / {
                # 如果找不到真实存在的文件,把请求分发至 index.php
                try_files $uri $uri/ /index.php?$args;
        }

        location ~ \\.php$ {
                include fastcgi.conf;
                fastcgi_pass   127.0.0.1:9000;
                fastcgi_param ENV \'sit\';
                include fastcgi_params;
                #fastcgi_pass unix:/var/run/php5-fpm.sock;
                try_files $uri =404;
        }

        location ~ /\\.(ht|svn|git) {
                deny all;
        }

        access_log  /var/log/nginx/sit.fengye.access.log;
        error_log  /var/log/nginx/sit.fengye.error.log;
}

这些行代表什么意思,我会在Nginx的后续章节给大伙详解。

保存退出,需要让nginx在启动的时候加载虚拟主机配置,我们需要在刚才的conf目录下面的nginx.conf文件里面加一行。

include /usr/local/nginx/conf/vhosts/*.conf;

添加到http属性的最后一行即可。

保存退出,重启Nginx。

#service nginx restart

编辑你远程服务器的hosts和本地的hosts,让www.sit.fengye.com进入到hosts中,以便你顺畅的访问。

远程服务器编辑/etc/hosts,新增下一行

127.0.0.1   www.sit.fengye.com

本地编辑/etc/hosts【OS X】,新增下一行

服务器IP   www.sit.fengye.com

至此,在浏览器中输入下面的链接,看到hello world,你就成功啦!!!

http://www.sit.fengye.com/user/info/base-info

结束语

好了,到此为止,证明之前的配置没有任何问题,路由规则也是能够搞通的,perfect!

关于数据库和缓存还有后续的框架内容,我还是会按照之前的方式,先讲概念,再讲实践。

关于本章的代码,以及后续的代码,枫爷都已发布到github上,供大伙下载,感兴趣的朋友别忘了Fork和Star一下我哈~感谢。

github地址:https://github.com/ifengye/yii-basic

以上是关于Yii系列最佳实践之后台业务框架的主要内容,如果未能解决你的问题,请参考以下文章

Yii2 HOW-TO:最佳实践

elementUI,iview开发后台管理系统的最佳实践是怎样的

Spring Boot项目传参校验最佳实践

去工具化/脚本化理解,自动化运维落地最佳实践之业务/架构/模型/方法

最佳实践百度大规模Service Mesh落地实践

最佳实践百度大规模Service Mesh落地实践