Ecshop的商品筛选功能实现分析之一(主要对category.php进行分析)

一、首先,说明一下为什么要对category.php文件进行分析。

(1)原因如下:

①个人对商城类商品筛选功能的实现比较好奇;

②对商城中关于商品的数据表设计比较感兴趣。(该功能涉及到与数据库的交互,而且与数据库中数据表的设计好坏有一定的联系);

③多条件(属性)筛选功能在现今的很多网站都需要用到,很广泛(如:一般商城网、团购网、房产网、信息分类网站等等)。

(2)希望达到的目的是:

①能够对多条件筛选功能有一个初步的认识。(起码自己做,也能够快速实现吧);

②对多条件筛选的实现中,数据库该如何去设计才会更优化和更合理些(参考前人的经验);

③对多条件筛选中的一些策略或者是技巧,能有一个了解(会总结几点)

二、然后,我们首先看一下现在需求是如何的?(多条件筛选,请参考京东、苏宁、国美等)

①京东商城的商品筛选功能(截图):

②苏宁商城的商品筛选功能(截图)

③国美在线的商品筛选功能(截图)

补充:其实,要对该功能的观察,还必须对地址栏,也作一番思考的,我这里就省略了,毕竟如果这样分析,会更简单一些。上面这些例子,只作一个引子吧。后续我会完善它的。

④ECSHOP的商品筛选功能实现,展示细节(截图+文字)如下:

1)首先,我本地服务器,给本机安装的ecshop演示网站,配了一个虚拟主机地址:为 http://demo.ecshop.com

2)然后,我就通过该地址来访问主页,并查看属于导航栏中“GSM手机”分类下的商品。如下:

访问地址为:http://demo.ecshop.com/category.php?id=3   

结果页面为:

那么,此时的访问,会罗列出,属于“GSM手机”分类下(即cat_id=3)的所有商品,因为目前还没有对商品进行多筛选。

如果我想查看品牌为“诺基亚”的手机,那么点击“诺基亚”标签即可:

访问地址为:  http://demo.ecshop.com/category.php?id=3&brand=1&price_min=0&price_max=0

结果页面为:

如果我选择了多条件搜索,看截图:

访问地址为: http://demo.ecshop.com/category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.0.160.0

结果页面为:

分析:从上面的地址栏的变化和截图的变化,可以初步看出ecshop的多条件搜索方法是怎么样的了。

猜想1:随着用户每一次点击条件(属性)进行商品筛选时,搜索地址栏会变化,为什么地址栏会变化,归根结底,一定是每一个商品的属性的a标签的超链接地址被改变了。而且是每点击一次,都会随着搜索条件的不同,而改变。

从而我们知道,这个属性的超链接,是动态生成的。ecshop后台一定是作了大量的判断过程,并最终为每一个商品属性,生成一个超链接地址,以防止上一次的搜索条件丢失。

猜想2:商品的价格区间,是根据什么来计算的呢?还是人工后台设置的,京东的商品价格区间,好像都是很有规律的,和ecshop的价格区间,有比较大的区别。别管这么多了,我们还是先研究ecshop的再说。

猜想3:参数 filter_attr=163.0.160.0 中的几个数字,一定代表着下面:颜色、屏幕大小 、手机制式、外观样式属性下,都选择了哪一些值了。

----> 带着这样一些疑问,那我们直接去研究一下ecshop是如何实现上面的多条件搜索功能啦。。。GO。。。

首先,我们到ecshop的网站更目录,找到category.php文件,打开它进行研究一下。

1.点击这里,查看全部代码的分析过程。

  1 <?php
  2 /**
  3  * 分析首页 商品分类页面category.php的实现方法
  4  * ECSHOP 2.7.2 商品分类
  5  */
  6 define(‘IN_ECS‘, true);
  7 require(dirname(__FILE__) . ‘/includes/init.php‘);
  8 if ((DEBUG_MODE & 2) != 2) {
  9     $smarty->caching = true;
 10 }
 11
 12 //====> 请求地址栏:http://localhost/category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186
 13 //====> 1.获取分类id
 14 /* 获得请求的分类 ID */
 15 if (isset($_REQUEST[‘id‘])) {
 16     $cat_id = intval($_REQUEST[‘id‘]);
 17 }
 18 elseif (isset($_REQUEST[‘category‘])) {
 19     $cat_id = intval($_REQUEST[‘category‘]);
 20 } else {
 21     /* 如果分类ID为0,则返回首页 */
 22     ecs_header("Location: ./\n");
 23     exit;
 24 }
 25
 26 //====> 2.首先获取所有GET和POST中,可用于搜索的参数的值。
 27 //====> 若没有此参数,则说明,并没有用此参数来搜索,默认要给它一个默认值。
 28 /* 初始化分页信息 */
 29 $page = isset($_REQUEST[‘page‘])   && intval($_REQUEST[‘page‘])  > 0 ? intval($_REQUEST[‘page‘])  : 1;
 30 $size = isset($_CFG[‘page_size‘])  && intval($_CFG[‘page_size‘]) > 0 ? intval($_CFG[‘page_size‘]) : 10;
 31 $brand = isset($_REQUEST[‘brand‘]) && intval($_REQUEST[‘brand‘]) > 0 ? intval($_REQUEST[‘brand‘]) : 0;
 32 $price_max = isset($_REQUEST[‘price_max‘]) && intval($_REQUEST[‘price_max‘]) > 0 ? intval($_REQUEST[‘price_max‘]) : 0;
 33 $price_min = isset($_REQUEST[‘price_min‘]) && intval($_REQUEST[‘price_min‘]) > 0 ? intval($_REQUEST[‘price_min‘]) : 0;
 34 $filter_attr_str = isset($_REQUEST[‘filter_attr‘]) ? htmlspecialchars(trim($_REQUEST[‘filter_attr‘])) : ‘0‘;
 35 $filter_attr_str = urldecode($filter_attr_str);
 36 $filter_attr = empty($filter_attr_str) ? ‘‘ : explode(‘.‘, trim($filter_attr_str));
 37
 38 /* 排序、显示方式以及类型 */
 39 $default_display_type = $_CFG[‘show_order_type‘] == ‘0‘ ? ‘list‘ : ($_CFG[‘show_order_type‘] == ‘1‘ ? ‘grid‘ : ‘text‘);
 40 $default_sort_order_method = $_CFG[‘sort_order_method‘] == ‘0‘ ? ‘DESC‘ : ‘ASC‘;
 41 $default_sort_order_type   = $_CFG[‘sort_order_type‘] == ‘0‘ ? ‘goods_id‘ : ($_CFG[‘sort_order_type‘] == ‘1‘ ? ‘shop_price‘ : ‘last_update‘);
 42
 43 $sort  = (isset($_REQUEST[‘sort‘])  && in_array(trim(strtolower($_REQUEST[‘sort‘])), array(‘goods_id‘, ‘shop_price‘, ‘last_update‘))) ? trim($_REQUEST[‘sort‘])  : $default_sort_order_type;
 44 $order = (isset($_REQUEST[‘order‘]) && in_array(trim(strtoupper($_REQUEST[‘order‘])), array(‘ASC‘, ‘DESC‘)))                              ? trim($_REQUEST[‘order‘]) : $default_sort_order_method;
 45 $display  = (isset($_REQUEST[‘display‘]) && in_array(trim(strtolower($_REQUEST[‘display‘])), array(‘list‘, ‘grid‘, ‘text‘))) ? trim($_REQUEST[‘display‘])  : (isset($_COOKIE[‘ECS‘][‘display‘]) ? $_COOKIE[‘ECS‘][‘display‘] : $default_display_type);
 46 $display  = in_array($display, array(‘list‘, ‘grid‘, ‘text‘)) ? $display : ‘text‘;
 47 setcookie(‘ECS[display]‘, $display, gmtime() + 86400 * 7);
 48
 49 /* 页面的缓存ID */
 50 $cache_id = sprintf(‘%X‘, crc32($cat_id . ‘-‘ . $display . ‘-‘ . $sort  .‘-‘ . $order  .‘-‘ . $page . ‘-‘ . $size . ‘-‘ . $_SESSION[‘user_rank‘] . ‘-‘ .
 51         $_CFG[‘lang‘] .‘-‘. $brand. ‘-‘ . $price_max . ‘-‘ .$price_min . ‘-‘ . $filter_attr_str));
 52
 53 /* 如果页面没有被缓存则重新获取页面的内容 */
 54 if (!$smarty->is_cached(‘category.dwt‘, $cache_id)) {
 55 //====> 3.把该栏目下的所有子栏目id获取,如果没有子栏目,则是自身。
 56 //===> TABLE:ecs_category
 57 //====> RETURN:id=3 => g.cat_id IN (‘3‘)  或 id=6 => g.cat_id IN (‘6‘,‘8‘,‘9‘,‘11‘,‘7‘)
 58 //====> 说明:ecshop的特点是,顶级栏目下也可以添加商品,所以会把顶级栏目id也放在数组里面
 59 $children = get_children($cat_id);
 60
 61 //====> 4.获得该分类的相关信息。如:分类名称、价格分级、筛选属性、父id
 62 //===> TABLE:ecs_category
 63 //====> RETURN:Array ( [cat_name] => GSM手机 [keywords] => [cat_desc] => [style] => [grade] => 4 [filter_attr] => 185,189,173,178 [parent_id] => 1 )
 64 $cat = get_cat_info($cat_id);
 65
 66 //===> 5.如果有品牌筛选brand参数,那么获取出该品牌名称
 67 //===> TABLE:ecs_brand
 68 //===> SQL:SELECT brand_name FROM `ecshop`.`ecs_brand` WHERE brand_id = ‘1‘
 69 //====> RETURN:诺基亚
 70  /* 赋值固定内容 */
 71 if ($brand > 0) {
 72     $sql = "SELECT brand_name FROM " .$GLOBALS[‘ecs‘]->table(‘brand‘). " WHERE brand_id = ‘$brand‘";
 73     $brand_name = $db->getOne($sql);
 74 } else {
 75     $brand_name = ‘‘;
 76 }
 77
 78
 79 ///>>================开始---商品价格区间处理==================>>///
 80 //===> 6.获取该分类cat的价格分级:
 81 //===> ①如果价格分级=0,那么获取直接父类的价格分级。(Ⅰ如果父类价格也=0,那么就是不用价格分级 )
 82 //===> ②如果价格分级!=0,那么就是自身的价格分级。
 83 //===> TABLE:ecs_category
 84 //===> RETURN:$cat[‘grade‘]=4
 85 /* 获取价格分级 */
 86 if ($cat[‘grade‘] == 0  && $cat[‘parent_id‘] != 0) { //  ==>如果价格分级为空,但是它还有上级分类,那么取直接上级的价格分级等数
 87     $cat[‘grade‘] = get_parent_grade($cat_id); //如果当前分类级别为空,取最近的上级分类
 88 }
 89
 90 //===> 7.对价格区间进行划分。 ecshop的划分方法,是根据算法来的,比较复杂。
 91 //===> 如果价格分级>1,那么就执行价格区间划分
 92 if ($cat[‘grade‘] > 1) {
 93     /* 需要价格分级 */
 94
 95     /*
 96      算法思路:
 97     1、当分级大于1时,进行价格分级
 98     2、取出该类下商品价格的最大值、最小值
 99     3、根据商品价格的最大值来计算商品价格的分级数量级:
100     价格范围(不含最大值)    分级数量级
101     0-0.1                   0.001
102     0.1-1                   0.01
103     1-10                    0.1
104     10-100                  1
105     100-1000                10
106     1000-10000              100
107     4、计算价格跨度:
108     取整((最大值-最小值) / (价格分级数) / 数量级) * 数量级
109     5、根据价格跨度计算价格范围区间
110     6、查询数据库
111
112     可能存在问题:
113     1、
114     由于价格跨度是由最大值、最小值计算出来的
115     然后再通过价格跨度来确定显示时的价格范围区间
116     所以可能会存在价格分级数量不正确的问题
117     该问题没有证明
118     2、
119     当价格=最大值时,分级会多出来,已被证明存在
120     */
121
122     //===> 获得当前分类下商品价格的最大值、最小值
123     //===> 获得所有扩展分类属于指定分类的所有商品ID ,其中goods_id = 16的商品的扩展属于分类3
124     //===> TABLE:ecs_goods 和 ecs_goods_cat
125     //===> SQL:SELECT min(g.shop_price) AS min, max(g.shop_price) as max FROM `ecshop`.`ecs_goods` AS g WHERE (g.cat_id IN (‘5‘) OR g.goods_id IN (‘8‘,‘16‘) ) AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1
126     //===> RETURN:Array ( [min] => 280.00 [max] => 5999.00 )
127     $sql = "SELECT min(g.shop_price) AS min, max(g.shop_price) as max ".
128             " FROM " . $ecs->table(‘goods‘). " AS g ".
129             " WHERE ($children OR " . get_extension_goods($children) . ‘) AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1  ‘;
130     $row = $db->getRow($sql);
131
132
133     //===> 按照公式计算出最低价格和最高价格、以及价格跨度
134     //===============↓↓↓先不做讨论===============
135     // 取得价格分级最小单位级数,比如,千元商品最小以100为级数
136     $price_grade = 0.0001;
137     for($i=-2; $i<= log10($row[‘max‘]); $i++) {
138         $price_grade *= 10;
139     }
140
141     //价格跨度
142     $dx = ceil(($row[‘max‘] - $row[‘min‘]) / ($cat[‘grade‘]) / $price_grade) * $price_grade;
143     if($dx == 0) {
144         $dx = $price_grade;
145     }
146
147     for($i = 1; $row[‘min‘] > $dx * $i; $i ++);
148
149         for($j = 1; $row[‘min‘] > $dx * ($i-1) + $price_grade * $j; $j++);
150         $row[‘min‘] = $dx * ($i-1) + $price_grade * ($j - 1);
151
152         for(; $row[‘max‘] >= $dx * $i; $i ++);
153         $row[‘max‘] = $dx * ($i) + $price_grade * ($j - 1);
154
155         //===>这里打印最高价格和最低价格:$row=>Array ( [min] => 200 [max] => 6200 )
156         //===>这里打印价格跨度:$dx = 1500
157
158         //===============先不做讨论↑↑↑==================//
159
160
161         //===> 根据商品的价格、价格区间的最低价格、以及价格跨度,计算该商品价格属于哪一个区间内。
162         //===> 获取属于该价格区间内的商品的数量、获取sn则属于哪一个区间sn=0为200-1700、sn=1为1700-3200、sn=3为4700-6200。
163         //===> 因为没有商品价格属于第二区间,则不存在sn=2,那么3200-4700则没有任何商品
164         //===> TABLE:ecs_goods 和 ecs_goods_cat
165         //===> SQL:SELECT (FLOOR((g.shop_price - 200) / 1500)) AS sn, COUNT(*) AS goods_num FROM `ecshop`.`ecs_goods` AS g WHERE (g.cat_id IN (‘3‘) OR g.goods_id IN (‘16‘) ) AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 GROUP BY sn
166         //===>RETURN:Array ( [0] => Array ( [sn] => 0 [goods_num] => 6 ) [1] => Array ( [sn] => 1 [goods_num] => 5 ) [2] => Array ( [sn] => 3 [goods_num] => 1 ) )
167         $sql = "SELECT (FLOOR((g.shop_price - $row[min]) / $dx)) AS sn, COUNT(*) AS goods_num  ".
168                 " FROM " . $ecs->table(‘goods‘) . " AS g ".
169                 " WHERE ($children OR " . get_extension_goods($children) . ‘) AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 ‘.
170                 " GROUP BY sn ";
171         $price_grade = $db->getAll($sql);
172
173
174         //===> 根据价格等级price_grade,计算真正的价格区间。
175         //===> 方法build_uri()重要:要为每一个价格区间,生成一个url超链接,以备前台点击搜索用
176         //===> 并根据价格参数,判断该区间,是否是当前被搜索的区间
177         //===> 把价格区间,注入模板,供前台使用
178         //===> RETURN:Array ( [0] => Array ( [sn] => 0 [goods_num] => 6 [start] => 0 [end] => 0 [price_range] => 全部 [url] => category.php?id=3&brand=1&price_min=0&price_max=0&filter_attr=163.216.160.186 [selected] => 0 ) [1] => Array ( [sn] => 1 [goods_num] => 6 [start] => 200 [end] => 1700 [price_range] => 200 - 1700 [formated_start] => ¥200元 [formated_end] => ¥1700元 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) [2] => Array ( [sn] => 3 [goods_num] => 5 [start] => 1700 [end] => 3200 [price_range] => 1700 - 3200 [formated_start] => ¥1700元 [formated_end] => ¥3200元 [url] => category.php?id=3&brand=1&price_min=1700&price_max=3200&filter_attr=163.216.160.186 [selected] => 0 ) [3] => Array ( [goods_num] => 1 [start] => 4700 [end] => 6200 [price_range] => 4700 - 6200 [formated_start] => ¥4700元 [formated_end] => ¥6200元 [url] => category.php?id=3&brand=1&price_min=4700&price_max=6200&filter_attr=163.216.160.186 [selected] => 0 ) )
179         foreach ($price_grade as $key=>$val) {
180             $temp_key = $key + 1;
181             $price_grade[$temp_key][‘goods_num‘] = $val[‘goods_num‘];
182             $price_grade[$temp_key][‘start‘] = $row[‘min‘] + round($dx * $val[‘sn‘]);
183             $price_grade[$temp_key][‘end‘] = $row[‘min‘] + round($dx * ($val[‘sn‘] + 1));
184             $price_grade[$temp_key][‘price_range‘] = $price_grade[$temp_key][‘start‘] . ‘&nbsp;-&nbsp;‘ . $price_grade[$temp_key][‘end‘];
185             $price_grade[$temp_key][‘formated_start‘] = price_format($price_grade[$temp_key][‘start‘]);
186             $price_grade[$temp_key][‘formated_end‘] = price_format($price_grade[$temp_key][‘end‘]);
187             $price_grade[$temp_key][‘url‘] = build_uri(‘category‘, array(‘cid‘=>$cat_id, ‘bid‘=>$brand, ‘price_min‘=>$price_grade[$temp_key][‘start‘], ‘price_max‘=> $price_grade[$temp_key][‘end‘], ‘filter_attr‘=>$filter_attr_str), $cat[‘cat_name‘]);
188             /* 判断价格区间是否被选中 */
189             if (isset($_REQUEST[‘price_min‘]) && $price_grade[$temp_key][‘start‘] == $price_min && $price_grade[$temp_key][‘end‘] == $price_max) {
190                 $price_grade[$temp_key][‘selected‘] = 1;
191             }
192             else {
193                 $price_grade[$temp_key][‘selected‘] = 0;
194             }
195         }
196         //补充一个选择全部的类型的数组
197         $price_grade[0][‘start‘] = 0;
198         $price_grade[0][‘end‘] = 0;
199         $price_grade[0][‘price_range‘] = $_LANG[‘all_attribute‘];
200         $price_grade[0][‘url‘] = build_uri(‘category‘, array(‘cid‘=>$cat_id, ‘bid‘=>$brand, ‘price_min‘=>0, ‘price_max‘=> 0, ‘filter_attr‘=>$filter_attr_str), $cat[‘cat_name‘]);
201         $price_grade[0][‘selected‘] = empty($price_max) ? 1 : 0;
202         //把价格区间数组,注入模板文件
203         $smarty->assign(‘price_grade‘,     $price_grade);
204     }
205     ///<<================结束---商品价格区间处理==================<<///
206
207
208     ///>>================开始---商品品牌处理==================>>///
209     //====> ???db_create_in(array_unique(array_merge(array($cat_id), array_keys(cat_list($cat_id, 0, false))))) . ")
210     //===> 品牌筛选功能:把该栏目下(其中包括扩展分类下的商品),所有商品的品牌获取,但不能重复。
211     //===> 品牌下有商品并且商品状态正常,才能把该品牌取出。没有商品的品牌不能取出
212     //===> TABLE:ecs_brand、ecs_goods 和 ecs_goods_cat
213     //===> SQL:SELECT b.brand_id, b.brand_name, COUNT(*) AS goods_num FROM `ecshop`.`ecs_brand`AS b, `ecshop`.`ecs_goods` AS g LEFT JOIN `ecshop`.`ecs_goods_cat` AS gc ON g.goods_id = gc.goods_id WHERE g.brand_id = b.brand_id AND (g.cat_id IN (‘3‘) OR gc.cat_id IN (‘3‘) ) AND b.is_show = 1 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 AND g.is_delete = 0 GROUP BY b.brand_id HAVING goods_num > 0 ORDER BY b.sort_order, b.brand_id ASC
214     //===> RETURN:Array ( [0] => Array ( [brand_id] => 1 [brand_name] => 诺基亚 [goods_num] => 3 ) [1] => Array ( [brand_id] => 2 [brand_name] => 摩托罗拉 [goods_num] => 1 ) [2] => Array ( [brand_id] => 3 [brand_name] => 多普达 [goods_num] => 1 ) [3] => Array ( [brand_id] => 4 [brand_name] => 飞利浦 [goods_num] => 2 ) [4] => Array ( [brand_id] => 5 [brand_name] => 夏新 [goods_num] => 1 ) [5] => Array ( [brand_id] => 6 [brand_name] => 三星 [goods_num] => 2 ) [6] => Array ( [brand_id] => 7 [brand_name] => 索爱 [goods_num] => 1 ) [7] => Array ( [brand_id] => 9 [brand_name] => 联想 [goods_num] => 1 ) [8] => Array ( [brand_id] => 10 [brand_name] => 金立 [goods_num] => 1 ) )
215     /* 品牌筛选 */
216     $sql = "SELECT b.brand_id, b.brand_name, COUNT(*) AS goods_num ".
217             "FROM " . $GLOBALS[‘ecs‘]->table(‘brand‘) . "AS b, ".
218             $GLOBALS[‘ecs‘]->table(‘goods‘) . " AS g LEFT JOIN ". $GLOBALS[‘ecs‘]->table(‘goods_cat‘) . " AS gc ON g.goods_id = gc.goods_id " .
219             "WHERE g.brand_id = b.brand_id AND ($children OR " . ‘gc.cat_id ‘ . db_create_in(array_unique(array_merge(array($cat_id), array_keys(cat_list($cat_id, 0, false))))) . ") AND b.is_show = 1 " .
220             " AND g.is_on_sale = 1 AND g.is_alone_sale = 1 AND g.is_delete = 0 ".
221             "GROUP BY b.brand_id HAVING goods_num > 0 ORDER BY b.sort_order, b.brand_id ASC";
222     $brands = $GLOBALS[‘db‘]->getAll($sql);
223
224     //===> 把该分类下所有商品的品牌,组合成数组,给前台调用
225     //===> 方法build_uri()重要:要为每品牌,生成一个url超链接,以备前台点击搜索用
226     //===> 把数组注入模板文件
227     //====! 这样一种组织数组的方式,有它的缺陷:就是说不能够把每一个品牌下面的,商品的数量保存下来,同时也会有一些无用的数据,掺杂其中。
228     //RETURN:Array ( [0] => Array ( [brand_id] => 1 [brand_name] => 全部 [goods_num] => 3 [url] => category.php?id=3&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [1] => Array ( [brand_id] => 2 [brand_name] => 诺基亚 [goods_num] => 1 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) [2] => Array ( [brand_id] => 3 [brand_name] => 摩托罗拉 [goods_num] => 1 [url] => category.php?id=3&brand=2&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [3] => Array ( [brand_id] => 4 [brand_name] => 多普达 [goods_num] => 2 [url] => category.php?id=3&brand=3&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [4] => Array ( [brand_id] => 5 [brand_name] => 飞利浦 [goods_num] => 1 [url] => category.php?id=3&brand=4&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [5] => Array ( [brand_id] => 6 [brand_name] => 夏新 [goods_num] => 2 [url] => category.php?id=3&brand=5&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [6] => Array ( [brand_id] => 7 [brand_name] => 三星 [goods_num] => 1 [url] => category.php?id=3&brand=6&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [7] => Array ( [brand_id] => 9 [brand_name] => 索爱 [goods_num] => 1 [url] => category.php?id=3&brand=7&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [8] => Array ( [brand_id] => 10 [brand_name] => 联想 [goods_num] => 1 [url] => category.php?id=3&brand=9&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [9] => Array ( [brand_name] => 金立 [url] => category.php?id=3&brand=10&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) )
229     foreach ($brands AS $key => $val) {
230         $temp_key = $key + 1;
231         $brands[$temp_key][‘brand_name‘] = $val[‘brand_name‘];
232         $brands[$temp_key][‘url‘] = build_uri(‘category‘, array(‘cid‘ => $cat_id, ‘bid‘ => $val[‘brand_id‘], ‘price_min‘=>$price_min, ‘price_max‘=> $price_max, ‘filter_attr‘=>$filter_attr_str), $cat[‘cat_name‘]);
233         /* 判断品牌是否被选中 */
234         if ($brand == $brands[$key][‘brand_id‘]) {
235             $brands[$temp_key][‘selected‘] = 1;
236         } else {
237             $brands[$temp_key][‘selected‘] = 0;
238         }
239     }
240     //补充一个选择全部品牌的数组
241     $brands[0][‘brand_name‘] = $_LANG[‘all_attribute‘];
242     $brands[0][‘url‘] = build_uri(‘category‘, array(‘cid‘ => $cat_id, ‘bid‘ => 0, ‘price_min‘=>$price_min, ‘price_max‘=> $price_max, ‘filter_attr‘=>$filter_attr_str), $cat[‘cat_name‘]);
243     $brands[0][‘selected‘] = empty($brand) ? 1 : 0;
244     //把品牌数组注入模板
245     $smarty->assign(‘brands‘, $brands);
246     ///<<==================结束---商品品牌处理==================<<///
247
248
249
250     ///>>==================开始---商品属性处理==================>>///
251     /* 属性筛选 */
252     $ext = ‘‘; //商品查询条件扩展
253     if ($cat[‘filter_attr‘] > 0) {
254         //===>需要筛选的属性,是人工在后台添加的,存放在ecs_category 表的中 filter_attr字段里面,格式如:185,189,120,190
255         //===>RETURN:Array ( [0] => 185 [1] => 189 [2] => 173 [3] => 178 )
256         $cat_filter_attr = explode(‘,‘, $cat[‘filter_attr‘]);       //提取出此分类的筛选属性
257
258         //===> 然后,对每一个属性(此属性是主属性,下面还有子属性),循环进行操作
259         //===> ①获取该属性的属性名
260         //===> ②获取该属性的所有子属性(子属性必须是有被商品在使用的,不然,不要将其显示出来)
261         //===> 意义:因为该属性涉及到搜索参数,如果该属性下本身没有商品,那么就没有显示出来的意义了。
262         //===> RETURN: Array ( [0] => Array ( [attr_id] => 185 [goods_id] => 167 [attr_value] => 灰色 ) [1] => Array ( [attr_id] => 185 [goods_id] => 198 [attr_value] => 白色 ) [2] => Array ( [attr_id] => 185 [goods_id] => 197 [attr_value] => 金色 ) [3] => Array ( [attr_id] => 185 [goods_id] => 163 [attr_value] => 黑色 ) )
263         $all_attr_list = array();
264         foreach ($cat_filter_attr AS $key => $value) {
265             $sql = "SELECT a.attr_name FROM " . $ecs->table(‘attribute‘) . " AS a, " . $ecs->table(‘goods_attr‘) . " AS ga, " . $ecs->table(‘goods‘) . " AS g WHERE ($children OR " . get_extension_goods($children) . ") AND a.attr_id = ga.attr_id AND g.goods_id = ga.goods_id AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 AND a.attr_id=‘$value‘";
266             if($temp_name = $db->getOne($sql)) {
267                 //获取该属性名(主属性)
268                 $all_attr_list[$key][‘filter_attr_name‘] = $temp_name;
269
270                 //获取该属性的所有子属性(子属性必须是有被商品在使用的,不然,不要将其显示出来)
271                 //RETURN: Array ( [0] => Array ( [attr_id] => 185 [goods_id] => 167 [attr_value] => 灰色 ) [1] => Array ( [attr_id] => 185 [goods_id] => 198 [attr_value] => 白色 ) [2] => Array ( [attr_id] => 185 [goods_id] => 197 [attr_value] => 金色 ) [3] => Array ( [attr_id] => 185 [goods_id] => 163 [attr_value] => 黑色 ) )
272                 $sql = "SELECT a.attr_id, MIN(a.goods_attr_id ) AS goods_id, a.attr_value AS attr_value FROM " . $ecs->table(‘goods_attr‘) . " AS a, " . $ecs->table(‘goods‘) .
273                 " AS g" .
274                 " WHERE ($children OR " . get_extension_goods($children) . ‘) AND g.goods_id = a.goods_id AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 ‘.
275                 " AND a.attr_id=‘$value‘ ".
276                 " GROUP BY a.attr_value";
277                 $attr_list = $db->getAll($sql);
278
279                 //如果后台指定该分类下,用于搜索的属性的组数,是跟地址栏中filter_attr=0.0.0.0  中0的个数是一样的,而且顺序都是一样的
280                 //第一个0,表示第一组属性中,它选择了哪一个子属性,以此类推
281                 //获取当前url中已选择属性的值,并保留在数组中
282                 //!这里要作循环,是因为避免属性为0或者空时,导致出错,因为直接把$filter_attr 赋值给 $temp_arrt_url_arr会出错。
283                 //RETURN:Array ( [0] => 163 [1] => 216 [2] => 160 [3] => 186 )
284                 $temp_arrt_url_arr = array();
285                 for ($i = 0; $i < count($cat_filter_attr); $i++) {
286                     $temp_arrt_url_arr[$i] = !empty($filter_attr[$i]) ? $filter_attr[$i] : 0;
287                 }
288
289                 //这里是该属性下,选择全部时的数组形式
290                 //哪一个属性的值为0,即说明用户选择的是该属性的全部选项
291                 //为“全部”生成url
292                 //DATA:Array ( [0] => 0 [1] => 216 [2] => 160 [3] => 186 )
293                 $temp_arrt_url_arr[$key] = 0;    //“全部”的信息生成
294                 $temp_arrt_url = implode(‘.‘, $temp_arrt_url_arr);
295                 $all_attr_list[$key][‘attr_list‘][0][‘attr_value‘] = $_LANG[‘all_attribute‘];
296                 $all_attr_list[$key][‘attr_list‘][0][‘url‘] = build_uri(‘category‘, array(‘cid‘=>$cat_id, ‘bid‘=>$brand, ‘price_min‘=>$price_min, ‘price_max‘=>$price_max, ‘filter_attr‘=>$temp_arrt_url), $cat[‘cat_name‘]);
297                 $all_attr_list[$key][‘attr_list‘][0][‘selected‘] = empty($filter_attr[$key]) ? 1 : 0;
298
299                 //循环计算子属性的相关数组:属性值,属性是否选择,属性的url
300                 //判断当前子属性,是否被选中状态
301                 //RETURN:Array ( [0] => Array ( [filter_attr_name] => 颜色 [attr_list] => Array ( [0] => Array ( [attr_value] => 全部 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=0.216.160.186 [selected] => 0 ) [1] => Array ( [attr_value] => 灰色 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=167.216.160.186 [selected] => 0 ) [2] => Array ( [attr_value] => 白色 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=198.216.160.186 [selected] => 0 ) [3] => Array ( [attr_value] => 金色 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=197.216.160.186 [selected] => 0 ) [4] => Array ( [attr_value] => 黑色 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) ) ) [1] => Array ( [filter_attr_name] => 屏幕大小 [attr_list] => Array ( [0] => Array ( [attr_value] => 全部 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.0.160.186 [selected] => 0 ) [1] => Array ( [attr_value] => 1.75英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.229.160.186 [selected] => 0 ) [2] => Array ( [attr_value] => 2.0英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) [3] => Array ( [attr_value] => 2.2英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.223.160.186 [selected] => 0 ) [4] => Array ( [attr_value] => 2.6英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.156.160.186 [selected] => 0 ) [5] => Array ( [attr_value] => 2.8英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.200.160.186 [selected] => 0 ) ) ) [2] => Array ( [filter_attr_name] => 手机制式 [attr_list] => Array ( [0] => Array ( [attr_value] => 全部 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.0.186 [selected] => 0 ) [1] => Array ( [attr_value] => CDMA [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.202.186 [selected] => 0 ) [2] => Array ( [attr_value] => GSM,850,900,1800,1900 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) [3] => Array ( [attr_value] => GSM,900,1800,1900,2100 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.195.186 [selected] => 0 ) ) ) [3] => Array ( [filter_attr_name] => 外观样式 [attr_list] => Array ( [0] => Array ( [attr_value] => 全部 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.0 [selected] => 0 ) [1] => Array ( [attr_value] => 滑盖 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.199 [selected] => 0 ) [2] => Array ( [attr_value] => 直板 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) ) ) )
302                 foreach ($attr_list as $k => $v) {
303                     $temp_key = $k + 1;
304                     $temp_arrt_url_arr[$key] = $v[‘goods_id‘];       //为url中代表当前筛选属性的位置变量赋值,并生成以‘.’分隔的筛选属性字符串
305                     $temp_arrt_url = implode(‘.‘, $temp_arrt_url_arr);
306
307                     $all_attr_list[$key][‘attr_list‘][$temp_key][‘attr_value‘] = $v[‘attr_value‘];
308                     $all_attr_list[$key][‘attr_list‘][$temp_key][‘url‘] = build_uri(‘category‘, array(‘cid‘=>$cat_id, ‘bid‘=>$brand, ‘price_min‘=>$price_min, ‘price_max‘=>$price_max, ‘filter_attr‘=>$temp_arrt_url), $cat[‘cat_name‘]);
309
310                     if (!empty($filter_attr[$key]) AND $filter_attr[$key] == $v[‘goods_id‘]) { //处理已被选择的子属性
311                         $all_attr_list[$key][‘attr_list‘][$temp_key][‘selected‘] = 1;
312                     }
313                     else {
314                         $all_attr_list[$key][‘attr_list‘][$temp_key][‘selected‘] = 0;
315                     }
316                 }
317             }
318         }
319         //为模板注入变量
320         $smarty->assign(‘filter_attr_list‘,  $all_attr_list);
321
322
323         /* 扩展商品查询条件 */
324         if (!empty($filter_attr)) {
325             $ext_sql = "SELECT DISTINCT(b.goods_id) FROM " . $ecs->table(‘goods_attr‘) . " AS a, " . $ecs->table(‘goods_attr‘) . " AS b " .  "WHERE ";
326             $ext_group_goods = array();
327             foreach ($filter_attr AS $k => $v) { // 查出符合所有筛选属性条件的商品id */
328                 if (is_numeric($v) && $v !=0 ) {
329                     $sql = $ext_sql . "b.attr_value = a.attr_value AND b.attr_id = " . $cat_filter_attr[$k] ." AND a.goods_attr_id = " . $v;
330                     $ext_group_goods = $db->getColCached($sql);
331                     $ext .= ‘ AND ‘ . db_create_in($ext_group_goods, ‘g.goods_id‘);
332                 }
333             }
334         }
335     }
336     ///<<==================结束---商品属性处理==================///
337
338     //向模板,载入一些前台,必备的变量和常量
339     assign_template(‘c‘, array($cat_id));
340
341     //RETURN:Array ( [title] => 夏新_GSM手机_手机类型_ECSHOP演示站 - Powered by ECShop [ur_here] => 首页 > 手机类型 > GSM手机 > 夏新 )
342     $position = assign_ur_here($cat_id, $brand_name);
343
344     $smarty->assign(‘page_title‘,       $position[‘title‘]);    // 页面标题
345     $smarty->assign(‘ur_here‘,          $position[‘ur_here‘]);  // 当前位置
346
347     $smarty->assign(‘categories‘,       get_categories_tree($cat_id)); // 分类树
348     $smarty->assign(‘helps‘,            get_shop_help());              // 网店帮助
349     $smarty->assign(‘top_goods‘,        get_top10());                  // 销售排行
350     $smarty->assign(‘show_marketprice‘, $_CFG[‘show_marketprice‘]); //是否显示市场价
351     $smarty->assign(‘category‘,         $cat_id);
352     $smarty->assign(‘brand_id‘,         $brand);
353     $smarty->assign(‘price_max‘,        $price_max);
354     $smarty->assign(‘price_min‘,        $price_min);
355     $smarty->assign(‘filter_attr‘,      $filter_attr_str);
356     $smarty->assign(‘feed_url‘,         ($_CFG[‘rewrite‘] == 1) ? "feed-c$cat_id.xml" : ‘feed.php?cat=‘ . $cat_id); // RSS URL
357
358     if ($brand > 0) {
359         $arr[‘all‘] = array(‘brand_id‘  => 0,
360                 ‘brand_name‘    => $GLOBALS[‘_LANG‘][‘all_goods‘],
361                 ‘brand_logo‘    => ‘‘,
362                 ‘goods_num‘     => ‘‘,
363                 ‘url‘           => build_uri(‘category‘, array(‘cid‘=>$cat_id), $cat[‘cat_name‘])
364         );
365     } else {
366         $arr = array();
367     }
368
369     $brand_list = array_merge($arr, get_brands($cat_id, ‘category‘));
370     $smarty->assign(‘data_dir‘,    DATA_DIR); //网站data目录
371     $smarty->assign(‘brand_list‘,      $brand_list);
372     $smarty->assign(‘promotion_info‘, get_promotion_info()); //获取推荐信息
373
374     /* 调查 */
375     $vote = get_vote();
376     if (!empty($vote)) {
377         $smarty->assign(‘vote_id‘,     $vote[‘id‘]);
378         $smarty->assign(‘vote‘,        $vote[‘content‘]);
379     }
380
381     //获取最热销、推荐和最热卖商品
382     $smarty->assign(‘best_goods‘,      get_category_recommend_goods(‘best‘, $children, $brand, $price_min, $price_max, $ext));
383     $smarty->assign(‘promotion_goods‘, get_category_recommend_goods(‘promote‘, $children, $brand, $price_min, $price_max, $ext));
384     $smarty->assign(‘hot_goods‘,       get_category_recommend_goods(‘hot‘, $children, $brand, $price_min, $price_max, $ext));
385     //获取该前状态下,商品的数量
386     $count = get_cagtegory_goods_count($children, $brand, $price_min, $price_max, $ext);
387     //最大页数
388     $max_page = ($count> 0) ? ceil($count / $size) : 1;
389     if ($page > $max_page) {
390         $page = $max_page;
391     }
392
393     //获取该栏目下的所有商品
394     $goodslist = category_get_goods($children, $brand, $price_min, $price_max, $ext, $size, $page, $sort, $order);
395
396     //判断选择了列表还是图片方式显示方式
397     if($display == ‘grid‘) {
398         if(count($goodslist) % 2 != 0) {
399             $goodslist[] = array();
400         }
401     }
402
403     $smarty->assign(‘goods_list‘,       $goodslist); //注入商品列表
404     $smarty->assign(‘category‘,         $cat_id); //注入分类id
405     $smarty->assign(‘script_name‘, ‘category‘); //注入该脚本的名称
406
407     assign_pager(‘category‘,            $cat_id, $count, $size, $sort, $order, $page, ‘‘, $brand, $price_min, $price_max, $display, $filter_attr_str); // 分页
408     assign_dynamic(‘category‘); // 动态内容
409 }
410 $smarty->display(‘category.dwt‘, $cache_id);
411 ?>

查看category.php全部代码

2.分步分析其实现过程:

1)第一步,首先,文件一开头,一定是接收前台页面发送过来的各种POST和GET参数了,这里主要还是指地址栏GET方式传过来的参数了。

 1 //====> 2.首先获取所有GET和POST中,可用于搜索的参数的值。
 2 //====> 若没有此参数,则说明,并没有用此参数来搜索,默认要给它一个默认值。
 3 /* 初始化分页信息 */
 4 $page = isset($_REQUEST[‘page‘])   && intval($_REQUEST[‘page‘])  > 0 ? intval($_REQUEST[‘page‘])  : 1;
 5 $size = isset($_CFG[‘page_size‘])  && intval($_CFG[‘page_size‘]) > 0 ? intval($_CFG[‘page_size‘]) : 10;
 6 $brand = isset($_REQUEST[‘brand‘]) && intval($_REQUEST[‘brand‘]) > 0 ? intval($_REQUEST[‘brand‘]) : 0;
 7 $price_max = isset($_REQUEST[‘price_max‘]) && intval($_REQUEST[‘price_max‘]) > 0 ? intval($_REQUEST[‘price_max‘]) : 0;
 8 $price_min = isset($_REQUEST[‘price_min‘]) && intval($_REQUEST[‘price_min‘]) > 0 ? intval($_REQUEST[‘price_min‘]) : 0;
 9 $filter_attr_str = isset($_REQUEST[‘filter_attr‘]) ? htmlspecialchars(trim($_REQUEST[‘filter_attr‘])) : ‘0‘;
10 $filter_attr_str = urldecode($filter_attr_str);
11 $filter_attr = empty($filter_attr_str) ? ‘‘ : explode(‘.‘, trim($filter_attr_str));
12
13 /* 排序、显示方式以及类型 */
14 $default_display_type = $_CFG[‘show_order_type‘] == ‘0‘ ? ‘list‘ : ($_CFG[‘show_order_type‘] == ‘1‘ ? ‘grid‘ : ‘text‘);
15 $default_sort_order_method = $_CFG[‘sort_order_method‘] == ‘0‘ ? ‘DESC‘ : ‘ASC‘;
16 $default_sort_order_type   = $_CFG[‘sort_order_type‘] == ‘0‘ ? ‘goods_id‘ : ($_CFG[‘sort_order_type‘] == ‘1‘ ? ‘shop_price‘ : ‘last_update‘);
17
18 $sort  = (isset($_REQUEST[‘sort‘])  && in_array(trim(strtolower($_REQUEST[‘sort‘])), array(‘goods_id‘, ‘shop_price‘, ‘last_update‘))) ? trim($_REQUEST[‘sort‘])  : $default_sort_order_type;
19 $order = (isset($_REQUEST[‘order‘]) && in_array(trim(strtoupper($_REQUEST[‘order‘])), array(‘ASC‘, ‘DESC‘)))                              ? trim($_REQUEST[‘order‘]) : $default_sort_order_method;
20 $display  = (isset($_REQUEST[‘display‘]) && in_array(trim(strtolower($_REQUEST[‘display‘])), array(‘list‘, ‘grid‘, ‘text‘))) ? trim($_REQUEST[‘display‘])  : (isset($_COOKIE[‘ECS‘][‘display‘]) ? $_COOKIE[‘ECS‘][‘display‘] : $default_display_type);
21 $display  = in_array($display, array(‘list‘, ‘grid‘, ‘text‘)) ? $display : ‘text‘;
22 setcookie(‘ECS[display]‘, $display, gmtime() + 86400 * 7);

2)第二步,处理商品分类参数,并获取该分类的详细信息:

 1 //====> 3.把该栏目下的所有子栏目id获取,如果没有子栏目,则是自身。
 2 //===> TABLE:ecs_category
 3 //====> RETURN:id=3 => g.cat_id IN (‘3‘)  或 id=6 => g.cat_id IN (‘6‘,‘8‘,‘9‘,‘11‘,‘7‘)
 4 //====> 说明:ecshop的特点是,顶级栏目下也可以添加商品,所以会把顶级栏目id也放在数组里面
 5 $children = get_children($cat_id);
 6
 7 //====> 4.获得该分类的相关信息。如:分类名称、价格分级、筛选属性、父id
 8 //===> TABLE:ecs_category
 9 //====> RETURN:Array ( [cat_name] => GSM手机 [keywords] => [cat_desc] => [style] => [grade] => 4 [filter_attr] => 185,189,173,178 [parent_id] => 1 )
10 $cat = get_cat_info($cat_id);   

3)第三步,处理价格,并对商品价格进行区间的划分:

  1 ///>>================开始---商品价格区间处理==================>>///
  2 //===> 6.获取该分类cat的价格分级:
  3 //===> ①如果价格分级=0,那么获取直接父类的价格分级。(Ⅰ如果父类价格也=0,那么就是不用价格分级 )
  4 //===> ②如果价格分级!=0,那么就是自身的价格分级。
  5 //===> TABLE:ecs_category
  6 //===> RETURN:$cat[‘grade‘]=4
  7 /* 获取价格分级 */
  8 if ($cat[‘grade‘] == 0  && $cat[‘parent_id‘] != 0) { //  ==>如果价格分级为空,但是它还有上级分类,那么取直接上级的价格分级等数
  9     $cat[‘grade‘] = get_parent_grade($cat_id); //如果当前分类级别为空,取最近的上级分类
 10 }
 11
 12 //===> 7.对价格区间进行划分。 ecshop的划分方法,是根据算法来的,比较复杂。
 13 //===> 如果价格分级>1,那么就执行价格区间划分
 14 if ($cat[‘grade‘] > 1) {
 15     /* 需要价格分级 */
 16
 17     /*
 18      算法思路:
 19     1、当分级大于1时,进行价格分级
 20     2、取出该类下商品价格的最大值、最小值
 21     3、根据商品价格的最大值来计算商品价格的分级数量级:
 22     价格范围(不含最大值)    分级数量级
 23     0-0.1                   0.001
 24     0.1-1                   0.01
 25     1-10                    0.1
 26     10-100                  1
 27     100-1000                10
 28     1000-10000              100
 29     4、计算价格跨度:
 30     取整((最大值-最小值) / (价格分级数) / 数量级) * 数量级
 31     5、根据价格跨度计算价格范围区间
 32     6、查询数据库
 33
 34     可能存在问题:
 35     1、
 36     由于价格跨度是由最大值、最小值计算出来的
 37     然后再通过价格跨度来确定显示时的价格范围区间
 38     所以可能会存在价格分级数量不正确的问题
 39     该问题没有证明
 40     2、
 41     当价格=最大值时,分级会多出来,已被证明存在
 42     */
 43
 44     //===> 获得当前分类下商品价格的最大值、最小值
 45     //===> 获得所有扩展分类属于指定分类的所有商品ID ,其中goods_id = 16的商品的扩展属于分类3
 46     //===> TABLE:ecs_goods 和 ecs_goods_cat
 47     //===> SQL:SELECT min(g.shop_price) AS min, max(g.shop_price) as max FROM `ecshop`.`ecs_goods` AS g WHERE (g.cat_id IN (‘5‘) OR g.goods_id IN (‘8‘,‘16‘) ) AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1
 48     //===> RETURN:Array ( [min] => 280.00 [max] => 5999.00 )
 49     $sql = "SELECT min(g.shop_price) AS min, max(g.shop_price) as max ".
 50             " FROM " . $ecs->table(‘goods‘). " AS g ".
 51             " WHERE ($children OR " . get_extension_goods($children) . ‘) AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1  ‘;
 52     $row = $db->getRow($sql);
 53
 54
 55     //===> 按照公式计算出最低价格和最高价格、以及价格跨度
 56     //===============↓↓↓先不做讨论===============
 57     // 取得价格分级最小单位级数,比如,千元商品最小以100为级数
 58     $price_grade = 0.0001;
 59     for($i=-2; $i<= log10($row[‘max‘]); $i++) {
 60         $price_grade *= 10;
 61     }
 62
 63     //价格跨度
 64     $dx = ceil(($row[‘max‘] - $row[‘min‘]) / ($cat[‘grade‘]) / $price_grade) * $price_grade;
 65     if($dx == 0) {
 66         $dx = $price_grade;
 67     }
 68
 69     for($i = 1; $row[‘min‘] > $dx * $i; $i ++);
 70
 71         for($j = 1; $row[‘min‘] > $dx * ($i-1) + $price_grade * $j; $j++);
 72         $row[‘min‘] = $dx * ($i-1) + $price_grade * ($j - 1);
 73
 74         for(; $row[‘max‘] >= $dx * $i; $i ++);
 75         $row[‘max‘] = $dx * ($i) + $price_grade * ($j - 1);
 76
 77         //===>这里打印最高价格和最低价格:$row=>Array ( [min] => 200 [max] => 6200 )
 78         //===>这里打印价格跨度:$dx = 1500
 79
 80         //===============先不做讨论↑↑↑==================//
 81
 82
 83         //===> 根据商品的价格、价格区间的最低价格、以及价格跨度,计算该商品价格属于哪一个区间内。
 84         //===> 获取属于该价格区间内的商品的数量、获取sn则属于哪一个区间sn=0为200-1700、sn=1为1700-3200、sn=3为4700-6200。
 85         //===> 因为没有商品价格属于第二区间,则不存在sn=2,那么3200-4700则没有任何商品
 86         //===> TABLE:ecs_goods 和 ecs_goods_cat
 87         //===> SQL:SELECT (FLOOR((g.shop_price - 200) / 1500)) AS sn, COUNT(*) AS goods_num FROM `ecshop`.`ecs_goods` AS g WHERE (g.cat_id IN (‘3‘) OR g.goods_id IN (‘16‘) ) AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 GROUP BY sn
 88         //===>RETURN:Array ( [0] => Array ( [sn] => 0 [goods_num] => 6 ) [1] => Array ( [sn] => 1 [goods_num] => 5 ) [2] => Array ( [sn] => 3 [goods_num] => 1 ) )
 89         $sql = "SELECT (FLOOR((g.shop_price - $row[min]) / $dx)) AS sn, COUNT(*) AS goods_num  ".
 90                 " FROM " . $ecs->table(‘goods‘) . " AS g ".
 91                 " WHERE ($children OR " . get_extension_goods($children) . ‘) AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 ‘.
 92                 " GROUP BY sn ";
 93         $price_grade = $db->getAll($sql);
 94
 95
 96         //===> 根据价格等级price_grade,计算真正的价格区间。
 97         //===> 方法build_uri()重要:要为每一个价格区间,生成一个url超链接,以备前台点击搜索用
 98         //===> 并根据价格参数,判断该区间,是否是当前被搜索的区间
 99         //===> 把价格区间,注入模板,供前台使用
100         //===> RETURN:Array ( [0] => Array ( [sn] => 0 [goods_num] => 6 [start] => 0 [end] => 0 [price_range] => 全部 [url] => category.php?id=3&brand=1&price_min=0&price_max=0&filter_attr=163.216.160.186 [selected] => 0 ) [1] => Array ( [sn] => 1 [goods_num] => 6 [start] => 200 [end] => 1700 [price_range] => 200 - 1700 [formated_start] => ¥200元 [formated_end] => ¥1700元 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) [2] => Array ( [sn] => 3 [goods_num] => 5 [start] => 1700 [end] => 3200 [price_range] => 1700 - 3200 [formated_start] => ¥1700元 [formated_end] => ¥3200元 [url] => category.php?id=3&brand=1&price_min=1700&price_max=3200&filter_attr=163.216.160.186 [selected] => 0 ) [3] => Array ( [goods_num] => 1 [start] => 4700 [end] => 6200 [price_range] => 4700 - 6200 [formated_start] => ¥4700元 [formated_end] => ¥6200元 [url] => category.php?id=3&brand=1&price_min=4700&price_max=6200&filter_attr=163.216.160.186 [selected] => 0 ) )
101         foreach ($price_grade as $key=>$val) {
102             $temp_key = $key + 1;
103             $price_grade[$temp_key][‘goods_num‘] = $val[‘goods_num‘];
104             $price_grade[$temp_key][‘start‘] = $row[‘min‘] + round($dx * $val[‘sn‘]);
105             $price_grade[$temp_key][‘end‘] = $row[‘min‘] + round($dx * ($val[‘sn‘] + 1));
106             $price_grade[$temp_key][‘price_range‘] = $price_grade[$temp_key][‘start‘] . ‘&nbsp;-&nbsp;‘ . $price_grade[$temp_key][‘end‘];
107             $price_grade[$temp_key][‘formated_start‘] = price_format($price_grade[$temp_key][‘start‘]);
108             $price_grade[$temp_key][‘formated_end‘] = price_format($price_grade[$temp_key][‘end‘]);
109             $price_grade[$temp_key][‘url‘] = build_uri(‘category‘, array(‘cid‘=>$cat_id, ‘bid‘=>$brand, ‘price_min‘=>$price_grade[$temp_key][‘start‘], ‘price_max‘=> $price_grade[$temp_key][‘end‘], ‘filter_attr‘=>$filter_attr_str), $cat[‘cat_name‘]);
110             /* 判断价格区间是否被选中 */
111             if (isset($_REQUEST[‘price_min‘]) && $price_grade[$temp_key][‘start‘] == $price_min && $price_grade[$temp_key][‘end‘] == $price_max) {
112                 $price_grade[$temp_key][‘selected‘] = 1;
113             }
114             else {
115                 $price_grade[$temp_key][‘selected‘] = 0;
116             }
117         }
118         //补充一个选择全部的类型的数组
119         $price_grade[0][‘start‘] = 0;
120         $price_grade[0][‘end‘] = 0;
121         $price_grade[0][‘price_range‘] = $_LANG[‘all_attribute‘];
122         $price_grade[0][‘url‘] = build_uri(‘category‘, array(‘cid‘=>$cat_id, ‘bid‘=>$brand, ‘price_min‘=>0, ‘price_max‘=> 0, ‘filter_attr‘=>$filter_attr_str), $cat[‘cat_name‘]);
123         $price_grade[0][‘selected‘] = empty($price_max) ? 1 : 0;
124         //把价格区间数组,注入模板文件
125         $smarty->assign(‘price_grade‘,     $price_grade);
126     }
127     ///<<================结束---商品价格区间处理==================<<///
128     

4)第四步,处理品牌,并为每一个品牌生成url。

 1 ///>>================开始---商品品牌处理==================>>///
 2     //====> ???db_create_in(array_unique(array_merge(array($cat_id), array_keys(cat_list($cat_id, 0, false))))) . ")
 3     //===> 品牌筛选功能:把该栏目下(其中包括扩展分类下的商品),所有商品的品牌获取,但不能重复。
 4     //===> 品牌下有商品并且商品状态正常,才能把该品牌取出。没有商品的品牌不能取出
 5     //===> TABLE:ecs_brand、ecs_goods 和 ecs_goods_cat
 6     //===> SQL:SELECT b.brand_id, b.brand_name, COUNT(*) AS goods_num FROM `ecshop`.`ecs_brand`AS b, `ecshop`.`ecs_goods` AS g LEFT JOIN `ecshop`.`ecs_goods_cat` AS gc ON g.goods_id = gc.goods_id WHERE g.brand_id = b.brand_id AND (g.cat_id IN (‘3‘) OR gc.cat_id IN (‘3‘) ) AND b.is_show = 1 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 AND g.is_delete = 0 GROUP BY b.brand_id HAVING goods_num > 0 ORDER BY b.sort_order, b.brand_id ASC
 7     //===> RETURN:Array ( [0] => Array ( [brand_id] => 1 [brand_name] => 诺基亚 [goods_num] => 3 ) [1] => Array ( [brand_id] => 2 [brand_name] => 摩托罗拉 [goods_num] => 1 ) [2] => Array ( [brand_id] => 3 [brand_name] => 多普达 [goods_num] => 1 ) [3] => Array ( [brand_id] => 4 [brand_name] => 飞利浦 [goods_num] => 2 ) [4] => Array ( [brand_id] => 5 [brand_name] => 夏新 [goods_num] => 1 ) [5] => Array ( [brand_id] => 6 [brand_name] => 三星 [goods_num] => 2 ) [6] => Array ( [brand_id] => 7 [brand_name] => 索爱 [goods_num] => 1 ) [7] => Array ( [brand_id] => 9 [brand_name] => 联想 [goods_num] => 1 ) [8] => Array ( [brand_id] => 10 [brand_name] => 金立 [goods_num] => 1 ) )
 8     /* 品牌筛选 */
 9     $sql = "SELECT b.brand_id, b.brand_name, COUNT(*) AS goods_num ".
10             "FROM " . $GLOBALS[‘ecs‘]->table(‘brand‘) . "AS b, ".
11             $GLOBALS[‘ecs‘]->table(‘goods‘) . " AS g LEFT JOIN ". $GLOBALS[‘ecs‘]->table(‘goods_cat‘) . " AS gc ON g.goods_id = gc.goods_id " .
12             "WHERE g.brand_id = b.brand_id AND ($children OR " . ‘gc.cat_id ‘ . db_create_in(array_unique(array_merge(array($cat_id), array_keys(cat_list($cat_id, 0, false))))) . ") AND b.is_show = 1 " .
13             " AND g.is_on_sale = 1 AND g.is_alone_sale = 1 AND g.is_delete = 0 ".
14             "GROUP BY b.brand_id HAVING goods_num > 0 ORDER BY b.sort_order, b.brand_id ASC";
15     $brands = $GLOBALS[‘db‘]->getAll($sql);
16
17     //===> 把该分类下所有商品的品牌,组合成数组,给前台调用
18     //===> 方法build_uri()重要:要为每品牌,生成一个url超链接,以备前台点击搜索用
19     //===> 把数组注入模板文件
20     //====! 这样一种组织数组的方式,有它的缺陷:就是说不能够把每一个品牌下面的,商品的数量保存下来,同时也会有一些无用的数据,掺杂其中。
21     //RETURN:Array ( [0] => Array ( [brand_id] => 1 [brand_name] => 全部 [goods_num] => 3 [url] => category.php?id=3&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [1] => Array ( [brand_id] => 2 [brand_name] => 诺基亚 [goods_num] => 1 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) [2] => Array ( [brand_id] => 3 [brand_name] => 摩托罗拉 [goods_num] => 1 [url] => category.php?id=3&brand=2&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [3] => Array ( [brand_id] => 4 [brand_name] => 多普达 [goods_num] => 2 [url] => category.php?id=3&brand=3&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [4] => Array ( [brand_id] => 5 [brand_name] => 飞利浦 [goods_num] => 1 [url] => category.php?id=3&brand=4&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [5] => Array ( [brand_id] => 6 [brand_name] => 夏新 [goods_num] => 2 [url] => category.php?id=3&brand=5&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [6] => Array ( [brand_id] => 7 [brand_name] => 三星 [goods_num] => 1 [url] => category.php?id=3&brand=6&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [7] => Array ( [brand_id] => 9 [brand_name] => 索爱 [goods_num] => 1 [url] => category.php?id=3&brand=7&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [8] => Array ( [brand_id] => 10 [brand_name] => 联想 [goods_num] => 1 [url] => category.php?id=3&brand=9&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) [9] => Array ( [brand_name] => 金立 [url] => category.php?id=3&brand=10&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 0 ) )
22     foreach ($brands AS $key => $val) {
23         $temp_key = $key + 1;
24         $brands[$temp_key][‘brand_name‘] = $val[‘brand_name‘];
25         $brands[$temp_key][‘url‘] = build_uri(‘category‘, array(‘cid‘ => $cat_id, ‘bid‘ => $val[‘brand_id‘], ‘price_min‘=>$price_min, ‘price_max‘=> $price_max, ‘filter_attr‘=>$filter_attr_str), $cat[‘cat_name‘]);
26         /* 判断品牌是否被选中 */
27         if ($brand == $brands[$key][‘brand_id‘]) {
28             $brands[$temp_key][‘selected‘] = 1;
29         } else {
30             $brands[$temp_key][‘selected‘] = 0;
31         }
32     }
33     //补充一个选择全部品牌的数组
34     $brands[0][‘brand_name‘] = $_LANG[‘all_attribute‘];
35     $brands[0][‘url‘] = build_uri(‘category‘, array(‘cid‘ => $cat_id, ‘bid‘ => 0, ‘price_min‘=>$price_min, ‘price_max‘=> $price_max, ‘filter_attr‘=>$filter_attr_str), $cat[‘cat_name‘]);
36     $brands[0][‘selected‘] = empty($brand) ? 1 : 0;
37     //把品牌数组注入模板
38     $smarty->assign(‘brands‘, $brands);
39     ///<<==================结束---商品品牌处理==================<<///

5)第五步,处理商品的属性,并为每一个属性生成url。

 1 ///>>==================开始---商品属性处理==================>>///
 2     /* 属性筛选 */
 3     $ext = ‘‘; //商品查询条件扩展
 4     if ($cat[‘filter_attr‘] > 0) {
 5         //===>需要筛选的属性,是人工在后台添加的,存放在ecs_category 表的中 filter_attr字段里面,格式如:185,189,120,190
 6         //===>RETURN:Array ( [0] => 185 [1] => 189 [2] => 173 [3] => 178 )
 7         $cat_filter_attr = explode(‘,‘, $cat[‘filter_attr‘]);       //提取出此分类的筛选属性
 8
 9         //===> 然后,对每一个属性(此属性是主属性,下面还有子属性),循环进行操作
10         //===> ①获取该属性的属性名
11         //===> ②获取该属性的所有子属性(子属性必须是有被商品在使用的,不然,不要将其显示出来)
12         //===> 意义:因为该属性涉及到搜索参数,如果该属性下本身没有商品,那么就没有显示出来的意义了。
13         //===> RETURN: Array ( [0] => Array ( [attr_id] => 185 [goods_id] => 167 [attr_value] => 灰色 ) [1] => Array ( [attr_id] => 185 [goods_id] => 198 [attr_value] => 白色 ) [2] => Array ( [attr_id] => 185 [goods_id] => 197 [attr_value] => 金色 ) [3] => Array ( [attr_id] => 185 [goods_id] => 163 [attr_value] => 黑色 ) )
14         $all_attr_list = array();
15         foreach ($cat_filter_attr AS $key => $value) {
16             $sql = "SELECT a.attr_name FROM " . $ecs->table(‘attribute‘) . " AS a, " . $ecs->table(‘goods_attr‘) . " AS ga, " . $ecs->table(‘goods‘) . " AS g WHERE ($children OR " . get_extension_goods($children) . ") AND a.attr_id = ga.attr_id AND g.goods_id = ga.goods_id AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 AND a.attr_id=‘$value‘";
17             if($temp_name = $db->getOne($sql)) {
18                 //获取该属性名(主属性)
19                 $all_attr_list[$key][‘filter_attr_name‘] = $temp_name;
20
21                 //获取该属性的所有子属性(子属性必须是有被商品在使用的,不然,不要将其显示出来)
22                 //RETURN: Array ( [0] => Array ( [attr_id] => 185 [goods_id] => 167 [attr_value] => 灰色 ) [1] => Array ( [attr_id] => 185 [goods_id] => 198 [attr_value] => 白色 ) [2] => Array ( [attr_id] => 185 [goods_id] => 197 [attr_value] => 金色 ) [3] => Array ( [attr_id] => 185 [goods_id] => 163 [attr_value] => 黑色 ) )
23                 $sql = "SELECT a.attr_id, MIN(a.goods_attr_id ) AS goods_id, a.attr_value AS attr_value FROM " . $ecs->table(‘goods_attr‘) . " AS a, " . $ecs->table(‘goods‘) .
24                 " AS g" .
25                 " WHERE ($children OR " . get_extension_goods($children) . ‘) AND g.goods_id = a.goods_id AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 ‘.
26                 " AND a.attr_id=‘$value‘ ".
27                 " GROUP BY a.attr_value";
28                 $attr_list = $db->getAll($sql);
29
30                 //如果后台指定该分类下,用于搜索的属性的组数,是跟地址栏中filter_attr=0.0.0.0  中0的个数是一样的,而且顺序都是一样的
31                 //第一个0,表示第一组属性中,它选择了哪一个子属性,以此类推
32                 //获取当前url中已选择属性的值,并保留在数组中
33                 //!这里要作循环,是因为避免属性为0或者空时,导致出错,因为直接把$filter_attr 赋值给 $temp_arrt_url_arr会出错。
34                 //RETURN:Array ( [0] => 163 [1] => 216 [2] => 160 [3] => 186 )
35                 $temp_arrt_url_arr = array();
36                 for ($i = 0; $i < count($cat_filter_attr); $i++) {
37                     $temp_arrt_url_arr[$i] = !empty($filter_attr[$i]) ? $filter_attr[$i] : 0;
38                 }
39
40                 //这里是该属性下,选择全部时的数组形式
41                 //哪一个属性的值为0,即说明用户选择的是该属性的全部选项
42                 //为“全部”生成url
43                 //DATA:Array ( [0] => 0 [1] => 216 [2] => 160 [3] => 186 )
44                 $temp_arrt_url_arr[$key] = 0;    //“全部”的信息生成
45                 $temp_arrt_url = implode(‘.‘, $temp_arrt_url_arr);
46                 $all_attr_list[$key][‘attr_list‘][0][‘attr_value‘] = $_LANG[‘all_attribute‘];
47                 $all_attr_list[$key][‘attr_list‘][0][‘url‘] = build_uri(‘category‘, array(‘cid‘=>$cat_id, ‘bid‘=>$brand, ‘price_min‘=>$price_min, ‘price_max‘=>$price_max, ‘filter_attr‘=>$temp_arrt_url), $cat[‘cat_name‘]);
48                 $all_attr_list[$key][‘attr_list‘][0][‘selected‘] = empty($filter_attr[$key]) ? 1 : 0;
49
50                 //循环计算子属性的相关数组:属性值,属性是否选择,属性的url
51                 //判断当前子属性,是否被选中状态
52                 //RETURN:Array ( [0] => Array ( [filter_attr_name] => 颜色 [attr_list] => Array ( [0] => Array ( [attr_value] => 全部 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=0.216.160.186 [selected] => 0 ) [1] => Array ( [attr_value] => 灰色 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=167.216.160.186 [selected] => 0 ) [2] => Array ( [attr_value] => 白色 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=198.216.160.186 [selected] => 0 ) [3] => Array ( [attr_value] => 金色 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=197.216.160.186 [selected] => 0 ) [4] => Array ( [attr_value] => 黑色 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) ) ) [1] => Array ( [filter_attr_name] => 屏幕大小 [attr_list] => Array ( [0] => Array ( [attr_value] => 全部 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.0.160.186 [selected] => 0 ) [1] => Array ( [attr_value] => 1.75英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.229.160.186 [selected] => 0 ) [2] => Array ( [attr_value] => 2.0英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) [3] => Array ( [attr_value] => 2.2英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.223.160.186 [selected] => 0 ) [4] => Array ( [attr_value] => 2.6英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.156.160.186 [selected] => 0 ) [5] => Array ( [attr_value] => 2.8英寸 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.200.160.186 [selected] => 0 ) ) ) [2] => Array ( [filter_attr_name] => 手机制式 [attr_list] => Array ( [0] => Array ( [attr_value] => 全部 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.0.186 [selected] => 0 ) [1] => Array ( [attr_value] => CDMA [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.202.186 [selected] => 0 ) [2] => Array ( [attr_value] => GSM,850,900,1800,1900 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) [3] => Array ( [attr_value] => GSM,900,1800,1900,2100 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.195.186 [selected] => 0 ) ) ) [3] => Array ( [filter_attr_name] => 外观样式 [attr_list] => Array ( [0] => Array ( [attr_value] => 全部 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.0 [selected] => 0 ) [1] => Array ( [attr_value] => 滑盖 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.199 [selected] => 0 ) [2] => Array ( [attr_value] => 直板 [url] => category.php?id=3&brand=1&price_min=200&price_max=1700&filter_attr=163.216.160.186 [selected] => 1 ) ) ) )
53                 foreach ($attr_list as $k => $v) {
54                     $temp_key = $k + 1;
55                     $temp_arrt_url_arr[$key] = $v[‘goods_id‘];       //为url中代表当前筛选属性的位置变量赋值,并生成以‘.’分隔的筛选属性字符串
56                     $temp_arrt_url = implode(‘.‘, $temp_arrt_url_arr);
57
58                     $all_attr_list[$key][‘attr_list‘][$temp_key][‘attr_value‘] = $v[‘attr_value‘];
59                     $all_attr_list[$key][‘attr_list‘][$temp_key][‘url‘] = build_uri(‘category‘, array(‘cid‘=>$cat_id, ‘bid‘=>$brand, ‘price_min‘=>$price_min, ‘price_max‘=>$price_max, ‘filter_attr‘=>$temp_arrt_url), $cat[‘cat_name‘]);
60
61                     if (!empty($filter_attr[$key]) AND $filter_attr[$key] == $v[‘goods_id‘]) { //处理已被选择的子属性
62                         $all_attr_list[$key][‘attr_list‘][$temp_key][‘selected‘] = 1;
63                     }
64                     else {
65                         $all_attr_list[$key][‘attr_list‘][$temp_key][‘selected‘] = 0;
66                     }
67                 }
68             }
69         }
70         //为模板注入变量
71         $smarty->assign(‘filter_attr_list‘,  $all_attr_list);
72
73
74         /* 扩展商品查询条件 */
75         if (!empty($filter_attr)) {
76             $ext_sql = "SELECT DISTINCT(b.goods_id) FROM " . $ecs->table(‘goods_attr‘) . " AS a, " . $ecs->table(‘goods_attr‘) . " AS b " .  "WHERE ";
77             $ext_group_goods = array();
78             foreach ($filter_attr AS $k => $v) { // 查出符合所有筛选属性条件的商品id */
79                 if (is_numeric($v) && $v !=0 ) {
80                     $sql = $ext_sql . "b.attr_value = a.attr_value AND b.attr_id = " . $cat_filter_attr[$k] ." AND a.goods_attr_id = " . $v;
81                     $ext_group_goods = $db->getColCached($sql);
82                     $ext .= ‘ AND ‘ . db_create_in($ext_group_goods, ‘g.goods_id‘);
83                 }
84             }
85         }
86     }
87     ///<<==================结束---商品属性处理==================///

6)第六步,根据以上计算的条件,查询商品列表,并计算商品的数量等等,把变量注入模板中去。

 1 //向模板,载入一些前台,必备的变量和常量
 2     assign_template(‘c‘, array($cat_id));
 3
 4     //RETURN:Array ( [title] => 夏新_GSM手机_手机类型_ECSHOP演示站 - Powered by ECShop [ur_here] => 首页 > 手机类型 > GSM手机 > 夏新 )
 5     $position = assign_ur_here($cat_id, $brand_name);
 6
 7     $smarty->assign(‘page_title‘,       $position[‘title‘]);    // 页面标题
 8     $smarty->assign(‘ur_here‘,          $position[‘ur_here‘]);  // 当前位置
 9
10     $smarty->assign(‘categories‘,       get_categories_tree($cat_id)); // 分类树
11     $smarty->assign(‘helps‘,            get_shop_help());              // 网店帮助
12     $smarty->assign(‘top_goods‘,        get_top10());                  // 销售排行
13     $smarty->assign(‘show_marketprice‘, $_CFG[‘show_marketprice‘]); //是否显示市场价
14     $smarty->assign(‘category‘,         $cat_id);
15     $smarty->assign(‘brand_id‘,         $brand);
16     $smarty->assign(‘price_max‘,        $price_max);
17     $smarty->assign(‘price_min‘,        $price_min);
18     $smarty->assign(‘filter_attr‘,      $filter_attr_str);
19     $smarty->assign(‘feed_url‘,         ($_CFG[‘rewrite‘] == 1) ? "feed-c$cat_id.xml" : ‘feed.php?cat=‘ . $cat_id); // RSS URL
20
21     if ($brand > 0) {
22         $arr[‘all‘] = array(‘brand_id‘  => 0,
23                 ‘brand_name‘    => $GLOBALS[‘_LANG‘][‘all_goods‘],
24                 ‘brand_logo‘    => ‘‘,
25                 ‘goods_num‘     => ‘‘,
26                 ‘url‘           => build_uri(‘category‘, array(‘cid‘=>$cat_id), $cat[‘cat_name‘])
27         );
28     } else {
29         $arr = array();
30     }
31
32     $brand_list = array_merge($arr, get_brands($cat_id, ‘category‘));
33     $smarty->assign(‘data_dir‘,    DATA_DIR); //网站data目录
34     $smarty->assign(‘brand_list‘,      $brand_list);
35     $smarty->assign(‘promotion_info‘, get_promotion_info()); //获取推荐信息
36
37     /* 调查 */
38     $vote = get_vote();
39     if (!empty($vote)) {
40         $smarty->assign(‘vote_id‘,     $vote[‘id‘]);
41         $smarty->assign(‘vote‘,        $vote[‘content‘]);
42     }
43
44     //获取最热销、推荐和最热卖商品
45     $smarty->assign(‘best_goods‘,      get_category_recommend_goods(‘best‘, $children, $brand, $price_min, $price_max, $ext));
46     $smarty->assign(‘promotion_goods‘, get_category_recommend_goods(‘promote‘, $children, $brand, $price_min, $price_max, $ext));
47     $smarty->assign(‘hot_goods‘,       get_category_recommend_goods(‘hot‘, $children, $brand, $price_min, $price_max, $ext));
48     //获取该前状态下,商品的数量
49     $count = get_cagtegory_goods_count($children, $brand, $price_min, $price_max, $ext);
50     //最大页数
51     $max_page = ($count> 0) ? ceil($count / $size) : 1;
52     if ($page > $max_page) {
53         $page = $max_page;
54     }
55
56     //获取该栏目下的所有商品
57     $goodslist = category_get_goods($children, $brand, $price_min, $price_max, $ext, $size, $page, $sort, $order);
58
59     //判断选择了列表还是图片方式显示方式
60     if($display == ‘grid‘) {
61         if(count($goodslist) % 2 != 0) {
62             $goodslist[] = array();
63         }
64     }
65
66     $smarty->assign(‘goods_list‘,       $goodslist); //注入商品列表
67     $smarty->assign(‘category‘,         $cat_id); //注入分类id
68     $smarty->assign(‘script_name‘, ‘category‘); //注入该脚本的名称
69
70     assign_pager(‘category‘,            $cat_id, $count, $size, $sort, $order, $page, ‘‘, $brand, $price_min, $price_max, $display, $filter_attr_str); // 分页
71     assign_dynamic(‘category‘); // 动态内容
72 }
73 $smarty->display(‘category.dwt‘, $cache_id);

说明:以上的代码中,都有对其实现方法,有非常具体的说明,详情请见代码的备注。

总结:分析都最后,其实我有些些失望了,因为这个所谓多条件搜索功能的实现,并不算是很复杂,很高深的东西,都比较简单(和我的想法差不多)。

不过,我也学到了一些东西,具体如下:

① 对Ecshop商品主要数据表的设计有了了解。(下一篇会简单介绍)

② 原来这里的要对商品的那些属性进行筛选,并不是程序自动处理,而是管理员后台指定的。

③ 价格区间的计算,是按照一定的算法计算出来的,比较智能,但数字不太好看(另外一种策略,是自己后台为每一个商品分类,都指定一个价格区间,也是可以的。)

④ 品牌、价格区间和属性,都是按照一定的原则从数据库抽取出来的。即,这些说有的分类或者属性下,必须是有商品的,才会把它获取出来。比如,如果颜色为黑色的属性下面是没有任何商品的,那么黑色这个属性,就不应该显示出来。其他依次类推。

⑤ 对于一些较为复杂的mysql语句查询,有了一些了解(希望不断提高啦。。)

以上,是小弟做的一些小小的分析和总结,我经验还不丰富啊,有哪一些不对的地方和不足,希望大家指正,我会虚心学习和接受,谢谢啦!!

时间: 2024-10-17 14:18:33

Ecshop的商品筛选功能实现分析之一(主要对category.php进行分析)的相关文章

ECSHOP分类页面筛选功能(按分类下子分类和品牌筛选)

其实分类页面里面本来就有相关的品牌.属性.分类的筛选功能在category.php和模板加上相应的功能即可 1.读出当前分类的所有下级分类 $chlidren_category = $GLOBALS['db']->getALl('SELECT cat_id,cat_name FROM ' . $GLOBALS['ecs']->table('category') ." WHERE parent_id = '$cat_id' and is_show=1"); $category

jQuery制作仿京东商城-商品列表商品筛选功能

这次使用jquery来实现一个仿京东商城-商品列表商品筛选的功能 一.html代码 <!DOCTYPE html> <html> <head> <title></title> <link rel="stylesheet" type="text/css" href="css/style.css"> </head> <body> <div class

求解:php商品条件筛选功能你是怎么做出来的?

求解:php商品条件筛选功能你是怎么做出来的? 2013-09-25 13:43 chenhang607 | 浏览 2756 次 资源共享 求思路或者方法,最好能有些代码 2013-09-25 14:14 提问者采纳 php按条件筛选商品的功能,还是比较简单的.其实就是根据不同的条件组成SQL查询条件,从数据库里查出不同的商品出来.举个例子:用户可以按价格范围.按品牌.按商品名称这几项来综合查询.那么,在用户选择了上面这些查询条件后(可能这3个条件都设置了,也可能只设置了其中2个),提交到服务器

ecshop二次开发功能插件计划列表

原文地址:php ecshop 二次开发 http://phpecshop.blog.51cto.com/6296699/1854849 ecshop功能开发计划列表 1.搜索页面添加筛选功能,类似京东 2.搜索结合coreseek实现中文分词功能,后台可以添加修改删除关键词 3.搜索框输入关键词自动提示,类似京东效果 4.缓存使用memcached储存,加快访问速度 5.添加多语言,一个后台管理多个语言商城内容 6.每天登录送积分,设置连续登录不同的天数再奖励相应的积分 7.注册添加手机验证码

【经验】angularjs 实现带查找筛选功能的select下拉框

一.背景 对于select的下拉列表,像国家选择这样的功能,全世界那么多国家,一直拉滚动条多辛苦,眼睛也要盯着找,累!so,为优化用户体验,带查找功能的下拉框是非常非常有必要的.都知道jquery里有这样的插件,但我们用的是Angularjs,更希望用双向绑定,指令的方式优雅地解决这个问题. 分析:    目标 在原来的<select ng-options="">标签上新加一个属性 select-search 就能支持查找的功能.如果这个属性没起作用,也不影响原来的sele

织梦CMS实现多条件筛选功能

用织梦实现筛选的功能,其实主要就是运用到了织梦的高级搜索功能,然后用ajax去post替换掉本来的结果就可以了. 其实筛选的话,主要有两个问题需要解决,一个是前台的筛选实现,一个是后台根据前台的点击,反馈出相应的结果. 于是在网上搜索了N多的资料了之后,先实现前台的功能,就是你点了之后会有一个筛选的效果出来,当然,也只是一个效果.具体可以参照:jquery仿京东筛选效果.下面就一步一步用织梦来实现这样的功能. 首先我们先在后台自定义模型(自定义模型都不会的同学,可以直接去面壁思过了) 看到参照网

android下载管理、理财、浏览器、商品筛选、录音源码等

Android精选源码 android仿美拍直播的点赞动画 android视频播放器完美切换全屏.小窗口源码 android类似随手记理财类源码 android简单浏览器源码 android电动车项目源码 android文件下载管理demo源码 android录音和播放的管理类源码 android仿QQ图片编辑器源码 水平的无限滑动的选择View Android商品属性筛选与商品筛选(一) Android优质博客 如何改变Android应用的主题色 轻听是一款小而美的Android本地音乐播放器

[转载]织梦DEDE多选项筛选_联动筛选功能的实现_二次开发

织梦默认的列表页没有筛选功能,但有时候我们做产品列表页的时候,产品的字段比较多,很多人都需要用到筛选功能,这样可以让用户更方便的找到自己所需要的东西,实现这个联动筛选功能需要对织梦进行二次开发,下面就告诉大家如何对织梦进行二次开发实现这个很多人都需要的筛选功能,如下图所示: 首先需要说明的是这个功能需要在模板里面用到php标签,所以需要在后台模板引擎禁用标签里面解除这个标签的禁用,具体方法: 后台——系统——系统基本参数——其它选项——模板引擎禁用标签:php 将这个PHP去掉后保存就可以了!

【SSH网上商城项目实战09】添加和更新商品类别功能的实现

上一节我们做完了查询和删除商品的功能,这一节我们做一下添加和更新商品的功能. 1. 添加商品类别 1.1 添加类别的UI设计 我们先说一下思路:首先当用户点击"添加商品"时,我们应该弹出一个"添加商品"的UI窗口(注意这里不是跳转到新的jsp,EasyUI只有一个页面),弹出这个"添加商品"的窗口后,应该锁住它父类的所有窗口(即点击其他地方无效,只能操作添加商品的窗口),等用户填好了信息后,在新弹出来的窗口上点击"添加"后,将