Только для читателей Lifeexample возможно открыть интернет-магазин на Moguta.CMS со скидкой в 15%

<<< htaccess запретить доступ || Формат JSON >>>

Модули интернет магазина

20.02.2012
Модули интернет магазина

Здравствуй уважаемый читатель блога LifeExample, в этой статье мы продолжим создавать наш интернет магазин своими руками, используя только php и mysql. По плану я хотел начать в этом уроке рассматривать библиотеку JQuery но, кажется до нее еще рановато. В предыдущем уроке посвященном разработке фундамента интернет магазина, я выложил для скачивания готовую MVC систему, на примере которой рассказал о принципах и основах взаимодействия ее составляющих.

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

Если ты читатель в предыдущем уроке не скачал архив, с основой интернет магазина можешь сделать это сейчас:

Листинг урока №1 ( Скачали: 24420 чел. ) 


Листинг урока №2 ( Скачали: 6793 чел. ) 

Любой интернет магазин должен иметь такие составляющие:

  1. Каталог
  2. Систему наполнения каталога
  3. Карточки товаров
  4. Маленькая корзина
  5. Большая корзина
  6. Форма оформления заказа
  7. Информация о доставке и оплате

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

Каталог (Модуль представления каталога)

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

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

В реальности таблица может разрастить такими полями как описание, наличие на складе, артикул продукта, особыми ценами, и многими другими параметрами. Кстати к концу этой статьи мы добавим несколько полей в таблицу.

Сейчас таблица имеет такой вид:

Таблица для модуля каталога

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

Каталог модуля интернет магазина

Картинки хранятся в папке /images , где все они пронумерованы в соответствии с номерами продуктов. Другими словами, если мы создадим новый продукт в таблице, и его номер будет равен 7 , то картинка для этого продукта должна находиться в /images и именоваться как 7.jpg. Такой подход не совсем верный, и имеет ряд плюсов и минусов, правильнее было бы именовать картинки в соответствии с артикулами продуктов. Но так как разрабатываемый интернет магазин всего лишь урок, то для простоты понимания механизма оставим все как есть сейчас. В будущем доработаем этот недочет

На данный момент модуль каталога работает таким образом:

  1. Система получает запрос на открытие страницы http://lifeexampleshop.ru/catalog
  2. Соответствующий контролер /application/controllers/catalog.php запрашивает у модели информацию из БД по каталогу.
  3. Модель /application/models/catalog.php извлекает из БД необходимую информацию и передает в представление.
  4. Представление показывает нам содержимое каталога в строчку по три продукта.

Система наполнения каталога (Модуль авторизации)

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

Для того чтобы не лезть каждый раз в mySQL таблицу вручную, мы сделаем специальный модуль интернет магазина реализующий интерфейс для добавления товаров и редактирования уже существующих.

Замечу! Что добавлять товары сможет только пользователь с правами администратора, поэтому нам нужно будет создать отдельную таблицу в базе данных и вносить в нее всех пользователей системы.

Создадим таблицу user и внесем в нее запись администратора.

Таблица для модуля авторизации

В идеале пароль должен храниться в md5 хеше, но как видите тут все без премудростей, зато логика работы скриптов как на ладони:

1
2
Логин: admin
Пароль: 1

В нашей системе уже действует механизм авторизации, но он примитивен и не использует связь с БД, исправим это. Откроем скрипт модуля авторизации (/application/models/auth.php), и изменим метод ValidData():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function ValidData($login,$pass){

  $sql = "SELECT * FROM user WHERE login='$login' and pass='$pass'";
  $result = mysql_query($sql) or die(mysql_error());
 
  if(mysql_num_rows($result))
  {
   $_SESSION["Auth"]=true;  
   $_SESSION["User"]=$login;  
  }
  else $_SESSION["Auth"]=false;  

  if (!$_SESSION["Auth"]){
   $msg="<em><span style='color:red'>Данные введены не верно!</span></em>";
  }
  else {
   $msg="<em><span style='color:green'>Вы верно ввели данные!</span></em>";
   $unVisibleForm=true;
  }
       
  $result=array("unVisibleForm"=>$unVisibleForm,
        "userName"=>$login,
        "msg"=>$msg,
        "login"=>$login,
        "pass"=>$pass,);
  return $result;
}

Коротко о том, что здесь происходит: функция ValidData() получает данные логин и пароль, формирует запрос к БД, в котором пытается найти соответствующую пару, если пара найдена, то авторизация прошла успешно, и в сессию записывается информация о пользователе. Также в переменную $result передается массив значений переменных, который будет доступен контролеру, и тот сможет его корректно обработать и передать необходимую информацию в представление.

Подробная информация о продукте (Модуль карточка товара)

В этом уроке можно было бы обойтись и без карточек товара, но все же для полноты картины создадим еще один важный модуль интернет магазина. Коротко говоря, карточка товара это отдельная страница товара, на которой представлена полная информация и характеристика предлагаемой продукции. С этой страницы, также как и из каталога, пользователь может добавить товар в корзину.

В представленной MVC системе такого функционала еще нет, поэтому сейчас мы его и разработаем.

Создадим три файла product.php и перенесем их в папки views, controllers и models.

Начнем с представления. Файл представления product.php будет иметь следующий вид:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<h1><?=$product['name']?></h1>
<div class="card_product">
 <div class="product_image">
  <image src="/images/<?=$product['id']?>.jpg" />
 </div>

 <div class="product_desc">
  <?=$product['desc']?>                
 </div>

 <div class="price">
  <?=$product['price']?> руб.                   
 </div>

 <div class="product_buy">
  <a href="/">Купить</a>
 </div>

</div>

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

Как вы обратили внимание в коде идет работа с массивом $product, для того чтобы его передать в представление с помощью контролера нам нужно сгенерировать этот массив в модели.

Создадим модель product.php, ее код будет выглядеть так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Application_Models_Product
{    
  function getProduct($id)
  {
    $sql = "SELECT * FROM product WHERE id='$id'";
    $result = mysql_query($sql)  or die(mysql_error());

    if($row = mysql_fetch_object($result))
    {        
      $product=array(
    "id"=>$row->id,
    "name"=>$row->name,
    "desc"=>$row->desc,
    "price"=>$row->price
    );     
   }
 return $product;
  }
}

Все что делает эта модель, это получает данные из БД о конкретном продукте по id и передает их контролеру в массиве $product.

Контролер в свою очередь возвращает данные в представление:

1
2
3
4
5
6
7
8
9
class Application_Controllers_Product extends Lib_BaseController
  {
    function index()
     {
      $model=new Application_Models_Product;
      $product = $model->getProduct($_REQUEST['id']);  
      $this->product=$product;
     }
  }

Примечание! С помощью данных из $_REQUEST[‘id’] контролер сообщает модели информацию какого именно продукта нужно вернуть.

Внимание! Еще раз повторю что для работы контролера нужно в GET параметрах передать id запрашиваемого продукта, очень важно запомнить это сечас, так как в дальнейшем нам придется к этому вернуться.

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

1
<a href="/product?id='.$item["id"].'">'.$item["name"].'</a>

В итоге этих не хитрых манипуляций мы видим результат:

Карточка товара

Все бы было хорошо, если бы не одно большое НО! Обратим внимание на ссылки товаров, которые у нас получились:

1
2
3
4
/product?id=1
/product?id=2
/product?id=3
/product?id=4

Вид у них просто отвратительный, с точки зрения SEO оптимизации. Для поисковиков более престижным является вид ссылок такого рода:

1
2
3
4
/product/kompyuternaya-mysh
/product/monitor
/product/klaviatura
/product/kolonki

Чтобы нам получить такой красивый вид ссылок, нужно познакомиться с понятием ЧПУ!

ЧПУ человекопонятные урлы, тоесь ссылки которые можно прочесть и понять смысл их содержимого.

Давайте теперь сделаем так чтобы при переходе по ссылке:

1
http://lifeexampleshop.ru/product?id=2

И при переходе по ссылке:

1
http://lifeexampleshop.ru/product/monitor

Мы попадали на одну и туже страницу.

На самом деле это не так сложно как может показаться с первого взгляда, но требуются крепкие базовые знания php. Сначала нам нужно добавить в таблицу product каждому продукту значение, по которому к нему можно будет обратиться из url:

Таблица для модуля ЧПУ

Теперь давайте в классе Lib_Application изменим метод getRoute() который отвечает за маршрутизацию ссылок.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private function getRoute() {
if (empty($_GET['route']))
{
   $route = 'index';
}
else
{
   $route = $_GET['route'];            
   $rt=explode('/', $route);
   $route=$rt[(count($rt)-1)];

   if($rt[(count($rt)-2)]=="product"){         
    $sql = "SELECT * FROM product WHERE url like '$route'";
    $result = mysql_query($sql)  or die(mysql_error());
           
    if($row = mysql_fetch_object($result))
    {
      $_REQUEST['id']=$row->id;
      $route="product";
    }
               
   }
 }

return $route;
}

При запуске MVC системы функция getRoute() одна из первых имеет честь быть вызванной. Её задачей является определить название контролера, которому нужно передать управление. Другими словами ссылка любого вида сначала попадает на кухню данной функции, где она обрабатывается и из нее вычисляется название необходимого контролера. Таким образом, мы можем попытаться перейти по абсолютно любой ссылке, а функция в свою очередь должна определить может ли система предложить нам какую-то страницу по запрашиваемой нами ссылке или нет.

Вот в эту функцию мы и вставим обработчик наших человекопонятных (чпу) ссылок. Допустим, мы пытаемся перейти по ссылке:

1
http://lifeexampleshop.ru/product/monitor

Это значит, что должен отработать контролер product.php, чтобы выявить этот факт функция проверяет не находится ли в пути ссылке ключевое слово product.

1
if($rt[(count($rt)-2)]=="product")

Если все сходится и ссылка содержит раздел product, причем он должен быть предпоследним в пути, то контролер считается определенным и далее система передает управление в /application/controllers/product.php.

Еще одним важным моментом является параметр id, который должен быть передан в контролер. Выше я обращал внимание на то, что контролер получает id из массива $_REQUEST, самое время вспомнить об этом.

Если id не будет передан, контролер не сможет запросить у модели необходимую информацию. Поэтому мы обращаемся к таблице product в нашей БД и находим соответствующий id.

В нашем случае [url = monitor], а [id = 2]. Это значит, что нам надо записать этот номер в массив $_REQUEST:

1
$_REQUEST['id']=$row->id;

После этих действий ссылка вида:

1
http://lifeexampleshop.ru/product/monitor

системой будет пониматься точно также как и ссылка:

1
http://lifeexampleshop.ru/product?id=2

И результаты вывода будут идентичны.

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

Скачать Листинг урока №2. ( Скачали: 6793 чел. ) 


<<< Предыдущий урок | Следующий урок >>>

Чтобы не пропустить публикацию следующей статьи подписывайтесь на рассылку по E-mail или RSS ленту блога.

Нравится

Комментарии

  • Анастасия

    Хорошая статья, спасибо. Жду продолжения.

  • Андрей

    Отличная статья, полезно про реализацию ЧПУ.

  • Дiмка

    Думал в этой статье найду ответ… Что такое $member[‘init’]=0 в index.php???

    • Mark

      $member[‘init’]=0 — аналог строчке:

      1
      if (isset($member))

      Можешь попробовать подставить её, так думаю будет более прозрачно ;- )

  • Дiмка

    Кстати, таким же образом можно заменить /enter?out=1 при выходе из личного кабинета что то вроде /enter/out добавив в Lib_Application:

    1
    2
    3
    4
    if($rt[(count($rt)-2)]=="enter" and $route="out"){               
                     $_REQUEST['out']=1;
                        $route="enter";
                     }

    и в view/enter.php заменить ссылку на /enter/out

    Как то так…

    • Mark

      Относительно /enter/out , да можно сделать так почему бы и нет. Радует, что начали поступать предложения по улучшению кода, ибо это говорит о том, что кто-то все таки его пытается понять. Наверное стоит сказать что в данном коде не паханное поле для его оптимизации. От части это сделано умышлено, для того чтобы вы сами напрягали мозги а не просто запускали на исполнение всю систему и наблюдали за подтверждением теории.

  • Павел

    Возникли проблемы при реализации ЧПУ.
    Код срабатывает, но отваливается .сss файл!
    не срабатывает RewriteCond %{REQUEST_FILENAME} !-f в чем может быть проблема?
    п.с. делал все как в примере… вроде бы)))

  • Павел

    Прописал полный путь для .css файла, все работает. Но все ровно не могу понять в чем была проблема..

    • Максим

      Тоже столкнулся с етой ошыбкой и не понимаю так где прописовать полное имя css файла?

  • Сергей

    почему при попытке перейти по ссылке каталог или вход, перекидывает на служебную страницу денвера.

  • Дiмка

    Сергей, я думаю, дело в «хитрой» структуре папок в Denwerе…
    Если Ваша папка расположена, как рекомендуют создатели, в директории Z:\home\localhost\www\, то в этом случае в путь к сайту примешивается \localhost\… И система ищет эту папку в названиях контроллера для исполнения.
    В таком случае рекомендую Вам перенести проект следующем образом…
    Z:\home\имя_вашего_проекта\www\ и в этой директории уже размещать Ваш проект

  • aleksey_ov

    ИМХО, для полноты картины надо маленькое замечание сделать
    относительно вот этой записи:

    1
    $sql = "SELECT * FROM product WHERE url like '$route'";

    В таблице БД поле url надо сделать уникальным (unique), а то на 2-3 разных товара в этой поле одно значение пропишут и что будет тогда? Мне думается надо бы поправить мальца)

    • В данном случае при одинаковых URL будет выведен товар занесенный в БД последним.
      Все в ваших силах, если считаете нужным правьте. 😉

  • Igor

    Mark, Здравствуй!
    У меня следующая проблема при добавлении базы в phpmyadmin

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    Error
    SQL query:

    --
    -- База данных: `LifeExampleShop`
    --
    -- --------------------------------------------------------
    --
    -- Структура таблицы `order`
    --
    CREATE TABLE IF NOT EXISTS  `order` (

     `id` INT( 11 ) NOT NULL AUTO_INCREMENT ,
     `date` INT( 11 ) NOT NULL ,
     `name` VARCHAR( 255 ) NOT NULL ,
     `email` VARCHAR( 255 ) NOT NULL ,
     `phone` VARCHAR( 255 ) NOT NULL ,
     `adres` VARCHAR( 255 ) NOT NULL ,
     `summ` VARCHAR( 255 ) NOT NULL ,
     `order_content` VARCHAR( 255 ) NOT NULL ,
    PRIMARY KEY (  `id` )
    ) ENGINE = MYISAM DEFAULT CHARSET = utf8 AUTO_INCREMENT =80;

    MySQL said:

    #1046 - No database selected

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

    • Ошибка говорит о том что вы не выбрали базу в которую хотите импортировать таблицы. Я подробно описал алгоритм добавления в комментариях к уроку номер пять. Смотрите в конце комментариев, также там есть скриншот.

  • Александр

    Добрый день. Подскажите по функционалу:
    Нужно сделать переключатель в описании товара, или поле которое содержит число ( это не сложно, нашел).
    А затем цену в корзину считать как — умножить ‘price’ на число введенное в поле. Где это сделать? В каком файле?

    • Если вы добавили поле с числом в таблицу.
      То вам нужно немного изменить модели product.php и cart.php

  • Александр

    Нет, я наверное не совсем правильно объяснил. Грубо говоря, мне при нажатии на кнопку «Купить» нужно умножать цену на число которое ввел пользователь.
    Подскажите, где происходит обработка события «Купить»

    • Александр, в любом случае весь расчет стоимости происходит в модели cart.php. А для того, чтобы передать необходимое число, нужно использовать форму, и соответствующий для нее обработчик. Эта задача требует определенных знаний, и вам следует обратиться к профессионалам. Или ко мне через форму обратной связи, для уточнения ТЗ.

  • алексей

    А как переделать сам катало в виде дерева раскрывающим tree не как не идёт

  • Евгений

    У меня проблема, пользуюсь AppServ, при переходе по ссылкам , перекидывает на служебную страницу. И еще отваливается css при реализации ЧПУ

  • oleh

    А в контролере не нужно session_start() ? А то у меня не работает авторизация.

  • oleh

    Разве в контролере не нужно session_start() ? А то у меня не работает авторизация.

  • Олег

    Здравствуйте!
    Скажите, пожалуйста, как вы сделали так, что в ссылках нет расширения .php? (product?id=4)

    • С помощью .htaccess и маршрутизатора.

  • Александр

    Добрый вечер, Марк! Можете подсказать, как сделать чтобы выходя из карточки товара через кнопку «назад» попадать не в общий каталог, а в раздел данного товара? Буду очень благодарен за помощь, т.к. мой мозг юного программиста уже дымится)))

  • Олег

    «С помощью .htaccess и маршрутизатора.».. а можно пример? Уж больно хочется научиться такое же делать.

  • Олег, пример листинге урока.

  • Иван

    Как создать таблицу user и внести в неё запись администратора?

    • Не понимаю вашего вопроса. Также как и любую другую таблицу.

  • Алексей

    вот я чайник php код совсем не понимаю,но так чувствую что он мне родной

  • Andy

    Здравуствуйте. А можно сделать что бы модель Application_Models_Product совместить с Application_Models_Catalog что бы не создавать отдельные файлы?

  • Алексей

    Здравствуйте Mark!
    Подскажите пожалуйста зачем мы наследуем контроллер Lib_BaseController? что конкретно он делает? я что то не до понимаю.
    Спасибо заранее.

    • Дает возможность задавать набор переменных, которые потом будут доступны в представлении.

  • Andy

    Подскажите пожалуйста.

  • Andi

    Здравствуйте. Разбираю Ваши уроки. Не понял в контроллере каталога
    class Application_Controllers_Catalog extends Lib_BaseController
    {
    function index()
    {
    $model=new Application_Models_Catalog;
    $Items = $model->getList();
    $this->Items=$Items;

    }
    }
    В переменную $Items мы получили список товаров. Что
    делает строчка $this->Items=$Items; Мы же не создавали в классе переменную $Items. Или переменная приравнивается к самой себе? Можно ли return $Items; вместо этого?

  • Сергей

    А как реализовать в роутере принцип вложеных категорий. можно просто на словах . что как разбиваем ..

  • lufter

    еще важно чтоб в каталоге ссылки были сразу ЧПУ, я изменил в ссылке id на url

    1
    <a href="/product/'.$item["url"].'">'.$item["name"].'</a>

    я заменил заменил код работы с базой на PDO у меня в массив урл сразу попадает, вам нужно в модельном файле каталога добавить урл в массив

    1
    2
    3
    4
    5
    6
    $сatalogItems[]=array(
    "id"=>$row['id'],
    "name"=>$row['name'],
    "price"=>$row['price'],
    "url"=>$row['url']
    );
  • Борис

    ‘.$item[«name»].’

    Подскажите пожалуйста куда вставить этот код, что я не могу понять!? Заранее спасибо!!!

  • Макс

    При открытии какого либо товара пишет «No database selected» на месте информации о товаре
    Что может быть?

  • Максим

    Столкнулся с тем что если набираю product/monitor стили пропадают

  • Михаил

    а как открыть базу данных, если пишет неверный пользователь?

  • Оставить комментарий

    Не отвечать

    Подписаться на комментарии к этой статье по RSS

    Яндекс.Метрика