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

原因如下:

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

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

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

希望达到的目的是:

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

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

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

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

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

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

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

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

④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. //===> 6.获取该分类cat的价格分级:
  80. //===> ①如果价格分级=0,那么获取直接父类的价格分级。(Ⅰ如果父类价格也=0,那么就是不用价格分级 )
  81. //===> ②如果价格分级!=0,那么就是自身的价格分级。
  82. //===> TABLE:ecs_category
  83. //===> RETURN:$cat['grade']=4
  84. /* 获取价格分级 */
  85. if ($cat['grade'] == 0 && $cat['parent_id'] != 0) { // ==>如果价格分级为空,但是它还有上级分类,那么取直接上级的价格分级等数
  86. $cat['grade'] = get_parent_grade($cat_id); //如果当前分类级别为空,取最近的上级分类
  87. }
  88.  
  89. //===> 7.对价格区间进行划分。 ecshop的划分方法,是根据算法来的,比较复杂。
  90. //===> 如果价格分级>1,那么就执行价格区间划分
  91. if ($cat['grade'] > 1) {
  92. /* 需要价格分级 */
  93.  
  94. /*
  95. 算法思路:
  96. 1、当分级大于1时,进行价格分级
  97. 2、取出该类下商品价格的最大值、最小值
  98. 3、根据商品价格的最大值来计算商品价格的分级数量级:
  99. 价格范围(不含最大值) 分级数量级
  100. 0-0.1 0.001
  101. 0.1-1 0.01
  102. 1-10 0.1
  103. 10-100 1
  104. 100-1000 10
  105. 1000-10000 100
  106. 4、计算价格跨度:
  107. 取整((最大值-最小值) / (价格分级数) / 数量级) * 数量级
  108. 5、根据价格跨度计算价格范围区间
  109. 6、查询数据库
  110.  
  111. 可能存在问题:
  112. 1、
  113. 由于价格跨度是由最大值、最小值计算出来的
  114. 然后再通过价格跨度来确定显示时的价格范围区间
  115. 所以可能会存在价格分级数量不正确的问题
  116. 该问题没有证明
  117. 2、
  118. 当价格=最大值时,分级会多出来,已被证明存在
  119. */
  120.  
  121. //===> 获得当前分类下商品价格的最大值、最小值
  122. //===> 获得所有扩展分类属于指定分类的所有商品ID ,其中goods_id = 16的商品的扩展属于分类3
  123. //===> TABLE:ecs_goods 和 ecs_goods_cat
  124. //===> 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
  125. //===> RETURN:Array ( [min] => 280.00 [max] => 5999.00 )
  126. $sql = "SELECT min(g.shop_price) AS min, max(g.shop_price) as max ".
  127. " FROM " . $ecs->table('goods'). " AS g ".
  128. " WHERE ($children OR " . get_extension_goods($children) . ') AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 ';
  129. $row = $db->getRow($sql);
  130.  
  131. //===> 按照公式计算出最低价格和最高价格、以及价格跨度
  132. //===============↓↓↓先不做讨论===============
  133. // 取得价格分级最小单位级数,比如,千元商品最小以100为级数
  134. $price_grade = 0.0001;
  135. for($i=-2; $i<= log10($row['max']); $i++) {
  136. $price_grade *= 10;
  137. }
  138.  
  139. //价格跨度
  140. $dx = ceil(($row['max'] - $row['min']) / ($cat['grade']) / $price_grade) * $price_grade;
  141. if($dx == 0) {
  142. $dx = $price_grade;
  143. }
  144.  
  145. for($i = 1; $row['min'] > $dx * $i; $i ++);
  146.  
  147. for($j = 1; $row['min'] > $dx * ($i-1) + $price_grade * $j; $j++);
  148. $row['min'] = $dx * ($i-1) + $price_grade * ($j - 1);
  149.  
  150. for(; $row['max'] >= $dx * $i; $i ++);
  151. $row['max'] = $dx * ($i) + $price_grade * ($j - 1);
  152.  
  153. //===>这里打印最高价格和最低价格:$row=>Array ( [min] => 200 [max] => 6200 )
  154. //===>这里打印价格跨度:$dx = 1500
  155.  
  156. //===============先不做讨论↑↑↑==================//
  157.  
  158. //===> 根据商品的价格、价格区间的最低价格、以及价格跨度,计算该商品价格属于哪一个区间内。
  159. //===> 获取属于该价格区间内的商品的数量、获取sn则属于哪一个区间sn=0为200-1700、sn=1为1700-3200、sn=3为4700-6200。
  160. //===> 因为没有商品价格属于第二区间,则不存在sn=2,那么3200-4700则没有任何商品
  161. //===> TABLE:ecs_goods 和 ecs_goods_cat
  162. //===> 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
  163. //===>RETURN:Array ( [0] => Array ( [sn] => 0 [goods_num] => 6 ) [1] => Array ( [sn] => 1 [goods_num] => 5 ) [2] => Array ( [sn] => 3 [goods_num] => 1 ) )
  164. $sql = "SELECT (FLOOR((g.shop_price - $row[min]) / $dx)) AS sn, COUNT(*) AS goods_num ".
  165. " FROM " . $ecs->table('goods') . " AS g ".
  166. " WHERE ($children OR " . get_extension_goods($children) . ') AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 '.
  167. " GROUP BY sn ";
  168. $price_grade = $db->getAll($sql);
  169.  
  170. //===> 根据价格等级price_grade,计算真正的价格区间。
  171. //===> 方法build_uri()重要:要为每一个价格区间,生成一个url超链接,以备前台点击搜索用
  172. //===> 并根据价格参数,判断该区间,是否是当前被搜索的区间
  173. //===> 把价格区间,注入模板,供前台使用
  174. //===> 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 ) )
  175. foreach ($price_grade as $key=>$val) {
  176. $temp_key = $key + 1;
  177. $price_grade[$temp_key]['goods_num'] = $val['goods_num'];
  178. $price_grade[$temp_key]['start'] = $row['min'] + round($dx * $val['sn']);
  179. $price_grade[$temp_key]['end'] = $row['min'] + round($dx * ($val['sn'] + 1));
  180. $price_grade[$temp_key]['price_range'] = $price_grade[$temp_key]['start'] . '&nbsp;-&nbsp;' . $price_grade[$temp_key]['end'];
  181. $price_grade[$temp_key]['formated_start'] = price_format($price_grade[$temp_key]['start']);
  182. $price_grade[$temp_key]['formated_end'] = price_format($price_grade[$temp_key]['end']);
  183. $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']);
  184. /* 判断价格区间是否被选中 */
  185. if (isset($_REQUEST['price_min']) && $price_grade[$temp_key]['start'] == $price_min && $price_grade[$temp_key]['end'] == $price_max) {
  186. $price_grade[$temp_key]['selected'] = 1;
  187. }
  188. else {
  189. $price_grade[$temp_key]['selected'] = 0;
  190. }
  191. }
  192. //补充一个选择全部的类型的数组
  193. $price_grade[0]['start'] = 0;
  194. $price_grade[0]['end'] = 0;
  195. $price_grade[0]['price_range'] = $_LANG['all_attribute'];
  196. $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']);
  197. $price_grade[0]['selected'] = empty($price_max) ? 1 : 0;
  198. //把价格区间数组,注入模板文件
  199. $smarty->assign('price_grade', $price_grade);
  200. }
  201. ///<<================结束---商品价格区间处理==================<<///
  202.  
  203. ///>>================开始---商品品牌处理==================>>///
  204. //====> ???db_create_in(array_unique(array_merge(array($cat_id), array_keys(cat_list($cat_id, 0, false))))) . ")
  205. //===> 品牌筛选功能:把该栏目下(其中包括扩展分类下的商品),所有商品的品牌获取,但不能重复。
  206. //===> 品牌下有商品并且商品状态正常,才能把该品牌取出。没有商品的品牌不能取出
  207. //===> TABLE:ecs_brand、ecs_goods 和 ecs_goods_cat
  208. //===> 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
  209. //===> 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 ) )
  210. /* 品牌筛选 */
  211. $sql = "SELECT b.brand_id, b.brand_name, COUNT(*) AS goods_num ".
  212. "FROM " . $GLOBALS['ecs']->table('brand') . "AS b, ".
  213. $GLOBALS['ecs']->table('goods') . " AS g LEFT JOIN ". $GLOBALS['ecs']->table('goods_cat') . " AS gc ON g.goods_id = gc.goods_id " .
  214. "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 " .
  215. " AND g.is_on_sale = 1 AND g.is_alone_sale = 1 AND g.is_delete = 0 ".
  216. "GROUP BY b.brand_id HAVING goods_num > 0 ORDER BY b.sort_order, b.brand_id ASC";
  217. $brands = $GLOBALS['db']->getAll($sql);
  218.  
  219. //===> 把该分类下所有商品的品牌,组合成数组,给前台调用
  220. //===> 方法build_uri()重要:要为每品牌,生成一个url超链接,以备前台点击搜索用
  221. //===> 把数组注入模板文件
  222. //====! 这样一种组织数组的方式,有它的缺陷:就是说不能够把每一个品牌下面的,商品的数量保存下来,同时也会有一些无用的数据,掺杂其中。
  223. //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 ) )
  224. foreach ($brands AS $key => $val) {
  225. $temp_key = $key + 1;
  226. $brands[$temp_key]['brand_name'] = $val['brand_name'];
  227. $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']);
  228. /* 判断品牌是否被选中 */
  229. if ($brand == $brands[$key]['brand_id']) {
  230. $brands[$temp_key]['selected'] = 1;
  231. } else {
  232. $brands[$temp_key]['selected'] = 0;
  233. }
  234. }
  235. //补充一个选择全部品牌的数组
  236. $brands[0]['brand_name'] = $_LANG['all_attribute'];
  237. $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']);
  238. $brands[0]['selected'] = empty($brand) ? 1 : 0;
  239. //把品牌数组注入模板
  240. $smarty->assign('brands', $brands);
  241. ///<<==================结束---商品品牌处理==================<<///
  242.  
  243. ///>>==================开始---商品属性处理==================>>///
  244. /* 属性筛选 */
  245. $ext = ''; //商品查询条件扩展
  246. if ($cat['filter_attr'] > 0) {
  247. //===>需要筛选的属性,是人工在后台添加的,存放在ecs_category 表的中 filter_attr字段里面,格式如:185,189,120,190
  248. //===>RETURN:Array ( [0] => 185 [1] => 189 [2] => 173 [3] => 178 )
  249. $cat_filter_attr = explode(',', $cat['filter_attr']); //提取出此分类的筛选属性
  250.  
  251. //===> 然后,对每一个属性(此属性是主属性,下面还有子属性),循环进行操作
  252. //===> ①获取该属性的属性名
  253. //===> ②获取该属性的所有子属性(子属性必须是有被商品在使用的,不然,不要将其显示出来)
  254. //===> 意义:因为该属性涉及到搜索参数,如果该属性下本身没有商品,那么就没有显示出来的意义了。
  255. //===> 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] => 黑色 ) )
  256. $all_attr_list = array();
  257. foreach ($cat_filter_attr AS $key => $value) {
  258. $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'";
  259. if($temp_name = $db->getOne($sql)) {
  260. //获取该属性名(主属性)
  261. $all_attr_list[$key]['filter_attr_name'] = $temp_name;
  262.  
  263. //获取该属性的所有子属性(子属性必须是有被商品在使用的,不然,不要将其显示出来)
  264. //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] => 黑色 ) )
  265. $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') .
  266. " AS g" .
  267. " 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 '.
  268. " AND a.attr_id='$value' ".
  269. " GROUP BY a.attr_value";
  270. $attr_list = $db->getAll($sql);
  271.  
  272. //如果后台指定该分类下,用于搜索的属性的组数,是跟地址栏中filter_attr=0.0.0.0 中0的个数是一样的,而且顺序都是一样的
  273. //第一个0,表示第一组属性中,它选择了哪一个子属性,以此类推
  274. //获取当前url中已选择属性的值,并保留在数组中
  275. //!这里要作循环,是因为避免属性为0或者空时,导致出错,因为直接把$filter_attr 赋值给 $temp_arrt_url_arr会出错。
  276. //RETURN:Array ( [0] => 163 [1] => 216 [2] => 160 [3] => 186 )
  277. $temp_arrt_url_arr = array();
  278. for ($i = 0; $i < count($cat_filter_attr); $i++) {
  279. $temp_arrt_url_arr[$i] = !empty($filter_attr[$i]) ? $filter_attr[$i] : 0;
  280. }
  281.  
  282. //这里是该属性下,选择全部时的数组形式
  283. //哪一个属性的值为0,即说明用户选择的是该属性的全部选项
  284. //为“全部”生成url
  285. //DATA:Array ( [0] => 0 [1] => 216 [2] => 160 [3] => 186 )
  286. $temp_arrt_url_arr[$key] = 0; //“全部”的信息生成
  287. $temp_arrt_url = implode('.', $temp_arrt_url_arr);
  288. $all_attr_list[$key]['attr_list'][0]['attr_value'] = $_LANG['all_attribute'];
  289. $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']);
  290. $all_attr_list[$key]['attr_list'][0]['selected'] = empty($filter_attr[$key]) ? 1 : 0;
  291.  
  292. //循环计算子属性的相关数组:属性值,属性是否选择,属性的url
  293. //判断当前子属性,是否被选中状态
  294. //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 ) ) ) )
  295. foreach ($attr_list as $k => $v) {
  296. $temp_key = $k + 1;
  297. $temp_arrt_url_arr[$key] = $v['goods_id']; //为url中代表当前筛选属性的位置变量赋值,并生成以‘.’分隔的筛选属性字符串
  298. $temp_arrt_url = implode('.', $temp_arrt_url_arr);
  299.  
  300. $all_attr_list[$key]['attr_list'][$temp_key]['attr_value'] = $v['attr_value'];
  301. $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']);
  302.  
  303. if (!empty($filter_attr[$key]) AND $filter_attr[$key] == $v['goods_id']) { //处理已被选择的子属性
  304. $all_attr_list[$key]['attr_list'][$temp_key]['selected'] = 1;
  305. }
  306. else {
  307. $all_attr_list[$key]['attr_list'][$temp_key]['selected'] = 0;
  308. }
  309. }
  310. }
  311. }
  312. //为模板注入变量
  313. $smarty->assign('filter_attr_list', $all_attr_list);
  314.  
  315. /* 扩展商品查询条件 */
  316. if (!empty($filter_attr)) {
  317. $ext_sql = "SELECT DISTINCT(b.goods_id) FROM " . $ecs->table('goods_attr') . " AS a, " . $ecs->table('goods_attr') . " AS b " . "WHERE ";
  318. $ext_group_goods = array();
  319. foreach ($filter_attr AS $k => $v) { // 查出符合所有筛选属性条件的商品id */
  320. if (is_numeric($v) && $v !=0 ) {
  321. $sql = $ext_sql . "b.attr_value = a.attr_value AND b.attr_id = " . $cat_filter_attr[$k] ." AND a.goods_attr_id = " . $v;
  322. $ext_group_goods = $db->getColCached($sql);
  323. $ext .= ' AND ' . db_create_in($ext_group_goods, 'g.goods_id');
  324. }
  325. }
  326. }
  327. }
  328. ///<<==================结束---商品属性处理==================///
  329.  
  330. //向模板,载入一些前台,必备的变量和常量
  331. assign_template('c', array($cat_id));
  332.  
  333. //RETURN:Array ( [title] => 夏新_GSM手机_手机类型_ECSHOP演示站 - Powered by ECShop [ur_here] => 首页 > 手机类型 > GSM手机 > 夏新 )
  334. $position = assign_ur_here($cat_id, $brand_name);
  335.  
  336. $smarty->assign('page_title', $position['title']); // 页面标题
  337. $smarty->assign('ur_here', $position['ur_here']); // 当前位置
  338.  
  339. $smarty->assign('categories', get_categories_tree($cat_id)); // 分类树
  340. $smarty->assign('helps', get_shop_help()); // 网店帮助
  341. $smarty->assign('top_goods', get_top10()); // 销售排行
  342. $smarty->assign('show_marketprice', $_CFG['show_marketprice']); //是否显示市场价
  343. $smarty->assign('category', $cat_id);
  344. $smarty->assign('brand_id', $brand);
  345. $smarty->assign('price_max', $price_max);
  346. $smarty->assign('price_min', $price_min);
  347. $smarty->assign('filter_attr', $filter_attr_str);
  348. $smarty->assign('feed_url', ($_CFG['rewrite'] == 1) ? "feed-c$cat_id.xml" : 'feed.php?cat=' . $cat_id); // RSS URL
  349.  
  350. if ($brand > 0) {
  351. $arr['all'] = array('brand_id' => 0,
  352. 'brand_name' => $GLOBALS['_LANG']['all_goods'],
  353. 'brand_logo' => '',
  354. 'goods_num' => '',
  355. 'url' => build_uri('category', array('cid'=>$cat_id), $cat['cat_name'])
  356. );
  357. } else {
  358. $arr = array();
  359. }
  360.  
  361. $brand_list = array_merge($arr, get_brands($cat_id, 'category'));
  362. $smarty->assign('data_dir', DATA_DIR); //网站data目录
  363. $smarty->assign('brand_list', $brand_list);
  364. $smarty->assign('promotion_info', get_promotion_info()); //获取推荐信息
  365.  
  366. /* 调查 */
  367. $vote = get_vote();
  368. if (!empty($vote)) {
  369. $smarty->assign('vote_id', $vote['id']);
  370. $smarty->assign('vote', $vote['content']);
  371. }
  372.  
  373. //获取最热销、推荐和最热卖商品
  374. $smarty->assign('best_goods', get_category_recommend_goods('best', $children, $brand, $price_min, $price_max, $ext));
  375. $smarty->assign('promotion_goods', get_category_recommend_goods('promote', $children, $brand, $price_min, $price_max, $ext));
  376. $smarty->assign('hot_goods', get_category_recommend_goods('hot', $children, $brand, $price_min, $price_max, $ext));
  377. //获取该前状态下,商品的数量
  378. $count = get_cagtegory_goods_count($children, $brand, $price_min, $price_max, $ext);
  379. //最大页数
  380. $max_page = ($count> 0) ? ceil($count / $size) : 1;
  381. if ($page > $max_page) {
  382. $page = $max_page;
  383. }
  384.  
  385. //获取该栏目下的所有商品
  386. $goodslist = category_get_goods($children, $brand, $price_min, $price_max, $ext, $size, $page, $sort, $order);
  387.  
  388. //判断选择了列表还是图片方式显示方式
  389. if($display == 'grid') {
  390. if(count($goodslist) % 2 != 0) {
  391. $goodslist[] = array();
  392. }
  393. }
  394.  
  395. $smarty->assign('goods_list', $goodslist); //注入商品列表
  396. $smarty->assign('category', $cat_id); //注入分类id
  397. $smarty->assign('script_name', 'category'); //注入该脚本的名称
  398.  
  399. assign_pager('category', $cat_id, $count, $size, $sort, $order, $page, '', $brand, $price_min, $price_max, $display, $filter_attr_str); // 分页
  400. assign_dynamic('category'); // 动态内容
  401. }
  402. $smarty->display('category.dwt', $cache_id);
  403. ?>

查看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. // 取得价格分级最小单位级数,比如,千元商品最小以100为级数
  57. $price_grade = 0.0001;
  58. for($i=-2; $i<= log10($row['max']); $i++) {
  59. $price_grade *= 10;
  60. }
  61.  
  62. //价格跨度
  63. $dx = ceil(($row['max'] - $row['min']) / ($cat['grade']) / $price_grade) * $price_grade;
  64. if($dx == 0) {
  65. $dx = $price_grade;
  66. }
  67.  
  68. for($i = 1; $row['min'] > $dx * $i; $i ++);
  69.  
  70. for($j = 1; $row['min'] > $dx * ($i-1) + $price_grade * $j; $j++);
  71. $row['min'] = $dx * ($i-1) + $price_grade * ($j - 1);
  72.  
  73. for(; $row['max'] >= $dx * $i; $i ++);
  74. $row['max'] = $dx * ($i) + $price_grade * ($j - 1);
  75.  
  76. //===>这里打印最高价格和最低价格:$row=>Array ( [min] => 200 [max] => 6200 )
  77. //===>这里打印价格跨度:$dx = 1500
  78.  
  79. //===============先不做讨论↑↑↑==================//
  80.  
  81. //===> 根据商品的价格、价格区间的最低价格、以及价格跨度,计算该商品价格属于哪一个区间内。
  82. //===> 获取属于该价格区间内的商品的数量、获取sn则属于哪一个区间sn=0为200-1700、sn=1为1700-3200、sn=3为4700-6200。
  83. //===> 因为没有商品价格属于第二区间,则不存在sn=2,那么3200-4700则没有任何商品
  84. //===> TABLE:ecs_goods 和 ecs_goods_cat
  85. //===> 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
  86. //===>RETURN:Array ( [0] => Array ( [sn] => 0 [goods_num] => 6 ) [1] => Array ( [sn] => 1 [goods_num] => 5 ) [2] => Array ( [sn] => 3 [goods_num] => 1 ) )
  87. $sql = "SELECT (FLOOR((g.shop_price - $row[min]) / $dx)) AS sn, COUNT(*) AS goods_num ".
  88. " FROM " . $ecs->table('goods') . " AS g ".
  89. " WHERE ($children OR " . get_extension_goods($children) . ') AND g.is_delete = 0 AND g.is_on_sale = 1 AND g.is_alone_sale = 1 '.
  90. " GROUP BY sn ";
  91. $price_grade = $db->getAll($sql);
  92.  
  93. //===> 根据价格等级price_grade,计算真正的价格区间。
  94. //===> 方法build_uri()重要:要为每一个价格区间,生成一个url超链接,以备前台点击搜索用
  95. //===> 并根据价格参数,判断该区间,是否是当前被搜索的区间
  96. //===> 把价格区间,注入模板,供前台使用
  97. //===> 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 ) )
  98. foreach ($price_grade as $key=>$val) {
  99. $temp_key = $key + 1;
  100. $price_grade[$temp_key]['goods_num'] = $val['goods_num'];
  101. $price_grade[$temp_key]['start'] = $row['min'] + round($dx * $val['sn']);
  102. $price_grade[$temp_key]['end'] = $row['min'] + round($dx * ($val['sn'] + 1));
  103. $price_grade[$temp_key]['price_range'] = $price_grade[$temp_key]['start'] . '&nbsp;-&nbsp;' . $price_grade[$temp_key]['end'];
  104. $price_grade[$temp_key]['formated_start'] = price_format($price_grade[$temp_key]['start']);
  105. $price_grade[$temp_key]['formated_end'] = price_format($price_grade[$temp_key]['end']);
  106. $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']);
  107. /* 判断价格区间是否被选中 */
  108. if (isset($_REQUEST['price_min']) && $price_grade[$temp_key]['start'] == $price_min && $price_grade[$temp_key]['end'] == $price_max) {
  109. $price_grade[$temp_key]['selected'] = 1;
  110. }
  111. else {
  112. $price_grade[$temp_key]['selected'] = 0;
  113. }
  114. }
  115. //补充一个选择全部的类型的数组
  116. $price_grade[0]['start'] = 0;
  117. $price_grade[0]['end'] = 0;
  118. $price_grade[0]['price_range'] = $_LANG['all_attribute'];
  119. $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']);
  120. $price_grade[0]['selected'] = empty($price_max) ? 1 : 0;
  121. //把价格区间数组,注入模板文件
  122. $smarty->assign('price_grade', $price_grade);
  123. }
  124. ///<<================结束---商品价格区间处理==================<<///

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. if (!empty($filter_attr)) {
  75. $ext_sql = "SELECT DISTINCT(b.goods_id) FROM " . $ecs->table('goods_attr') . " AS a, " . $ecs->table('goods_attr') . " AS b " . "WHERE ";
  76. $ext_group_goods = array();
  77. foreach ($filter_attr AS $k => $v) { // 查出符合所有筛选属性条件的商品id */
  78. if (is_numeric($v) && $v !=0 ) {
  79. $sql = $ext_sql . "b.attr_value = a.attr_value AND b.attr_id = " . $cat_filter_attr[$k] ." AND a.goods_attr_id = " . $v;
  80. $ext_group_goods = $db->getColCached($sql);
  81. $ext .= ' AND ' . db_create_in($ext_group_goods, 'g.goods_id');
  82. }
  83. }
  84. }
  85. }
  86. ///<<==================结束---商品属性处理==================///

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语句查询,有了一些了解(希望不断提高啦。。)

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

【PHP开源产品】Ecshop的商品筛选功能实现分析之一的更多相关文章

  1. ecshop添加商品筛选功能

    ecshop商品属性一直是使用问题的难点,而“属性筛选”更是ecshop属性中的难点,那么下面来详细说明一下 属性筛选功能 第一,属性筛选的特点: 属性筛选必须是分类页才会显示,列出所有商品的唯一属性 ...

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

    其实分类页面里面本来就有相关的品牌.属性.分类的筛选功能在category.php和模板加上相应的功能即可 1.读出当前分类的所有下级分类 $chlidren_category = $GLOBALS[ ...

  3. Ecshop、Discuz! 等开源产品的局限

    Ecshop.Discuz! 等开源产品的局限 记得今年年初,我初次接触Discuz!和Ecshop时,一阵阵地惊叹:成熟度这么高的产品,居然是免费的.我们这些搞传统软件开发的要怎么活?另外也奇怪,做 ...

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

    求解:php商品条件筛选功能你是怎么做出来的? 2013-09-25 13:43 chenhang607 | 浏览 2756 次 资源共享 求思路或者方法,最好能有些代码 2013-09-25 14: ...

  5. php商品条件筛选功能你是怎么做出来的?

    php商品条件筛选功能你是怎么做出来的? php按条件筛选商品的功能,还是比较简单的.其实就是根据不同的条件组成SQL查询条件,从数据库里查出不同的商品出来.举个例子:用户可以按价格范围.按品牌.按商 ...

  6. 产品列表页分类筛选、排序的算法实现(PHP)

    一.简单的单条件查询 工作都是从简单的开始,先从最简单的单表查询开始,这个一般用在首页以及一些比较独立的页面,只需要查找几个符合条件的产品展示出来即可,可以使用分页或者不使用分页.下面这个是产品控制器 ...

  7. [转载]ecshop 实现订单导出功能 指定订单导出 EXCEL 数据文件

    当下很多功能都觉得理所当然,但是实际作为2012年停更的ECSHOP来说,很多功能其实都是缺少的,好比今天的要说的功能 订单导出 这个功能对于现在的产品设计来说,应该属于一个比较常规的功能,但是ECS ...

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

    Android精选源码 android仿美拍直播的点赞动画   android视频播放器完美切换全屏.小窗口源码   android类似随手记理财类源码   android简单浏览器源码   andr ...

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

    用织梦实现筛选的功能,其实主要就是运用到了织梦的高级搜索功能,然后用ajax去post替换掉本来的结果就可以了. 其实筛选的话,主要有两个问题需要解决,一个是前台的筛选实现,一个是后台根据前台的点击, ...

随机推荐

  1. Python之几个技巧特点

    今天偶然看到一篇文章<你可能不知道的30个Python语言的提点技巧>,虽然做python有几年了,但中间还是好多不知道或没想到,特在这里做下摘抄. 原文地址: http://soft.c ...

  2. Prevent Adding Component More than once

    Question: I'm developing a C# component, I want to prevent the user from adding this component to th ...

  3. Hadoop2.6.0错误

    错误1: WARN hdfs.DFSClient: DataStreamer Exception org.apache.hadoop.ipc.RemoteException(java.io.IOExc ...

  4. MySQL主存复制与读写分离的感悟

    1.主存复制: 就是实现数据拷贝,有点实时的感觉,完成数据同步,存储两份数据. 项目开发中,类似场景许多,尤其是异构系统之间的交互,协作.-------------------场景目的:为了安全,各自 ...

  5. 业务中Spring使用

    不管是MVC框架还是DAO框架,在业务场景中能够通用的个人觉得AOP是一个重点,看是不是可以合理使用,其他的框架都是基础框架 ================================== 第一 ...

  6. JavaFX Application应用实例

    下面代码演示的是JavaFX进程命令行参数的实例.大家可以参阅一下. /*原文地址:http://www.manongjc.com/article/134.html */ import java.ut ...

  7. OSChina中远程GIT仓库同步探索

    GIT平台在OSChina中的搭建帮了我们很大的忙,但如何将本地GIT仓库上传至OSChina的远程仓库,相信这是一个艰难的坎,今天我就在此总结我的成功经验,帮助大家,共同学习.由于条件有限,我全部的 ...

  8. 在代码中调用 mvc 4 api

    mvc 4 api 的调用有很多种,最常见也最简单的一种是 用 ajax 的方式在前端界面中调用, 如果是在后台代码中调用 ,是要复杂一些,以下是 以 post 的方式调用 api 的封装好的方法: ...

  9. 浅谈 cookie 和 session

    1.关闭浏览器后,session是否还存在? session在服务器和客户端各保留一个副本,关闭浏览器与否和session是否存在没有任何关系. session采取的是服务器端保持状态的方案,它存储在 ...

  10. java map缓存

    /**  * 缓存池  * @author xiaoquan  * @create 2015年3月13日 上午10:32:13  * @see  */ public class CachePool { ...