• 在线商城表结构


    李炎恢-在线商城第三季总结

     

    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
  • 相关阅读:
    禁用aspx页面的客户端缓存
    水晶报表的自动换行(转)
    ORACLE锁的管理
    同时使用有线和无线
    Oracle系统表的查询
    Oracle中临时表的深入研究
    我的My Life Rate
    [学习笔记]c#Primer中文版命名空间
    出差兰州·火车上
    [学习笔记]c#Primer中文版类设计、static成员、const和readonly数据成员
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3020461.html
Copyright © 2020-2023  润新知