• 【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 appcommonsConfig::get($key, $val);
    }

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

    <?php
    namespace appcommons;
    
    /**
     * 主要实现不同文件配置查找扩展 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 = NoodlehausConfig::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';
    }
    
    appcommonsConfig::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 yiiwebApplication($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' => 'yiilogFileTarget',
                    'levels' => ['error', 'warning'],
                ],
                [
                    'class' => 'yiilogFileTarget',
                    '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' => 'appmodulesuserUser',
        ],
        // 商品模块
        'goods' => [
            'class' => 'appmodulesgoodsGoods',
        ],
        // 订单模块
        'order' => [
            'class' => 'appmodulesorderOrder',
        ],
        // 库存模块
        'stock' => [
            'class' => 'appmodulesstockStock',
        ],
        // 支付模块
        'pay' => [
            'class' => 'appmodulespayPay',
        ],
        // 消息模块
        'message' => [
            'class' => 'appmodulesmessageMessage',
        ],
    ];

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

    首先,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 appmodulesgoods;
    
    use Yii;
    
    class Goods extends yiiaseModule
    {
        public $controllerNamespace = 'appmodulesgoodscontrollers';
    
        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 appmodulesusercontrollers;
    
    use Yii;
    use yiiwebController;
    
    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

  • 相关阅读:
    redis分布式锁
    pod资源清单
    zookeeper
    [置顶]【WP】 Writeup for SJTU-CTF ,被同级大佬和学长联合虐爆
    魔术师猜数【更优解】
    数学基础之线代
    向量是什么?
    矩阵与线性变换
    线性组合、张成的空间、基
    线性代数的本质
  • 原文地址:https://www.cnblogs.com/riverdubu/p/6636743.html
Copyright © 2020-2023  润新知