在線商城表結構


李炎恢-在線商城第三季總結

 

1)      首先分析一下表結構 (數據庫設計尤為重要)

①   管理員表mall_manage

 

②   管理員等級表mall_level

 

  解釋:level為外鍵,為管理員等級(一對一)

③   用戶表mall_user

 

④   用戶收貨地址表mall_address

 

解釋:

1.用戶的收貨地址可以有多個,而只有一個是默認(selected=1);

2.這里的收貨地址表並沒有去關聯用戶表,其實可以關聯一下;

⑤   商品類型表mall_nav

 

解釋:

  1. 商品類型(商品欄目),這里支持無限極分類;
  2. 其中sid表示其分類id(為0表示頂級父類);
  3. 只有子類才可以關聯商品品牌(多對多)等外表,頂級父類不可以關聯;
  4. 而價格區間無論是子類還是父類都可關聯(多對多)。(補充:更合理划分價格區間,應該由該類目下的最高價格與最低價格之間進行比對,然后再自動划分,不太應該由用戶指定)

 

⑥   商品品牌表

 

 

⑦   商品屬性表

 

解釋:商品屬性關聯商品類型,原因是商品類型有限而固定,屬性可以隨時增減,屬性關聯類型更合理;(多對多)

 

⑧   商品價格區間表

 

⑨   商品表

 

解釋:

1.商品goods_id-à商品類型nav_id (一對一)(補充:這里商品類型必須是子類)

2.商品goods_id-à商品品牌brand_id(一對一)(一個商品只屬於一個品牌)

3.商品goods_id-à商品屬性attr_id(一對多)(一個商品有多個屬性)

4.關鍵字段說明:商品編號goods_sn、大縮略圖thumbnail、小縮略圖thumbnail2、本店價price_sale、市場價price_market、成本價price_cost、單位計量unit、重量weight、詳細描述content、是否上架is_up、是否免郵費is_freight、庫存量inventory、warn_inventory最小庫存量(小於它,將會報庫存警告)、發布時間date

 

⑩   訂單表

 

解釋:(說明,這里為了方便起見,並沒有將用戶表、用戶收貨地址表關聯起來)

  1. 訂單表order_id-àuser_id(一對一,該訂單只能屬於一個用戶);
  2. 訂單表order_id-àuser_address_id(一對一,該訂單只能對應一個收貨地址,可修改);
  3. 訂單表order_id-à支付方式表pay_id(一對一,該訂單只能對應一種支付方式,可修改);
  4. 訂單表order_id-à配送方式表delivery_id(一對一,該訂單只能對應一種配送方式,可修改)
  5. 補充:還有一個缺貨處理方式表,該表是否需要建立,目前未知;
  6. 關鍵字段說明:用戶備注text、缺貨處理方式ps、訂單編號ordernum、總價格price、商品詳請goods(serialize序列化后存儲)、訂單狀態order_state、配送狀態order_delivery、支付狀態order_pay、下單時間date

 

數據庫名mall,一共10張表,如下:

 

數據庫分析總結:需要改進的地方有以下幾點:

  1. 用戶表應與用戶收貨地址表相關聯,減小重復;
  2. 訂單表應與用戶收貨地址表相關聯,減少重復;
  3. 應建立支付方式表pay,再關聯,滿足三范式;
  4. 應建立配送方式表delivery,再關聯,滿足三范式;
  5. 其他還在整理中…

 

 

2)      然后,分析李炎恢第三季在線商城MVC框架(原理+實例)

 

①   其目錄結構如下:

 

 

②   目錄結構說明:

  1. 該架構使用smarty作為模板引擎,其對應目錄smarty、cache、compile、view(修改自templates),分別是smarty核心文件、緩存目錄、編譯文件、模板文件(MVC稱之為視圖層);
  2. 其MVC結構,controller控制器、model模型層、view視圖層、check驗證層(隸屬於model層,為model層服務,負責對請求數據,進行驗證);
  3. 其他目錄說明,ckeditor開源文本編輯器、configs配置文件、public公共類庫(如工具類、圖片處理類、文件上傳類等)、uploads存放上傳文件、index.php入口文件;

 

③   商城框架流程圖(非常重要)

層次結構(李炎恢老師畫)

 

---------------------------------------------------------------------------------------------------------------------

類結構(李炎恢老師畫)

 

說明:上圖在此你可能看不懂,下面會以實例說明之

 

④   其框架特點總結

  1. 單一入口,index.php,所有請求都通過index.php入口文件;
  2. 請求方式index.php?a=mamage&m=add (a表示action,m表示方法method),如上請求ManageAction()->add();
  3. 實例化action,使用了簡單工廠模式Factory::setAction()->run(),其原理是通過判斷$_GET[‘a’]去實例化action;
  4. 執行m方法,Factory::setAction()->run(),在頂級父類Action的run()方法中,判斷$_GET[‘m’],去執行相應的action方法;
  5. Action中持有model、smarty、redirect類的實例,使用了組合模式。調用model,對請求數據進行處理、驗證數據、查詢數據庫等,smarty加載模板文件並解析生成緩存文件(加載視圖),redirect負責頁面跳轉;
  6. Model中持有request、check、db類的實例,使用了組合模式。調用request對所請求的數據過濾,調用check驗證請求數據,調用db查詢數據庫完成增刪改查操作;
  7. 使用TPL類繼承Smarty,然后修改Smarty和實現單例,使用了單例模式;這里面很多類都是用了單例模式,請注意;
  8. 其他說明,controller層中類命名為xxxAction.class.php,model層中類命名為xxxModel.class.php,check層中類命名為xxxCheck.class.php。 如ManageAction.class.php,ManageModel.class.php,ManageCheck.class.php

 

 

⑤   以管理員Manage模塊中的添加管理員為例,詳解執行流程:

首先交代一下本次操作會涉及到的目錄及文件:

  • index.php
  • configs/run.inc.php à 運行時index.php直接加載的文件
  • configs/profile.inc.php- à 系統配置文件
  • Smarty/Smarty.class.php- à Smarty模板引擎調用入口類
  • Public/幾乎所有文件,其中較為重要Factory.class.php-à工廠類、TPL.class.php-à模板引擎類、DB.class.php-à數據庫工具類、Redirect.class.php-à跳轉類、Request.class.php-à請求處理類、Validate.class.php-à驗證類、Tool.class.php-à工具類等
  • Controller/Action.class.php à 控制器頂級父類
  • Controller/ManageAction.class.php- à 管理員控制器類
  • Model/ManageModel.class.php à 管理員模型類
  • Model/LevelModel.class.php à 等級模型類 (此類是對等級表進行增刪改查操作)

 

詳細執行流程如下:以請求參數http://localhost/Mall/index.php?a=manage&m=add,注意這里的請求時通過點擊新增管理員表單的submit按鈕后,直奔的地址,此時會把用戶名、密碼、確認密碼、等級等一起提交過來。故事就此展開……

 

首先服務器加載index.php;

里面只做了一件事,加載configs/run.inc.php

代碼:

1 require dirname(__FILE__).'/configs/run.inc.php';

 

 

然后run.inc.php文件里面做了以下主要操作:加載configs/profile.inc.php系統配置文件、加載Smarty/Smarty.class.php、自定義自動加載器_autoload()、調用Factory->setAction()實例化,由地址欄參數a=manage指定的ManageAction.class.php、最后再次調用Factory->setAction()->run(),即調用剛剛實例化的ManageAction對象的run()方法(這里的run()方法是繼承自Action.class.php),執行相應的方法,即執行的完成操作是$ManageAction->add()操作;

 

關鍵性代碼如下:(說明:以下只會貼出本次操作,該類下的相應方法,不是整個類)

Config/run.inc.php代碼如下:

復制代碼
 1 <?php
 2 
 3 session_start();
 4 
 5 //錯誤級別
 6 
 7 error_reporting(E_ALL);
 8 
 9 //網站根目錄
10 
11 define('ROOT_PATH', substr(dirname(__FILE__),0,-8));
12 
13 //設置編碼
14 
15 header('Content-Type: text/html;charset=utf-8');
16 
17 //設置時區
18 
19 date_default_timezone_set('Asia/Shanghai');
20 
21 //引入Smarty配置文件
22 
23 require ROOT_PATH.'/configs/profile.inc.php';
24 
25 //引入smarty引擎
26 
27 require ROOT_PATH.'/smarty/Smarty.class.php';
28 
29 //自動加載類
30 
31 function __autoload($className) {
32 
33 if (substr($className,-6) == 'Action') {
34 
35            require ROOT_PATH.'/controller/'.$className.'.class.php';
36 
37 } else if(substr($className,-5) == 'Model') {
38 
39            require ROOT_PATH.'/model/'.$className.'.class.php';
40 
41 } else if (substr($className, -5) == 'Check') {
42 
43            require ROOT_PATH.'/check/'.$className.'.class.php';
44 
45 } else {
46 
47            require ROOT_PATH.'/public/'.$className.'.class.php';
48 
49 }
50 
51 }
52 
53 //單入口
54 
55 Factory::setAction()->run();
56 
57 ?>
復制代碼

 

 

Factory.class.php代碼如下:

復制代碼
 1 //簡單工廠類
 2 
 3 class Factory{
 4 
 5 private static $_obj = null;
 6 
 7 public static function setAction() {
 8 
 9            $a = self::getA();
10 
11            if(!file_exists(ROOT_PATH.'/controller/'.$a.'Action.class.php')) $a = 'Index';
12 
13            eval('self::$_obj = new '.ucfirst($a).'Action();');
14 
15            return self::$_obj;
16 
17 }
18 
19 }
復制代碼

 

 

Action.class.php代碼如下:

復制代碼
 1 //頂級控制器
 2 
 3 class Action {
 4 
 5 //模板對象
 6 
 7 protected $tpl = null;
 8 
 9 //模型對象
10 
11 protected $model = null;
12 
13 //跳轉對象
14 
15 protected $redirect = null;
16 
17 protected function __construct() {
18 
19            $this->tpl = TPL::getInstance();
20 
21            $this->model = Factory::setModel();
22 
23            $this->redirect = Redirect::getInstance($this->tpl);
24 
25 }       
26 
27 public function run() {
28 
29            $m = isset($_GET['m']) ? $_GET['m'] : 'index';
30 
31            method_exists($this, $m) ? $this->$m() : $this->index();
32 
33 }
34 
35 }
復制代碼

 

 

在實例化ManageAction時,由於與此相對應的Model和其他所需Model如這里LevelModel,同樣會通過Factory工廠類進行實例化(因為實例化Model放在了ManageAction的__construct()中)。

ManageAction.class.php代碼如下:

復制代碼
 1 //管理員控制器
 2 
 3 class ManageAction extends Action {
 4 
 5          //等級對象
 6 
 7          private $level = null;
 8 
 9         
10 
11          public function __construct() {
12 
13                    parent::__construct();
14 
15                    $this->level = new LevelModel();
16 
17          }       
18 
19          public function add() {
20 
21                    if (isset($_POST['send'])) $this->model->add() ? $this->redirect->succ('?a=manage', '恭喜您,管理員添加成功!') : $this->redirect->error('對不起,管理員添加失敗!');
22 
23                    $this->tpl->assign('allLevel', Tool::setFormItem($this->level->findAll(), 'id', 'level_name'));
24 
25                    $this->tpl->display(SMARTY_ADMIN.'manage/add.tpl');
26 
27          }
28 
29 }
復制代碼

 

A. 此時在add()方法中,就直接調用了levelModel的findAll()方法即取出所有等級(新增管理員時需要),而且把返回的等級信息通過TPL對象的assign注入到模板中去,最后加載模板顯示。

 

B. 用戶點擊新增管理員后,調用的是ManageModel的add()方法;

代碼如下:

1 if (isset($_POST['send'])) $this->model->add() ? $this->redirect->succ('?a=manage', '恭喜您,管理員添加成功!') : $this->redirect->error('對不起,管理員添加失敗!');

 

在實例化ManageModel中,進行了許多操作,如:獲取db的實例對象、Request請求處理類對象、ManageCheck驗證類對象、表字段羅列、數據表名字、請求數據等;

Model.class.php代碼如下:

復制代碼
 1 class Model extends DB {
 2 
 3          //數據庫類實例
 4 
 5          protected $db = null;
 6 
 7          //數據表字段
 8 
 9          protected $fields = array();
10 
11          //數據表
12 
13          protected $tables = array();
14 
15          //驗證對象
16 
17          protected $check = null;
18 
19          //limit
20 
21          protected $limit = '';
22 
23          //請求數據
24 
25          protected $_R = array();
26 
27         
28 
29          protected function __construct() {
30 
31                    $this->db = DB::getInstance();
32 
33          }
34 
35         
36 
37          //獲取request對象
38 
39          protected function getRequest() {
40 
41                    return Request::getInstance($this, $this->check);
42 
43          }
44 
45         
46 
47          //新增數據
48 
49          protected function add(Array $postData) {
50 
51                    return $this->db->add($this->tables, $postData);
52 
53          }
54 
55 }
復制代碼

 

ManageModel.class.php代碼如下:

復制代碼
 1 //控制器模型類
 2 
 3 class ManageModel extends Model {
 4 
 5          public function __construct() {
 6 
 7                    parent::__construct();
 8 
 9                    $this->fields = array('id', 'user', 'pass', 'level', 'login_count', 'last_ip', 'last_time', 'reg_time');
10 
11                     $this->tables = array(DB_PREFIX.'manage');
12 
13                     $this->check = new ManageCheck();
14 
15                     list(
16 
17                                     $this->_R['id'],
18 
19                                     $this->_R['user'],
20 
21                                     $this->_R['pass'],
22 
23                                     $this->_R['code']
24 
25                     ) = $this->getRequest()->getParams(array(
26 
27                                     isset($_GET['id']) ? $_GET['id'] : null,
28 
29                                     isset($_POST['user']) ? $_POST['user'] : null,
30 
31                                     isset($_POST['pass']) ? $_POST['pass'] : null,
32 
33                                     isset($_POST['code']) ? $_POST['code'] : null
34 
35                     ));
36 
37          }
38 
39         
40 
41          public function add() {
42 
43                    $where = array("user='{$this->_R['user']}'");
44 
45                    if (!$this->check->checkAdd($this, $where)) $this->check->error();
46 
47                    $requestData = $this->getRequest()->filter($this->fields);
48 
49                    $requestData['pass'] = sha1($requestData['pass']);
50 
51                    $requestData['last_ip'] = Tool::getIP();
52 
53                    $requestData['reg_time'] = Tool::getDate();
54 
55                    return parent::add($requestData);
56 
57          }
58 
59 }
復制代碼

 

在執行model層的add()方法時,如上,首先使用驗證層對所提交數據,進行驗證,驗證失敗,跳轉到報錯頁面,否則繼續往下執行。其驗證過程封裝到ManageCheck.class.php類中;

Check.class.php代碼如下:

復制代碼
 1 class Check extends Validate {
 2 
 3          //驗證結果狀態
 4 
 5          protected $flag = true;
 6 
 7          //錯誤信息集
 8 
 9          protected $message = array();
10 
11          //模板對象
12 
13          private $_tpl = null;
14 
15  
16 
17          public function __construct() {
18 
19                    $this->_tpl = TPL::getInstance();
20 
21          }
22 
23          //顯示錯誤信息並返回
24 
25          public function error($url = '') {
26 
27                    if (empty($url)) {
28 
29                             $this->_tpl->assign('message', $this->message);
30 
31                             $this->_tpl->assign('prev', Tool::getPrevPage());
32 
33                             $this->_tpl->display(SMARTY_ADMIN.'public/error.tpl');
34 
35                             exit;
36 
37                    } else {
38 
39                             Redirect::getInstance()->succ($url);
40 
41                    }
42 
43          }
44 
45 }
復制代碼

 

ManageCheck.class.php代碼如下:

復制代碼
 1 //管理員驗證類
 2 
 3 class ManageCheck extends Check {
 4 
 5          //驗證新增數據
 6 
 7          public function checkAdd(Model &$model, Array $params) {
 8 
 9                    if (self::isNullString($_POST['user'])) {
10 
11                             $this->message[] = '管理員用戶名不得為空!';
12 
13                             $this->flag = false;
14 
15                    }
16 
17                    if (!self::checkStrLength($_POST['user'], 2, 'min')) {
18 
19                             $this->message[] = '管理員用戶名不得小於2位!';
20 
21                             $this->flag = false;
22 
23                    }
24 
25                    if (!self::checkStrLength($_POST['user'], 20, 'max')) {
26 
27                             $this->message[] = '管理員用戶名不得大於20位!';
28 
29                             $this->flag = false;
30 
31                    }
32 
33                    if (!self::checkStrLength($_POST['pass'], 6, 'min')) {
34 
35                             $this->message[] = '管理員密碼不得小於6位!';
36 
37                             $this->flag = false;
38 
39                    }
40 
41                    if (!self::checkStrEqual($_POST['pass'], $_POST['notpass'])) {
42 
43                             $this->message[] = '確認密碼與密碼必須保持一致!';
44 
45                             $this->flag = false;
46 
47                    }
48 
49                    if (self::isNullString($_POST['level'])) {
50 
51                             $this->message[] = '必須選擇管理員等級權限!';
52 
53                             $this->flag = false;
54 
55                    }
56 
57                    if ($model->checkOne($params)) {
58 
59                             $this->message[] = '管理員用戶名已被占用!';
60 
61                             $this->flag = false;
62 
63                    }
64 
65                    return $this->flag;
66 
67          }
68 
69 }
復制代碼

 

然后使用Request請求處理類,對提交數據,進行入庫前的過濾

代碼如下:

1 $requestData = $this->getRequest()->filter($this->fields);

 

 

最后,填充數據庫應有字段,如時間,用戶ip,密碼加密等

代碼如下:

1 $requestData['pass'] = sha1($requestData['pass']);
2 
3 $requestData['last_ip'] = Tool::getIP();
4 
5 $requestData['reg_time'] = Tool::getDate();

 

然后通過父類調用DB對象中的add()方法,新增一條數據;

代碼如下:

復制代碼
 1 return parent::add($requestData);
 2 
 3  
 4 
 5                   //新增數據
 6 
 7                   protected function add(Array $postData) {
 8 
 9                             return $this->db->add($this->tables, $postData);
10 
11                   }
復制代碼

 

DB.class.php關鍵代碼如下:

復制代碼
 1 //新增
 2 
 3          protected function add($tables, Array $postData) {
 4 
 5                    $addFields = array();
 6 
 7                    $addData = array();
 8 
 9                    foreach ($postData as $key=>$value) {
10 
11                             $addFields[] = $key;
12 
13                             $addData[] = $value;
14 
15                    }
16 
17                    $addFields = implode(',', $addFields);
18 
19                    $addData = implode("','", $addData);
20 
21                    $sql = "INSERT INTO $tables[0] ($addFields) VALUES ('$addData')";
22 
23                    return $this->execute($sql)->rowCount();              
24 
25          }
復制代碼

 

最后把是否新增成功的數據的結果,逐層從DB->Model->ManageModel->Controller反饋到ManageAtion的add方法中,如果新增成功跳轉到成功提示頁面,如果失敗跳轉到失敗提示頁面;

 

代碼如下:

1 if (isset($_POST['send'])) $this->model->add() ? $this->redirect->succ('?a=manage', '恭喜您,管理員添加成功!') : $this->redirect->error('對不起,管理員添加失敗!');

 

 

到此,整個執行流程執行完畢!

 

小結:整個執行流程按照非常嚴格的MVC的設計思想在進行,每一個層次的職責都非常明確。如controller控制器層,專門負責邏輯判斷,頁面跳轉等,是一個調度者。它可以調度model層去獲取數據,驗證數據、填充數據等,它還可以調度view層,把數據給顯示出來。

 

最后,整個框架的分析到這里就結束,接下來會對其中的重要模塊或功能進行總結。

學而時習之,不亦說乎?有朋自遠方來,不亦樂乎?*\(^v^)/*
 
分類:  php與mysql
標簽:  李炎恢第三季php在線商城總結mvc


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM