PHP.28-TP框架商城应用实例-后台5-多表操作-商品表与品牌表
表与表之间的关系:1:1 1:多 多:多
功能需求决定表关系
此处的表关系为:品牌表:商品表=1:多
1、首先在表结构上关联,在多的表(商品表)添加一个字段,关联一的表(品牌表)的ID(主键)
添加字段:ALTE TABLE p39_goods ADD brand_id mediumint unsigned not null default '0' comment '品牌id';
注:因为需求【有可能根据品牌搜商品】,所以在商品表加上品牌id索引
添加索引: ALTER TABLE p39_goods ADD INDEX brand_id(brand_id);
2、程序代码上关联
添加商品时选择品牌
2.1在控制器GoodsController.class.php/add()中取出所有品牌
2.2在表单/Adimin/View/Goods/add.html制作下拉框
$brandData:为品牌表中取出
2.3提交表单时,把品牌id保存到商品表的brand_id字段,修改商品模型GoodsModel.class.php允许接收表单的品牌id字段
商品列表中显示品牌信息
2.4在Goods/lst.html中添加列
$data:为商品表中取出
注:因为商品表中中保存的为品牌id,显示id没有意义,因此在取商品表数据$data时,应连表查询出品牌表中brand_name的数据
2.5取商品信息时连表取出品牌名称
修改商品模型GoodsModel.class.php中的search方法
__BRAND__:可以避免当表前缀发生改变时,连表失效【tp提供的】
注:多表查询建议给表取别名,以免发生不同表同字段的错误,导致显示、查询失败等。此处有一个需要注意的地方【错误8】
<?php namespace Admin\Model; use Think\Model; class GoodsModel extends Model { //添加调用create方法允许接收的字段 protected $insertFields = 'goods_name,market_price,shop_price,is_on_sale,goods_desc,brand_id'; //修改调用create方法允许接收的字段 protected $updateFields = 'id,goods_name,market_price,shop_price,is_on_sale,goods_desc,brand_id,member_price'; //定义验证规则 validate:TP模型层提供的一种数据验证方法 //a.静态方式:在模型类里面通过$_validate属性定义验证规则。b.动态方式:使用模型类的validate方法动态创建自动验证规则 //定义好验证规则后,就可以在使用create方法创建数据对象的时候自动调用 protected $_validate = array( array('goods_name', 'require', '商品名称不能为空!', '1'), array('market_price', 'currency', '市场价格必须是货币!', '1'), array('shop_price', 'currency', '本店价格必须是货币类型!', '1'), ); //钩子方法_before_insert:添加前插入,在添加前会自动调用 //第一个参数:表单中即将要被插入数据库中的数据=>数组 //&按引用传递:函数外部的变量的值要在函数内部修改的话,必须按引用传递,除非传递的为对象,因为对象默认按引用传递 protected function _before_insert(&$data, $option) { $id = $option['where']['id']; //要修改的商品的ID /**************处理LOGO******************/ //判断有没有选择图片 if($_FILES['logo']['error'] == 0) { $ret = uploadOne('logo', 'Goods', array( array(700, 700), array(350, 350), array(130, 130), array(50, 50), )); $data['logo'] = $ret['images'][0]; $data['mbig_logo'] = $ret['images'][1]; $data['big_logo'] = $ret['images'][2]; $data['mid_logo'] = $ret['images'][3]; $data['sm_logo'] = $ret['images'][4]; } //获取当前时间并添加到表单中,这样就会插入数据库中 $data['addtime'] = date('Y-m-d H:i:s', time()); //过滤这个字段 【必须对所有输入内容进行过滤】 $data['goods_desc'] = removeXSS($_POST['goods_desc']); } //钩子方法_before_update:更新前插入,在添加前会自动调用 protected function _before_update(&$data, $option) { /* var_dump($data); var_dump($option); die(); */ $id = $option['where']['id']; //要修改的商品的ID /**************处理LOGO******************/ //判断有没有选择图片 if($_FILES['logo']['error'] == 0) { $ret = uploadOne('logo', 'Goods', array( array(700, 700), array(350, 350), array(130, 130), array(50, 50), )); $data['logo'] = $ret['images'][0]; $data['mbig_logo'] = $ret['images'][1]; $data['big_logo'] = $ret['images'][2]; $data['mid_logo'] = $ret['images'][3]; $data['sm_logo'] = $ret['images'][4]; //先查询出原来的图片的路径 $oldLogo = $this->field('logo,mbig_logo,big_logo,mid_logo,sm_logo')->find($id); //从硬盘上删除图片 deleteImage($oldLogo); } //过滤这个字段 【必须对所有输入内容进行过滤】 $data['goods_desc'] = removeXSS($_POST['goods_desc']); } /* protected function _after_update(&$data, $option) { var_dump($data); var_dump($option); die(); } */ //钩子方法_before_delete:删除前的操作 protected function _before_delete($option) { $id = $option['where']['id']; //要删除的商品的ID //先查询出原来的图片的路径 $oldLogo = $this->field('logo,mbig_logo,big_logo,mid_logo,sm_logo')->find($id); deleteImage($oldLogo); } //钩子方法_after_insert:添加操作成功后执行 protected function _after_insert($data, $option) { $mp = I('post.member_price'); //接收post提交过来的会员价格数据 $mpModel = D('member_price'); foreach ($mp as $k => $v) { $_v = (float)$v; //强制转为浮点型,以免插入字符等错误数据 //设置会员价格>0就插入到表中 if($_v > 0) { $mpModel->add(array( 'price' => $_v, 'level_id' => $k, //级别Id 'goods_id' => $data['id'], )); } } } /** *实现翻页、搜索、排序 * */ public function search($perPage = 5) //$perPage控制显示条数 { /***********搜索(获取get提交的数据)************/ $where =array(); //空的where条件 //商品名称 $gn = I('get.gn'); if($gn) $where['a.goods_name'] = array('like', "%$gn%"); //WHERE goods_name LIKE '%$gn%' //品牌 $brandId = I('get.brand_id'); if($brandId) $where['a.brand_id'] = array('eq', "$brandId"); //WHERE goods_name LIKE '%$gn%' //市场价格 $fp = I('get.fp'); $tp = I('get.tp'); if($fp && $tp) $where['a.shop_price'] = array('between', array($fp, $tp)); //WHERE shop_price BETWEEN $fp AND $tp elseif($fp) $where['a.shop_price'] = array('egt', $fp); //WHERE shop_price >= $fp elseif($tp) $where['a.shop_price'] = array('elt', $tp); //WHERE shop_price <= $tp //是否上架 $ios = I('get.ios'); if($ios) $where['a.is_on_sale'] = array('eq', $ios); //WHERE is_on_sale = $ios //添加时间 $fa = I('get.fa'); $ta = I('get.ta'); if($fa && $ta) $where['a.addtime'] = array('between', array($fa, $ta)); //WHERE addtime BETWEEN $fa ADD $ta elseif($fa) $where['a.addtime'] = array('egt', $fa); //WHERE addtime >= $fa elseif($ta) $where['a.addtime'] = array('elt', $ta); //WHERE addtime <= $ta /***********翻页**********/ //取出总的记录数 $count = $this->alias('a')->where($where)->count(); //生成翻页类的对象 $pageObj = new \Think\Page($count, $perPage); //设置样式 $pageObj->setConfig('next', '下一页'); $pageObj->setConfig('prev', '上一页'); //生成页面下面显示的上一页、下一页的字符串 $pageString = $pageObj->show(); /**********排序********************/ $orderby = 'a.id'; //默认的排序字段 $orderway = 'desc'; //默认的排序方式(降序) $odby = I('get.odby'); if($odby) { if($odby == 'id_asc') //时间升序,id为自增 $orderway = 'asc'; elseif($odby == 'price_desc') //价格降序(默认降序) $orderby = 'a.shop_price'; elseif($odby == 'price_asc') //价格升序 { $orderby = 'a.shop_price'; $orderway = 'asc'; } } /**********取某一页的数据**********/ /*** * SELECT a.*,b.brand_name FROM p39_goods a LEFT JOIN p39_brand b ON a.brand_id=b.id; **/ $data = $this->order("$orderby $orderway") ->field('a.*, b.brand_name') ->alias('a') //加别名 ->join('LEFT JOIN __BRAND__ b ON a.brand_id=b.id') ->where($where) ->limit($pageObj->firstRow.','.$pageObj->listRows) ->select(); /************返回数据$data*************/ return array( 'data' => $data, //数据 'page' => $pageString, //翻页字符串 ); } } ?>
外连与内连查询的区别【商城项目多用外连】
外连:SELECT a.*,b.brand_name FROM p39_goods a LEFT JOIN p39_brand b ON a.brand_id=b.id;
主表数据一定能取出来,无论是否有关联;left join:左表为主表;
内连:SELECT a.*,b.brand_name FROM p39_goods a JOIN p39_brand b ON a.brand_id=b.id;
SELECT a.*,b.brand_name FROM p39_goods a, p39_brand b WHERE a.brand_id=b.id;
只能取出两个表中有关联关系的数据,
则lst.html品牌显示处,可修改brand_id为brand_name,使之显示品牌名称
修改商品页面edit.html中显示品牌信息
2.6在控制器GoodsController.class.php/edit()中【此处会取出$data商品表和$brandData品牌表】
2.7制作下拉框,显示当前品牌为选定状态
优化:下拉框函数