緣起
上面的幾章都講概念了,沒有怎么講到實踐的東西,可能會有些枯燥,這很正常的,概念還是需要慢慢啃的,尤其是官網其他的部分,需要狠狠的啃。
什么,你啃不動了?看看官網旁邊的那個在線用戶吧。
你不啃的時候可是有這么多人在啃知識,如果不想以后被這打擊,趕緊學!!!一如當年大學的我,每天夜里都抱着一本《算法導論》在啃一樣,自律相當重要。
這一章我就帶大伙了解一下前兩章的概念有啥用,應用到實際,這是臨門一腳,但是,我總是覺得概念的重要性至少要占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