Фильтры в интернет-магазине. Урок 4. Пишем базовый php-код

сентябрь 4 , 2016
Предыдущая статья Следующая статья Демо Исходники

В предыдущем уроке мы научились собирать данные на клиенте и отправлять их на сервер. А на сервере написали заглушку в том месте, где должны возвращаться товары, отфильтрованные по введенным параметрам. Сейчас мы избавимся от заглушки и напишем пару методов и запросов, которые вытаскивают из базы нужные товары и возвращают их клиенту. Урок достаточно короткий. Приступаем


Что будем делать?

Нам нужно выполнить всего 3 пункта:

  • 1. Получить данные с клиента и обработать их под нужды сервера. Например, проставить параметры по умолчанию
  • 2. Написать, собственно, сам код для извлечения товаров из базы. В первую очередь, подготовить sql-запрос
  • 3. Вернуть клиенту полученные данные


Получение данных с клиента

Вы можете спросить: для чего нужно выделять эту простую операцию отдельно, если все данные мы легко вытащим из массива $_GET?

Во-первых, для того, чтобы проставить значения по умолчанию. Нельзя полагаться на то, что клиент сам позаботится об этом.

Во-вторых, не все данные находятся в $_GET в пригодном для использования виде. Например, сортировку с клиента нам удобнее передавать одним параметром в виде поле_направление, например, price_asc. Но в sql-запросе это отдельные сущности, поэтому их нужно предварительно обработать.

Похожая ситуация и с брендами. На клиенте мы отправляем их в виде массива brands, и php их получает тоже как массив. Но для sql-запроса нужна строка - список брендов через запятую. Поэтому бренды тоже нужно дополнительно обрабатывать.

Итак, напишем функцию getOptions(), которая вытащит данные из $_GET и преобразует их в удобный нам вид. Почти все вводные я уже сообщил, поэтому сразу смотрим на готовый код.

    // Получение данных из массива _GET
    function getOptions() {
        // Категория и цены
        $categoryId = (isset($_GET['category'])) ? (int)$_GET['category'] : 0;
        $minPrice = (isset($_GET['min_price'])) ? (int)$_GET['min_price'] : 0;
        $maxPrice = (isset($_GET['max_price'])) ? (int)$_GET['max_price'] : 1000000;
    
        // Бренды
        $brands = (isset($_GET['brands'])) ? implode($_GET['brands'], ',') : null;
    
        // Сортировка
        $sort = (isset($_GET['sort'])) ? $_GET['sort'] : 'price_asc';
        $sort = explode('_', $sort);
        $sortBy = $sort[0];
        $sortDir = $sort[1];
    
        return array(
            'brands' => $brands,
            'category_id' => $categoryId,
            'min_price' => $minPrice,
            'max_price' => $maxPrice,
            'sort_by' => $sortBy,
            'sort_dir' => $sortDir
        );
    }

Здесь мы видим, что сначала получаем id категории. Если категория не передана, мы считаем category_id = 0. Минимальная цена будет 0, максимальная - 1 миллион. Если Ваш интернет-магазин продает плутоний (нефть китайцам, муравьев поштучно), то Вы всегда можете добавить нулей в нужную строку или на худой конец вести расчеты в евро.

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

Сортировку преобразуем по-другому. Отдельно вытаскиваем поле сортировки и параметр: asc или desc.

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


Подготовка sql-запроса и извлечение данных из базы

Все данные подготовлены в нужном нам виде, теперь напишем запрос и выполним его. Этим будет заниматься функция getGoods($options, $conn). В параметрах она принимает $options - данные, подготовленные предыдущей функцией, и $conn - объект подключения к БД, который мы создали в предыдущем уроке. Наша задача - написать sql-запрос. В общем виде он выглядит так:

    select
        g.id as good_id,
        g.good as good,
        b.brand as brand,
        g.price as price,
        g.rating as rating,
        g.photo as photo
    from
        goods as g,
        brands as b
    where
        g.category_id = выбранная_категория and 
        g.brand_id in (список_брендов_через_запятую) and
        g.brand_id = b.id and
        (g.price between минимальная_цена and максимальная_цена)
    order by поле_сортировки направление_сортировки

Мы извлекаем нужные поля, применив ряд условий where и указав нужную сортировку. С ценами и сортировкой вопросов нет, просто подставляем в соответствующие места запроса нужные значения. Но с категорией и брендами нужно быть повнимательнее и вот почему.

Каждый товар у нас всегда имеет категорию. Понятия нулевой категории в нашей базе данных нет - мы это сделали для своего же удобства, чтобы понимать, что пользователь в браузере не выбрал никакую категорию (или выбрал все - для нас это одно и то же). И в этом случае мы не должны включать в запрос строчку
g.category_id = выбранная_категория and
То же самое и с брендами, если они не выбраны, то соответствующую строку пропускаем. Вот как это выглядит в коде.

    // Получение товаров
    function getGoods($options, $conn) {
        // Обязательные параметры
        $minPrice = $options['min_price'];
        $maxPrice = $options['max_price'];
        $sortBy = $options['sort_by'];
        $sortDir = $options['sort_dir'];
    
        // Необязательные параметры
        $categoryId = $options['category_id'];
        $categoryWhere =
            ($categoryId !== 0)
                ? " g.category_id = $categoryId and "
                : '';
    
        $brands = $options['brands'];
        $brandsWhere =
            ($brands !== null)
                ? " g.brand_id in ($brands) and "
                : '';
    
        $query = "
            select
                g.id as good_id,
                g.good as good,
                b.brand as brand,
                g.price as price,
                g.rating as rating,
                g.photo as photo
            from
                goods as g,
                brands as b
            where
                $categoryWhere
                $brandsWhere
                g.brand_id = b.id and
                (g.price between $minPrice and $maxPrice)
            order by $sortBy $sortDir
        ";
    
        $data = $conn->query($query);
        return $data->fetch_all(MYSQLI_ASSOC);
    }

Сначала мы извлекаем из массива $options переменные цен и сортировок - они просто вставляются в запрос без изменений. А для категории и брендов мы формируем строки $categoryWhere и $brandsWhere по принципу: нужное условие для секции where, если данные есть, и пустая строка если данных нет. Таким образом получился достаточно вменяемый sql-запрос, учитывающий все наши пожелания. Две последние строчки выполняют оный запрос и возвращают из функции массив из объектов с нужными полями. Осталось собрать все в кучу и отправить полученные товары обратно уже заждавшемуся клиенту/браузеру.


Возвращаем товары клиенту

Это самая простая часть урока. Посмотрим на заглушку, написанную в предыдущем уроке.

    // Подключаемся к базе данных
    $conn = connectDB();

    // Возвращаем клиенту успешный ответ
    echo json_encode(array(
        'code' => 'success',
        'data' => $_GET
    ));

Заменим этот код на

    // Подключаемся к базе данных
    $conn = connectDB();

    // Получаем данные от клиента
    $options = getOptions();

    // Получаем товары
    $goods = getGoods($options, $conn);

    // Возвращаем клиенту успешный ответ
    echo json_encode(array(
        'code' => 'success',
        'options' => $options,
        'goods' => $goods
    ));

Мы добавили пару строк: функцией getOptions извлекли данные в переменную $options. Тут же использовали ее в получении товаров getGoods, результаты сохранили в $goods. И расширили ответ клиенту. Параметр data переименовали в options и вернули в него не содержимое $_GET, а уже преобразованные значения. И в параметре goods вернули массив полученных товаров.

На этом урок закончен. Пока мы не можем использовать эти данные на клиенте, отрисовать их в браузере - этим мы займемся на следующем уроке. Но всегда можем открыть консоль, потыкать кнопочки и галочки и убедиться, что сервер возвращает нам правильные товары.


Проверяем результаты работы

Выберем категорию Смартфоны и отметим бренды Apple и Samsung. В ответе увидим, что сервер вернул 3 товара, отсортированных по возрастанию цены

Теперь поставим минимальную цену в 20 тысяч и сменим сортировку на убывание цены Как видно, теперь всего 2 товара - один самсунг отбросился из-за неподходящей по фильтрам цены в 17 тысяч. И отсортированы товары уже наоборот. Если Вы все сделали правильно, то увидите точно такую же картинку.

Вы можете еще поиграть с консолью и убедиться, что данные возвращаются корректно. В конце концов, самое важное - это добиться правильной работы фильтров, возврата правильного списка товаров. Раскидать полученные данные по странице, с учетом уже готовой верстки - дело внешне самое интересное, но с точки зрения разработки достаточно простое. Но не буду забегать вперед - подробности в следующем уроке.

Предыдущий урок серии - Фильтры в интернет-магазине. Урок 3. Как собрать данные на клиенте и отправить их на сервер
Следующий урок - Фильтры в интернет-магазине. Урок 5. Принимаем данные с сервера и отображаем их на клиенте

Все об интернет-магазинах

Предыдущая статья Следующая статья Демо Исходники
Заходите в группу в контакте - https://vk.com/webdevkin
Анонсы статей, обсуждения интернет-магазинов, vue, фронтенда, php, гита.
Истории из жизни айти и обсуждение кода.
Как Вам статья? Оцените!