產品多屬性搜索實現


  前陣子碰上一個關於產品多屬性搜索的問題,給實現了,現在拿出來跟大家探討探討,有什么好建議記得留下。

  首先說明下,下面的實現,都僅僅是簡易版,純屬拋磚引玉而為,更強大的功能只能做相應的額外擴展才行。

  本文略過分類、屬性、產品的創建過程的源碼解析,如下僅附上圖片說明。

圖一:創建分類(僅兩級)

圖二:創建屬性

圖三:創建產品(這里屬性是可多選的)

  下面直奔產品多屬性搜索環節。

  首先說明一下,本文所用的搜索程序首次加載會將庫中所有的產品顯示出來,然后通過搜索結果,隱藏掉不匹配的產品,顯示正確的產品,從而實現搜索效果。

下面是整個搜索過程的圖片展示。

圖四:搜索首次加載結果

 

圖五:父分類搜索(含子分類數據)

圖六:子分類搜索

 

圖七:分類+多屬性搜索(1)

圖八:分類+多屬性搜索(2)

圖九:分類+多屬性搜索(3)

圖十:分類+多屬性搜索(4) 

 

圖十一:分類+多屬性搜索(5)

 圖十二:分類+多屬性搜索(6)

 

  圖十三:分類+多屬性搜索(7)

 

 搜索程序前台源碼(displayProduct.php):

View Code
  1 <?php
  2     require 'product.model.php';
  3 ?>
  4 <!DOCTYPE>
  5 <html>
  6 <head>
  7     <title>產品展示搜索</title>
  8     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  9     <meta http-equiv="Content-Language" content="zh-CN" />
 10     <script type="text/javascript" src="http://files.cnblogs.com/Zjmainstay/jquery-1.6.2.min.js"></script>
 11 </head>
 12 <body>
 13 <style>
 14 .product{float:left;width: 20%;}
 15 body{font-size:14px;}
 16 .p_price span{color:#FF0000;}
 17 del{color:#C0C0FF;}
 18 li{list-style:none;}
 19 #searchProduct ul{clear:left;float:left;margin: 3px 0;}
 20 .parentAttr{font-size:16px;font-weight:bold;float: left;margin-right: 10px;width: 100px;}
 21 .searchAttr{border:1px solid #CFCFCF;height:20px;line-height:20px;float:left;cursor:pointer;margin: 0 3px;padding: 0 3px;}
 22 #productList{margin: 0 auto;width: 960px;clear:left;}
 23 .selectedAttr{background-color:#ABC;}
 24 #searchBar{clear:left;float:left;margin-left: 40px;}
 25 #categories span{margin-left:40px;}
 26 #emptyProduct{display:none;}
 27 </style>
 28 <div id="container">
 29     <!-- 顯示分類 -->
 30     <div id="categories">
 31         <span class="parentAttr">產品分類</span>
 32         <?php echo Product::getCategoryList(); ?>
 33     </div>
 34     <!-- 顯示多屬性搜索選項 -->
 35     <div id="searchProduct">
 36         <?php echo Product::getAttributeList(true); ?>
 37         <input type="button" id="searchBar" value="搜索" />
 38     </div>
 39     <!-- 顯示搜索結果 -->
 40     <div id="productList">
 41         <?php echo Product::getProductList(); ?>
 42         <div id="emptyProduct">沒有搜索到結果!</div>
 43     </div>
 44 </div>
 45 <script type="text/javascript">
 46 $(document).ready(function(){
 47     // 搜索選項選中
 48     $(".searchAttr").click(function(){
 49         $(this).toggleClass('selectedAttr');
 50     });
 51     //分類選定觸發搜索
 52     $("#categoryList").change(function(){
 53         var catid = $.trim($(this).val());
 54         if(isNaN(catid)) return false;
 55         
 56         $.ajax({
 57             url:'displayProduct.process.php',
 58             type:'POST',
 59             data:{catid:catid,type:'cate'},
 60             dataType:'json',
 61             success:function(data){
 62                 if(data.status == 1){
 63                     $(".product").hide();                //先將所有產品隱藏,后面在通過搜索結果顯示相應的產品
 64                     if(data.products.length == 0){        //如果搜索結果為空
 65                         $("#emptyProduct").show();        //顯示“沒有搜索到結果!”
 66                     }else {                                //否則,隱藏“沒有搜索到結果!”,並逐個顯示搜索結果中的產品
 67                         $("#emptyProduct").hide();
 68                         $.each(data.products,function(i){
 69                             $("#product-"+data.products[i]).show();
 70                         });
 71                     }
 72                 }else {
 73                     alert(data.msg);
 74                 }
 75             },
 76             error:function(msg){
 77                 alert(msg);
 78             }
 79         });
 80     });
 81     //搜索按鈕觸發搜索
 82     $("#searchBar").click(function(){
 83         if($(".selectedAttr").length == 0) {
 84             $("#categoryList").change();            //若搜索屬性為空,則僅根據分類進行搜索(清除所有選中屬性的情況)
 85             return false;
 86         }
 87         
 88         //進行搜索屬性拼接,同級屬性(OR)用','分割,不同級屬性(AND)用'|'分割
 89         var searchString = '';
 90         var searchArray = [];
 91         $("#searchProduct ul").each(function(){
 92             $(".selectedAttr",$(this)).each(function(){
 93                 var attr = $.trim($(this).attr('attr'));
 94                 if(!isNaN(attr)) {
 95                     searchString += attr + ',';
 96                     searchArray.push(attr);
 97                 }
 98             })
 99             searchString = searchString.substr(0,searchString.length-1) + '|';
100         });
101         searchString = searchString.substr(0,searchString.length-1);
102         
103         if(searchString == '') return false;
104         
105         var catid = $.trim($("#categoryList").val());
106         if(isNaN(catid)) catid = 0;
107         
108         $.ajax({
109             url:'displayProduct.process.php',
110             type:'POST',
111             data:{searchString:searchString,catid:catid,type:'attr'},
112             dataType:'json',
113             success:function(data){
114                 if(data.status == 1){
115                     $(".product").hide();                   //先將所有產品隱藏,后面在通過搜索結果顯示相應的產品
116                     if(data.products.length == 0){          //如果搜索結果為空
117                         $("#emptyProduct").show();          //顯示“沒有搜索到結果!”
118                     }else {                                 //否則,隱藏“沒有搜索到結果!”,並逐個顯示搜索結果中的產品
119                         $("#emptyProduct").hide();
120                         $.each(data.products,function(i){
121                             $("#product-"+data.products[i]).show();
122                         });
123                     }
124                 }else {
125                     alert(data.msg);
126                 }
127             },
128             error:function(msg){
129                 alert(msg);
130             }
131         });
132     });
133 });
134 </script>
135 </body>
136 </html>

搜索程序后台源碼(displayProduct.process.php):

View Code
 1 <?php
 2 require 'product.model.php';
 3 switch($_POST['type']){
 4     case 'attr':
 5         echo json_encode(Product::searchProductByAttribute(mysql_escape_string($_POST['searchString']),(int)$_POST['catid']));
 6         break;
 7         
 8     case 'cate':
 9         echo json_encode(Product::searchProductByCategory((int)$_POST['catid']));
10         break;
11     default:
12         echo json_encode(array('status'=>0,'msg'=>'非法查詢類型!'));
13         break;
14 }
15 exit;

搜索程序后台數據處理層(product.model.php)源碼:

View Code
  1 <?php
  2 require '../db.php';
  3 class Product{
  4     public static function getCategoryList(){
  5         global $db;
  6         $sql = "SELECT id,name,0 AS ordering,id AS 'groupcol' FROM `ju_categories` WHERE parent=0
  7             UNION
  8             SELECT id,name,ordering,parent AS 'groupcol' FROM `ju_categories`
  9             WHERE parent IN(
 10             SELECT id FROM `ju_categories` WHERE parent=0
 11             ) ORDER BY `groupcol`,`ordering`";
 12         $result = mysql_query($sql,$db);
 13         $categoryList = '';
 14         while($row = mysql_fetch_assoc($result)){
 15             if($row['id'] != $row['groupcol']) $pref = '-';
 16             else $pref = '';
 17             $categoryList .= '<option value="'.$row['id'].'">'.$pref.$row['name'].'</option>';
 18         }
 19 
 20         $categoryList = '<select id="categoryList"><option value="0">Root</option>' . $categoryList . '</select>';
 21         return $categoryList;
 22     }
 23 
 24     public static function getAttributeList($search=false){
 25         global $db;
 26         $sql = "SELECT id,name,0 AS ordering,id AS 'groupcol' FROM `ju_attributes` WHERE parent=0
 27             UNION
 28             SELECT id,name,ordering,parent AS 'groupcol' FROM `ju_attributes`
 29             WHERE parent IN(
 30             SELECT id FROM `ju_attributes` WHERE parent=0
 31             ) ORDER BY `groupcol`,`ordering`";
 32         $result = mysql_query($sql,$db);
 33         $attributeList = '';
 34         if($search){
 35             while($row = mysql_fetch_assoc($result)){
 36                 if($row['id'] == $row['groupcol']) {
 37                     $attributeList .= '</ul><ul><li class="parentAttr">'.$row['name'].'</li>';
 38                 }else {
 39                     $attributeList .= '<li attr="'.$row['id'].'" class="searchAttr">'.$row['name'].'</li>';
 40                 }
 41             }
 42             if(stripos($attributeList,'</ul>') === 0) $attributeList = substr($attributeList,5);
 43             $attributeList .= '</ul>';
 44         }else {
 45             while($row = mysql_fetch_assoc($result)){
 46                 if($row['id'] != $row['groupcol']) {
 47                     $attributeList .= '<option value="'.$row['id'].'">-'.$row['name'].'</option>';
 48                 }
 49                 else {
 50                     $attributeList .= '<option value="'.$row['id'].'" class="parentAttr">'.$row['name'].'</option>';
 51                 }
 52             }
 53 
 54             $attributeList = '<select id="attributeList"><option value="0" class="root">-請選擇添加-</option>' . $attributeList . '</select>';
 55         }
 56         return $attributeList;
 57     }
 58 
 59     public static function save($data = array()){
 60         global $db;
 61         $name     = mysql_escape_string($data['name']);
 62         $sku     = mysql_escape_string($data['sku']);
 63         $catid     = (int)$data['catid'];
 64         $origPrice     = mysql_escape_string($data['origPrice']);
 65         $price     = mysql_escape_string($data['price']);
 66         $stock     = mysql_escape_string($data['stock']);
 67         $attrs     = implode(',',(array)$data['attrs']);
 68 
 69         if(empty($name)) {
 70             echo '分類名不能為空!';
 71             exit;
 72         }
 73 
 74         $sql = "INSERT INTO `ju_products`(`id`,`name`,`sku`,`catid`,`origPrice`,`price`,`stock`,`attributes`,`created_on`)"
 75             ." VALUES(null,'$name','$sku','$catid','$origPrice','$price','$stock','$attrs',now())";
 76         if(mysql_query($sql,$db)){
 77             $productId = mysql_insert_id($db);
 78             $sql = "INSERT INTO `ju_product_attributes`(`product_id`,`attribute_id`) VALUES";
 79             foreach($data['attrs'] as $attr){
 80                 $sql .="('$productId','$attr'),";
 81             }
 82             $sql = rtrim($sql,',');
 83             mysql_query($sql,$db);
 84             return true;
 85         }else {
 86             return false;
 87         }
 88 
 89     }
 90     
 91     public static function getProductList(){
 92         global $db;
 93         $productTpl = <<<TPL
 94             <div class="product" id="product-%d">
 95                 <div class="p_image"><img src="%s" alt="%s" width="150" height="200"/></div>
 96                 <div class="p_title">%s</div>
 97                 <div class="p_price">
 98                     <span>¥%.2f</span>
 99                     <del>¥%.2f</del>
100                 </div>
101             </div>
102 TPL;
103         $sql = "SELECT id,name,price,origPrice FROM `ju_products` ORDER BY id";
104         $result = mysql_query($sql,$db);
105         $productList = '';
106         while($row = mysql_fetch_assoc($result)){
107             $productList .= vsprintf($productTpl,array($row['id'],'#',$row['name'],$row['name'],$row['price'],$row['origPrice']));
108         }
109         return $productList;
110     }
111     
112     public static function searchProductByCategory($catid){
113         global $db;
114         if(!isset($catid)) return array('status'=>0,'msg'=>'分類不能為空!');
115         
116         $categories = self::getSubCategories($catid);        //默認遞歸包含子分類
117         $sql = "SELECT id FROM `ju_products` WHERE catid IN(".implode(',',$categories).") ORDER BY id";
118         $result = mysql_query($sql,$db);
119         $productArray = array();
120         while($row = mysql_fetch_assoc($result)){
121             array_push($productArray,$row['id']);
122         }
123         return array('status'=>1,'products'=>$productArray);
124     }
125     public static function searchProductByAttribute($searchString,$catid=0){
126         global $db;
127         if(empty($searchString)) return array('status'=>0,'msg'=>'搜索條件不能為空!');
128         
129         if(empty($catid)) $where = array();
130         else $where = array("p.catid IN(".implode(',',self::getSubCategories((int)$catid)).")");
131         $ands = explode('|',$searchString);
132         foreach($ands as $and){
133             $andString = "";
134             $ors = explode(',',$and);
135             foreach($ors as $or){
136                 $andString .= "LOCATE(',{$or},',pas.attribute_ids) OR ";
137             }
138             $andString = '('.substr($andString,0,strlen($andString)-4).')';        //-4去掉末尾“ OR ”
139             $where[] = $andString;
140         }
141         
142         $sql = "
143             SELECT p.id FROM `ju_products` as p
144             INNER JOIN (
145             SELECT product_id,concat(',,',group_concat(attribute_id),',,') as attribute_ids FROM `ju_product_attributes` GROUP BY product_id
146             ) as pas ON p.id=pas.product_id
147             WHERE ".implode(' AND ',$where)."
148             group by p.id
149         ";
150         $result = mysql_query($sql,$db);
151         $productArray = array();
152         while($row = mysql_fetch_assoc($result)){
153             array_push($productArray,$row['id']);
154         }
155         return array('status'=>1,'products'=>$productArray,'sql'=>$sql);
156     }
157     
158     public static function getSubCategories($pid,$recursive=true){
159         global $db;
160         $pid = (int)$pid;
161         $sql = "SELECT id FROM `ju_categories` as cate WHERE cate.parent=".$pid;
162         $result = mysql_query($sql,$db);
163         $subCategories = array($pid);    //加入當前分類
164         if($recursive){
165             while($row = mysql_fetch_row($result)){
166                 $subCategories = array_merge($subCategories,self::getSubCategories($row[0]));
167             }
168         }
169         return $subCategories;
170     }
171 }
172 
173 //End_php

數據庫連接文件(db.php)源碼:

View Code
 1 <?php
 2     static $connect = null;
 3     if(!isset($connect)){
 4         $connect = mysql_connect("localhost","Zjmainstay","") or die('無法連接數據庫!');
 5         mysql_select_db("test",$connect) or die('無法連接到指定數據庫!');
 6         mysql_query("SET NAMES UTF8",$connect);
 7         
 8         $db = $conn = $connect;
 9     }
10 
11 //End_php

 

重點:多屬性搜索方法

 1 public static function searchProductByAttribute($searchString,$catid=0){
 2         global $db;
 3         if(empty($searchString)) return array('status'=>0,'msg'=>'搜索條件不能為空!');
 4         
 5         if(empty($catid)) $where = array();
 6         else $where = array("p.catid IN(".implode(',',self::getSubCategories((int)$catid)).")");    //WHERE子句數組,分類搜索(getSubCategories方法默認含子分類)
 7         $ands = explode('|',$searchString);  //分離不同層級的屬性,如品牌與價格范圍
 8         foreach($ands as $and){
 9             $andString = "";
10             $ors = explode(',',$and);  //分離同一層級的多個屬性,如品牌中的"HP","華碩","聯想"等
11             foreach($ors as $or){
12                 $andString .= "LOCATE(',{$or},',pas.attribute_ids) OR ";  //對每個屬性進行LOCATE定位,定位目標為各個產品所有屬性組成的屬性串,格式為:,,26,33,3,21,,
13             }
14             $andString = '('.substr($andString,0,strlen($andString)-4).')';        //-4去掉末尾“ OR ”
15             $where[] = $andString;  //加入WHERE子句數組中
16         }
17         //使用group_concat(attribute_id)拼接每個產品的所有屬性,用於WHERE子句進行屬性LOCATE搜索
18         $sql = "
19             SELECT p.id FROM `ju_products` as p
20             INNER JOIN (
21             SELECT product_id,concat(',,',group_concat(attribute_id),',,') as attribute_ids FROM `ju_product_attributes` GROUP BY product_id
22             ) as pas ON p.id=pas.product_id
23             WHERE ".implode(' AND ',$where)."    //使用AND拼接WHERE子句數組
24             group by p.id
25         ";
26         $result = mysql_query($sql,$db);
27         $productArray = array();
28         while($row = mysql_fetch_assoc($result)){
29             array_push($productArray,$row['id']);    //將查得產品id加入$productArray數組中,響應請求。
30         }
31         return array('status'=>1,'products'=>$productArray,'sql'=>$sql);
32     }

 

 本文到此結束,謝謝大家耐心閱讀!

附:產品多屬性搜索源碼下載

 


免責聲明!

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



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