Уточнение результатов поиска на основе многоуровневых фильтров Mysql + PHP - PullRequest
0 голосов
/ 03 августа 2011

Я пытаюсь создать многоуровневый поиск, чтобы позволить пользователю уточнить тот же поиск в зависимости от бренда, категории продукта и диапазона цен (заказ не имеет значения).

Следующая реализация может работать не так, как естьпоскольку я только даю способ проиллюстрировать мою проблему.

Таблицы: продукты

|  id  |  name  | price_id  |
|  1   |  test1 |     1     |
|  2   |  test2 |     2     |
|  3   |  test3 |     1     |

Prices_ranges

|  id  |  price_from  | price_to  |
|  1   |     100      |    200    |
|  1   |     200      |    300    |

product_attributes

|  product_id  |  id_attribute  |
|      1       |        1       |
|      1       |        2       |
|      1       |        3       |
|      1       |        5       |
|      2       |        5       |
|      2       |        3       |
|      3       |        5       |

атрибуты

|  id  |  name     |
|  1   |   attr1   |
|  2   |   attr2   |
|  3   |   attr3   |
|  4   |   attr4   |
|  5   |   attr5   |
|  6   |   attr6   |
|  7   |   attr7   |

Я передаю аргументы в URL через $ _GET.И мой код для поиска по нескольким фильтрам выглядит примерно так:

//this generates the base query
$dynamicsql = get_by_filters();

//does the group by to discard duplicated products
$filtersql= $dynamicsql."group by p.id";
$query = mysql_query($filtersql) or die(mysql_error());
//the data is now ready to be presented but 
$total = mysql_num_rows($query);
for($i=0; $i<$total; $i++):
        $prods[$i] = mysql_fetch_object($query);
    endfor;

//first let's build the html code for filtering the results
list_prices_filter($dynamicsql);

//i'll only show the code for the bellow function. the above is pretty similar
list_attr_filter($dynamicsql);


//now i print the results
foreach($prods as $prod):
      //for the porpuse of this question will only print the product name
      echo $prod['pname'];
endforeach;

Функция для возврата отфильтрованного базового запроса

function get_by_filters(){

        $dynamicsql = "SELECT p.name as pname,p.price_from,p.price_to,a.name,a.id FROM `products` p ";
        $dynamicsql .= "left JOIN `price_ranges` pr ON p.price_id = pr.id ";
        $dynamicsql .= "LEFT JOIN `product_attributes` pa ON w.id = pa.product_id ";
        $dynamicsql .= "LEFT JOIN `attributes` a ON a.uid = pa.id_attribute where 1=1 ";

        foreach($_GET as $parameter=>$value):
                switch($parameter):

                    case 'price':
            $dynamicsql .= " AND p.price = ".$value;
            break;

                    //filtro por zip code
                    case 'attr':
                        $dynamicsql .= " AND a.id = ".$value;
                        break;
                    default:
                        $dynamicsql .= "AND ".$parameter." = ".$value." ";
                    break;
                endswitch;
        endforeach;

        return $dynamicsql;
}

Функция для вывода списка выбора атрибутов:

function get_special_care($dynamicsql){

    $sql = "SELECT * FROM attributes a";
    $query = mysql_query($sql);
    $total = mysql_num_rows($query);

    $output = '<ul>';
    for($i=0; $i<$total;$i++):
        $result[$i] = mysql_fetch_object($query);
        $active = ($_GET['attr'] == $result[$i]->uid) ? 'active':'';

        $workerstotal = mysql_query($dynamicsql  . "  and a.id ={$result[$i]->uid} group by p.id");
        $totalworkers = mysql_num_rows($workerstotal);

        $output .= '
            <li class="'.$active.'">
                <a href="'.url_increment('attr='.$result[$i]->uid).'">'.$result[$i]->name.'<span class="totalfound">('.$totalworkers.')</span></a>
                <a title="Remove" href="'.url_decrement('attr').'" class="remove-criteria"><img src="'image_src_url" alt="Remove" /></a>
            </li>';
    endfor;

    $output .= '</ul>';
    echo $output;
}

Функция url_increment () и url_decrement просто добавляет или удаляет этот фильтр в URL.Я не перечисляю это, потому что я думаю, что это не имеет отношения к проблеме.

Хорошо введение закончено !!Моя проблема в том, что если пользователь выбирает атрибут 5 на первом шаге, код показывает продукт 1, 2 и 3, но я не могу снова фильтровать атрибуты!

В этом случае функция get_special_care ($ Dynamicsql) говоритчто для атрибута 1, 2 есть 0 продуктов (и для продукта 1 должен быть один) и 3 (для продуктов 1 и 2 должно быть два совпадения).

Я почти уверен, что это из-зафункция, которая генерирует базовый запрос в:

case 'attr':
    $dynamicsql .= " AND a.id = ".$value;
    break;
default:

Но я не могу понять, как решить эту проблему.

Также есть другая проблема с этим кодом, потому что после выбора атрибута дляпервый раз URL выглядит как www.teste.com/search&attr=5.После второго щелчка (скажем, пользователь нажимает атрибут 1), URL будет www.teste.com/search&attr=5&attr=1, что также является проблемой (я думаю)

Кто-нибудь может помочь?Я уверен, что многие из вас реализовали аналогичные алгоритмы, и если бы вы могли помочь, было бы здорово.

И наконец, извините за длинный пост, но я хотел объяснить себя и, возможно, он послужит справкой для будущей помощи...

Заранее спасибо !!

Ответы [ 2 ]

1 голос
/ 04 августа 2011

Мне удалось решить эту проблему следующим образом:

создал функцию для получения всех атрибутов из URL-адреса (обычный $ _GET ['name'] ony возвращает атрибут = 5 в URL-адресе, например www.test.com/?mod=search&attribute=2&attribute=5

function getFilter(){
        $query  = explode('&', $_SERVER['QUERY_STRING']);
        $params = array();
    foreach( $query as $param )
    {
      list($name, $value) = explode('=', $param);
      $params[urldecode($name)][] = urldecode($value);
    }
    return $params;

}

тогда я изменил функцию get_by_filters

function get_by_filters(){

    $dynamicsql = "SELECT p.name as pname,p.price_from,p.price_to,a.name,a.id FROM `products` p ";
    $dynamicsql .= "left JOIN `price_ranges` pr ON p.price_id = pr.id ";
    $dynamicsql .= "LEFT JOIN `product_attributes` pa ON w.id = pa.product_id ";
    $dynamicsql .= "LEFT JOIN `attributes` a ON a.uid = pa.id_attribute where 1=1 ";

    foreach($_GET as $parameter=>$value):
            switch($parameter):

                case 'price':
        $dynamicsql .= " AND p.price = ".$value;
        break;

                //changes here
                case 'attr':
                    $get = tools::getFilter();
            foreach ($get['attr'] as $attrs => $value) {
        $filter .= " and w.uid in (select a from `product_attributes` where attribute_id= {$value}) ";
                    }
                default:
                    $dynamicsql .= "AND ".$parameter." = ".$value." ";
                break;
            endswitch;
    endforeach;

    return $dynamicsql;
}

и, наконец, мы должны представить все фильтры активных атрибутов, поэтому я изменил эту функцию следующим образом:

function get_special_care($dynamicsql){

    $sql = "SELECT * FROM attributes a";
    $query = mysql_query($sql);
    $total = mysql_num_rows($query);

    //changes here        
    $get = tools::getFilter();

    $output = '<ul>';
    for($i=0; $i<$total;$i++):
        $result[$i] = mysql_fetch_object($query);

        //changes here
        foreach ($get['attr'] as $attr => $value) {
        $active = ($value == $result[$i]->uid) ? 'active':$active;
    }


        $workerstotal = mysql_query($dynamicsql  . "  and a.id ={$result[$i]->uid} group by p.id");
        $totalworkers = mysql_num_rows($workerstotal);

        $output .= '
            <li class="'.$active.'">
                <a href="'.url_increment('attr='.$result[$i]->uid).'">'.$result[$i]->name.'<span class="totalfound">('.$totalworkers.')</span></a>
                <a title="Remove" href="'.url_decrement('attr').'" class="remove-criteria"><img src="'image_src_url" alt="Remove" /></a>
            </li>';
    endfor;

    $output .= '</ul>';
    echo $output;
}
1 голос
/ 03 августа 2011

Единственная ошибка, которую я могу заметить, это

 case 'price': $dynamicsql .= " AND p.price = ".$value;

p.price относится к products.price, где в таблице происхождения товара нет поля цены.

Есть ли исключения из запросов?

...