Разработка интернет-магазина одежды

Дипломная работа

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

Что же такое интернет-магазин? Это специальный сайт, на котором мы можем посмотреть предлагаемые товары, внимательно изучить особенности той или иной модели, оплатить, не выходя из дома и получить сам товар с доставкой на дом.

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

  • Экономия денежных средств
  • Экономия времени
  • Возможность для клиентов приобретать необходимые товары 24 часа в сутки

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

Плюсы интернет-магазина:

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

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

Товар мы можем доставлять при желании сами. Либо же воспользоваться службой доставки.

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

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

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

Минусы интернет-магазина:

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

40 стр., 19682 слов

Маркетинг интернет-магазина

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

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

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

Частично к минусам можно отнести доставку. Если мы не планируем сами развозить товар, то столкнемся с тем, что не все службы готовы сотрудничать с интернет-магазинами.

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

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

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

Цель работы — изучить принципы построения интернет-магазина, разработать сайт интернет-магазина одежды «Goodstore».

Исходя из поставленной цели, были определены задачи:

  • обоснование необходимости создания интернет-магазина;
  • проведение анализа и выбор интернет-технологий для разработки интернет-магазина;
  • разработка сайта интернет-магазина, управляемого базой данных;
  • оценка эффективности выполненной разработки.

интернет магазин база данные

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

1.1 Язык программирования PHP

  • это технология с открытым исходным кодом, предназначенная для генерации динамического, интерактивного веб-контента [1].

Как говорится в ее официальном описании, “PHP — широко используемый интерпретируемый язык общего назначения, особенно удобный для веб-приложений, который может встраиваться в HTML”.

“PHP” расшифровывается как “PHP”: “Hypertext Preprocessor”, и его можно бесплатно загрузить с официального сайта. История PHP началась примерно с 1994 года и представляет собой пример впечатляющего успеха. Среди факторов, обусловивших этот успех, можно упомянутьследующие:

  • PHP бесплатен. Если его использовать в сочетании с серверными программами под управлением Linux, он представляет собой экономическиэффективную платформу для генерации динамического веб-контента.
  • PHP легче изучать, чем большинство других интерпретируемых языков.
  • Существует большое сообщество разработчиков, использующих PHP. Естьмножество разнообразных библиотек для PHP и в них регулярно добавляются новые возможности.
  • PHP хорошо работает с разными веб-серверами и операционными системами (семейств Unix, Windows или MacOS).
    11 стр., 5068 слов

    Разработка технического задания для автоматизации магазина ‘Буква’

    ... - это процесс реинжиниринга. Цель данной курсовой работы - автоматизация управления и учета деятельности ноутбук - салона "Буква". Магазин занимается не только розничной торговлей ноутбуками ... меняющаяся законодательная база. Снижение объема продаж. Большая конкуренция Недостатки магазина: Отсутствие интернет версии магазина, которая позволила бы расширить круг клиентов нашей компании. Возможности: ...

Однако PHP — отнюдь не единственный серверный интерпретатор, позволяющий генерировать динамические веб-страницы. Среди его конкурентов можно упомянуть JavaServer Pages (JSP), Perl, ColdFusion и ASP.NET. У этих технологийесть свои особенности, но в целом они предназначены для решения одних и тех жезадач. Например, страницы, сгенерированные с помощью любой из этих технологий, состоят из простого HTML, отвечающего за статичную часть страниц (шаблон)и кода, генерирующего динамическую часть.

Программа на PHP (да и на любом другом языке программирования) — это набор команд (инструкций) [2].

Обработчику программы (парсеру) необходимо как-то отличать одну команду от другой. Для этого используются специальные символы — разделители. В PHP инструкции разделяются так же, как и в Си или Perl, — каждое выражение заканчивается точкой с запятой. Закрывающий тег «?>» также подразумевает конец инструкции, поэтому перед ним точку с запятой не ставят. Например, два следующих фрагмента кода эквивалентны (листинг 1):

Листинг 1. Примеры простых программ на PHP

<?php

// точка с запятой в конце команды обязательна»Hello, world!»;

  • ?>
  • <!— точка с запятой опускается из-за «?>» —>
  • <?php echo «Hello, world!» ?>

— Часто при написании программ возникает необходимость делать какие-либо комментарии к коду, которые никак не влияют на сам код, а только поясняют его. Это важно при создании больших программ и в случае, если несколько человек работают над одной программой. При наличии комментариев в программе в ее коде разобраться гораздо проще. Кроме того, если решать задачу по частям, недоделанные части решения также удобно комментировать, чтобы не забыть о них в дальнейшем. Во всех языках программирования предусмотрена возможность включать комментарии в код программы. PHP поддерживает несколько видов комментариев: в стиле Cи, C++ и оболочки Unix. Символы // и # обозначают начало однострочных комментариев, /* и */ — соответственно начало и конец многострочных комментариев (листинг 2).

Листинг 2. Использование комментариев в программе

<?php

// Конструкторкласса

public function __construct()

{

// В строке запроса должен присутствовать параметр

DepartmentId(isset ($_GET[‘DepartmentId’]))

$this->_mDepartmentId = (int)$_GET[‘DepartmentId’];_error(‘DepartmentId not set’);

/* Если CategoryId есть в строке запроса, мы сохраняем

его значение(преобразуя его в integer для защиты от

некорректныхзначений) */(isset ($_GET[‘CategoryId’]))

$this->_mCategoryId = (int)$_GET[‘CategoryId’];

}

?>

— Переменная в PHP обозначается знаком доллара, за которым следует ее имя $mDescription. Имя переменной чувствительно к регистру, т.е. переменные$mDescription и $MDescription различны. Имена переменных соответствуют тем же правилам, что и остальные наименования в PHP: правильное имя переменной должно начинаться с буквы или символа подчеркивания с последующими в любом количестве буквами, цифрами или символами подчеркивания.

26 стр., 12757 слов

Проектирование и разработка базы данных ‘Магазин продажи одежды’

... при пользовании данным приложением. 1. Анализ предметной области Задачей курсовой работы является проектирование и разработка базы данных «Магазина продажи одежды». Особенности: Введение данных в БД осуществляется с ... email password name phone ip .3 Описание физической БД СУБД mySql server идеально подходит для разработки БД для «Магазин продажи одежды» так как эта среда моделирует среду ...

Для хранения постоянных величин, т.е. таких величин, значение которых не меняется в ходе выполнения скрипта, используются константы. Такими величинами могут быть математические константы, пароли, пути к файлам и т.п. Основное отличие константы от переменной состоит в том, что ей нельзя присвоить значение больше одного раза и ее значение нельзя аннулировать после ее объявления. Кроме того, у константы нет приставки в виде знака доллара и ее нельзя определить простым присваиванием значения. Как же тогда можно определить константу? Для этого существует специальная функция define().

Еесинтаксистаков:

  • define(‘PRESENTATION_DIR’, SITE_ROOT . ‘/presentation/’);поддерживает восемь простых типов данных.

Четыре скалярных типа:

  • boolean (логический);
  • integer (целый);
  • float (сплавающейточкой);
  • string (строковый).

Двасмешанныхтипа:

  • array (массив);
  • object (объект).

Идваспециальныхтипа:

  • resource (ресурс);
  • NULL.

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

Оператор if — это один из самых важных операторов многих языков, включая PHP. Он позволяет выполнять фрагменты кода в зависимости от условия. Структуру оператора if можно представить следующим образом:

  • if ($page > 1)

$link .= ‘&Page=’ . $page;

— Оператор else расширяет if на случай, если проверяемое в if выражение является неверным, и позволяет выполнить какие-либо действия при таких условиях.Структуру оператора if, расширенного с помощью оператора else, можно представить следующим образом:

if (isset ($_GET[‘DepartmentId’]))

$this->_mDepartmentId = (int)$_GET[‘DepartmentId’];_error(‘DepartmentId not set’);

— Еще один способ расширения условного оператора if — использование оператора elseif. elseif — это комбинация else и if. Как и else, он расширяет if для выполнения различных действий в том случае, если условие, проверяемое в if, неверно. Но в отличие от else, альтернативные действия будут выполнены, только если elseif-условие является верным. Структуру оператора if, расширенного с помощью операторов else и elseif, можно представить следующим образом (листинг 3):

Листинг 3. Использованиеоператораelseif

  • ..(isset ($_GET[‘Search’]) || isset($_GET[‘SearchResults’]) || isset ($_GET[‘AddProduct’]))

{;

}

// Obtain proper URL for category pages(isset ($_GET[‘DepartmentId’]) && isset ($_GET[‘CategoryId’]))

{(isset ($_GET[‘Page’]))

14 стр., 6791 слов

Разработка базы данных для автоматизированной системы управления ...

... (RAC) обеспечивает работу одного экземпляра базы данных на нескольких узлах grid, позволяя управлять нагрузкой и ... СУБД MySQL поставляется со специальным типом таблиц EXAMPLE, демонстрирующим принципы создания новых типов таблиц. Благодаря открытой архитектуре и GPL-лицензированию, в СУБД MySQL постоянно появляются новые типы таблиц. MySQL ... структуры курсового проекта: В данной работе рассматривается ...

$proper_url = self::ToCategory($_GET[‘DepartmentId’],

$_GET[‘CategoryId’], $_GET[‘Page’]);

$proper_url= self::ToCategory($_GET[‘DepartmentId’],

$_GET[‘CategoryId’]);

}

Если говорить о возможностях сегодняшнего PHP, то они выходят далеко за рамки тех, что были реализованы в его первых версиях. С помощью PHP можно создавать изображения, PDF-файлы, флэш-ролики, в него включена поддержка большого числа современных баз данных, встроены функции для работы с текстовыми данными любых форматов, включая XML, и функции для работы с файловой системой. PHP поддерживает взаимодействие с различными сервисами посредством соответствующих протоколов, таких как протокол управления доступом к директориям LDAP, протокол работы с сетевым оборудованием SNMP, протоколы передачи сообщений IMAP, NNTP и POP3, протокол передачи гипертекста HTTP и т.д.

Обращая внимание на взаимодействие между различными языками, следует упомянуть о поддержке объектов Java и возможности их использования в качестве объектов PHP. Для доступа к удаленным объектам можно использовать расширение CORBA.

Для работы с текстовой информацией PHP унаследовал (с небольшими изменениями) механизмы работы с регулярными выражениями из языка Perl и UNIX-систем. Для обработки XML-документов можно использовать как стандарты DOM и SAX, так и API для XSLT-трансформаций.

Для создания приложений электронной коммерции существует ряд полезных функций, таких как функции осуществления платежей Cybercash, CyberMUT, VeriSign Payflow Pro и CCVS.

Сегодня PHP используется сотнями тысяч разработчиков. Несколько миллионов сайтов написаны на PHP, что составляет более 20% доменов Интернета [2].

1.2 Язык запросов SQL и система управления базами данных MYSQL

переводят на русский как Структурированный Язык Запросов. С помощью SQL-запросов можно создавать и работать с реляционными базами данных.определяется Американским Национальным Институтом Стандартов и Международной Организацией по стандартизации (ISO) . Несмотря на это, некоторые производители баз данных вносят изменения и дополнения в этот язык. Эти изменения незначительны и основа остаётся совместимой со стандартом.

Реляционная база данных — это таблица, в которой в качестве столбцов выступают поля данных, а каждая строка хранит данные. В каждой таблице должно быть одно уникальное поле, которое однозначно будет идентифицировать строку. Это поле называется ключевым. Эти поля очень часто используются для связывания таблиц. Но даже если таблица не связана, ключевое поле всё равно обязательно. В качестве ключа желательно использовать численный тип и если позволяет база данных, то будет лучше, если он будет типа «autoincrement» (автоматически увеличивающееся/уменьшающееся число).- это одна из наиболее популярных и эффективных систем управления базами данных, которая очень часто используется при построении современных веб-сайтов. На основе данной системы можно строить, как небольшие веб-сайты, так и крупные Интернет-проекты.СУБД MySQL поддерживает язык запросов SQL. Это позволяет совершать такие операции, как запись данных в базу, редактирование данных, извлечение или удаление данных из базы данных.

Работать с MySQL можно не только в текстовом режиме, но и в графическом. Существует очень популярный визуальный интерфейс (кстати, написанный на PHP) для работы с этой СУБД. Называется он PhpMyAdmin. Этот интерфейс позволяет значительно упростить работу с базами данных в MySQL.позволяет пользоваться всеми достоинствами браузера, включая прокрутку изображения, если оно не умещается на экран. Многие из базовых SQL-функций работы с данными в PhpMyAdminсведены к интуитивно понятным интерфейсам и действиям, напоминающим переход по ссылкам в Интернет.

15 стр., 7454 слов

Разработка клиентского веб-интерфейса к базе данных туристической фирмы

... данной курсовой работе будет рассмотрена разработка клиентского веб-интерфейса к базе данных туристической ... 2.1. Графическая схема шаблона сайта Клиентская часть сайта, доступная широкому кругу ... Apache 2.0.53; СУБД MySQL 4.0.23; PHP 5.3. Для клиентской машины: ... всегда преобразуется к стандарту HTML-странички. Это тоже ... Таблица 2. Сравнение характеристик БД Характеристика MS Access MS SQL Server MySQL ...

Начиная с версии 5.0, СУБД MySQL практически полностью удовлетворяет стандарту структурированного языка запросов SQL и, следовательно, совместима с другими базами данных.

Рассмотрим основные достоинства СУБД MySQL:

  • Высокое качество — MySQL характеризуется устойчивой работой.
  • Наряду с Oracle, MySQL считается одной из самых быстрых СУБД в мире.
  • Открытый код доступен для просмотра и модернизации, что позволяет постоянно улучшать программный продукт.
  • СУБД MySQL, разработанная с использованием языков C/C++, протестирована на многих платформах, среди которых Windows, Linux, FreeBSD, MacOSX, OS/2, Solaris и др.

— MySQLподдерживаетAPI (ApplicationProgrammingInterface, программныйинтерфейсприложения) дляС, C++, Eiffel, Java, Perl, PHP, Python, RubyиTcl. MySQL можно успешно применять как для построения Web-страниц с использованием Perl, PHP и Java, так и для работы прикладной программы, созданной с использованием Delphi, Builder C++ или платформы .NET.

  • СУБД MySQL предоставляет широкий выбор типов таблиц, в том числе и сторонних разработчиков, что позволяет реализовать оптимальную для решаемой задачи производительность и функциональность.
  • Локализация в MySQL выполнена корректно. У пользователя, как правило, не возникает проблем при обработке русского содержимого БД

Создание, заполнение и изменение таблиц в MySQL осуществляются с помощью стандартных SQL операторов CREATETABLE, ALTERTABLE, INSERT, UPDATE, DELETE. Определен также оператор REPLASE, который действует аналогично INSERT, но таким образом, что если значение индекса unique или primary KEY в старой записи таблицы такое же, как и в новой, то старая запись перед занесением новой будет удалена. Оператор TRUNCATETABLE предназначен для полного очищения таблицы [4].

СУБД MySQLподдерживает несколько типов таблиц.

ТипMyISAM назначается по умолчанию при создании таблицы. Каждая MyISAM-таблица хранится на диске в трех файлах, имена которых совпадают с названием таблицы. Первый из них содержит структуру таблицы и информацию о столбцах и индексах. Второй содержит данные таблицы, а третий — ее индексы.

Таблицы типа InnoDB могут достигать объема в 1 Тбайт. Таблицы этого типа хранятся в едином табличном пространстве. Данный тип таблиц поддерживает транзакции, блокировки на уровне отдельных записей и — единственный из типов таблиц MySQL — поддерживает внешние ключи и каскадное удаление (обновление).

Впрочем, таблицы InnoDB уступают в скорости обработки таблицам MyISAM.

Для создания InnoDB-таблицы применяется ключевое слово ENGINE= InnoDB в операторе CREATE TABLE.

MySQLподдерживает несколько типов данных [5].

15 стр., 7229 слов

Создание сайта на языке HTML

... HTML-страниц, не требует разработки специальных программных средств, так как все необходимые инструменты для работы с данными ... известным только фирме Microsoft. непереносимостью переносимым Переносимость HTML-документа достигается за счет того, что пересылается ... разметки HTML. Объект - веб-сайт. Предмет - создание сайта на языке HTML. Цель работы - изучение языка гипертекстовой разметки HTML и ...

Числовые данные. К ним относят целые числа, не содержащие дробной части, а также вещественные числа, имеющие как целую, так и дробную части. Числовые данные делятся на точечные (bit, boolean, integer и decimal) и приближенные (float, real и double precision).

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

При объявлении целого типа можно задать количество отводимых под число разрядов (от 1 до 255).

Тип BIT предназначен для хранения битовых полей. Тип BOOLEAN является синонимом для TINYINT. Значение 1 рассматривается как истина (true), a 0 — как ложь (false).

Тип DECIMAL, а также его синонимы NUMERIC и DEC предназначены для величин повышенной точности, например, для денежных данных.

Для представления вещественных (приближенных) типов в СУБД MySQL имеются типы: FLOAT, DOUBLE и DOUBLE. Числовые типы данных с плавающей точкой также могут иметь параметр UNSIGNED.

Строковые данные- последовательность символов, заключенных в одинарные или двойные кавычки: ‘Hello world’, ‘123’, «MySQL». Поскольку в качестве стандарта в SQL определены одинарные кавычки, для совместимости с другими базами данных рекомендуется использовать именно их. РазличаютстроковыетипыCHAR, VARCHAR, BLOB, TEXT, MEDIUMTEXT, MEDIUMBLOB, LONGTEXT, LONGBLOB, ENUM, SET.

Тип CHAR позволяет хранить строку фиксированной длины; его дополняет тип VARCHAR, позволяющий хранить строки переменной длины. Длина строки может изменяться от 0 до 65 535. При создании таблицы нельзя смешивать столбцы типа CHAR и VARCHAR.

Тип TEXTобычно используется для хранения больших объемов текста, в то время как BLOB- для больших двоичных объектов, таких как электронные документы, изображения, музыкальные файлы и т. п. Типы MEDIUMBLOB, MEDIUMTEXTимеютмаксимальный размер (224 — 1) символов, а типы LONGTEXT, LONGBLOB — (232 -1) символов.

К особымтипам данных относятся ENUM и SET. Строки этих типов принимают значения из заранее заданного списка допустимых значений. Основное различие между ними заключается в том, что значение типа ENUMдолжно содержать точно одно значение из указанного множества, тогда как столбцы SETмогут содержать любой (или все) элементы заранее заданного множества.

Календарные данные. СУБД MySQL имеет пять календарных типов данных: DАТЕ, DATETIME, TIME, TIMESTAMP и YEAR. Тип DАТЕ предназначен для хранения даты, TIME — для времени суток, a TIMESTAMP — для представления и даты, и времени суток. Тип TIMESTAMP предназначен для представления даты и времени суток в виде числа секунд, прошедших с полуночи 1 января 1970 года. Тип данных YEAR позволяет хранить только год. Для значений, имеющих тип DATE и DATATIME принят формат YYYY-MM-DD или YY-MM-DD. В типах TIMEи DATATIMEвремя приводится в привычном формате hh:mm:ss.

Тип NULL. Если поле может принимать значение NULL, то в определении столбца после типа данных следует указать ключевое слово NULL. Если нипри каких обстоятельствах поле не должно принимать значение NULL, следует указать ключевое слово NOT NULL.

Чтобы обратиться к серверу РСУБД, нужно составить SQL-запрос, передать егосерверу и получить от сервера ответ. SQL-запрос может содержать любое требование, касающееся базы данных, например “создать таблицу” (листинг 4), “вывести список отделов”, “удалить из базы данных товар 223” или “выдать всю информацию о зимних куртках каталоге”.

16 стр., 7905 слов

Разработка интернет-магазина по продаже компьютерной техники

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

Листинг 4. Запрос создания таблицы

  • Создаем таблицу departmen

CREATE TABLE `departmen` (

`departmen_id` INT NOT NULL AUTO_INCREMENT,

`name` VARCHAR(100) NOT NULL,

`description` VARCHAR(1000),KEY (`departmen_id`)

ENGINE=MyISAM;

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

Для общения с MySQL не придется применять SQL — язык, используемыйв реляционных базах данных. SQL позволяет отдавать РСУБД приказы наподобие“выдай мне детали последних десяти заказов” или “удали товар номер 228”.

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

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

1.3 Web-сервер XAMPP

кроссплатформенная сборка веб-сервера, содержащая Apache, MySQL, интерпретатор скриптов PHP, язык программирования Perl и большое количество дополнительных библиотек, позволяющих запустить полноценный веб-сервер.- это аббревиатура:

  • X (любая из четырех операционных систем)
  • Apache
  • MySQL
  • PHP
  • Perl.

Полный пакет содержит:

  • Web-сервер Apache с поддержкой SSL
  • СУБД MySQL
  • PHP
  • Perl
  • FTP-клиент FileZilla
  • POP3/SMTP сервер

— утилиту phpMyAdmin.работает со всеми 32-х разрядными ОС Microsoft (98/2000/XP/2003/Vista/7), а также с Linux, Mac OS X и Solaris. Программа свободно распространяется согласно лицензии GNU General Public License и является бесплатным, удобным в работе web-сервером, способным обслуживать динамические страницы.

Для установки XAMPP необходимо скачать всего один файл формата zip, tar или exe, а компоненты программы не требуют настройки. Программа регулярно обновляется, для включения в состав новейших версий Apache/MySQL/PHP и Perl. Также XAMPP идет с множеством других модулей, включая OpenSSL и phpMyAdmin. Пользовательский интерфейс программы настолько прост, что ее называют «сборкой для ленивых» («lazy man’s WAMP/LAMP installation»).

Установка XAMPP занимает меньше времени, чем установка каждого компонента в отдельности.

Данный web-сервер распространяется в полной, стандартной и уменьшенной (известной как XAMPP Lite) версиях. Все дополнительные модули также доступны для скачивания. Из дополнительных возможностей можно отметить, что сама компания выпускает пакеты обновления выпускаемые в виде zip, 7-zip , tar или exe, которые позволяют обновить все компоненты с одной версии сборки XAMPP на более новую. Изначально XAMPP создавался как инструмент для разработчиков, позволяя веб-дизайнерам и программистам тестировать свою работу, не используя Интернет. Для упрощения работы некоторые возможности и настройки безопасности отключены по умолчанию, и в целом XAMPP рекомендуется к использованию только в очень дружественном окружении. Однако XAMPP иногда используется и во всемирной паутине. Также программа поддерживает создание и управление базами данных MySQL и SQLite.

13 стр., 6134 слов

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

... курсовой работы рассмотреть наиболее популярные программы, которые используются для создания документов. Задачи курсовой работы: Рассмотреть основные системы подготовки текстовых документов, ... процессор Лексикон, поддержка и дальнейшая разработка которого осуществляется компанией «Арсеналъ». Текстовые ... символов новой строки. Такие файлы называются ASCII-файлами. Различаясь способами управления и ...

1.4 HTML — языкгипертекстовой разметки

Язык HTML (HyperTextMarkupLanguage — язык разметки гипертекста) является стандартным языком, предназначенным для создания гипертекстовых документов в среде WWW (WorldWideWeb — Всемирная паутина).

HTML-документы (или веб-документы) могут просматриваться различными типами веб-браузеров. Если документ создан с использованием HTML, веб-браузер может интерпретировать HTML для выделения различных элементов документа и первичной их обработки.

Основное преимущество HTML заключается в том, что документ может быть просмотрен на веб-браузерах различных типов и на различных платформах.HTML — один из наиболее простых языков создания веб-страниц[6].

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

Веб-сайт (web site) — совокупность веб-документов, организованных в виде титульной страницы и нескольких связанных с ней страниц. Каждая такая совокупность, доступная в Интернете, может иметь любые размер и содержание, информационную и эмоциональную направленность.

HTML-документы могут быть созданы при помощи любых текстовых редакторов или специализированных HTML-редакторов и конвертеров.

HTML-документ — это обычный файл в формате ASCII. В его основе лежат специальные дескрипторы (теги), которые и определяют правила форматирования данных[6].

Итак, тег — последовательность символов, заключенных между символами < и >. Почти все теги образуют пары, то есть для открывающего тега существует закрывающий тег. Есть и непарные теги, например <BR>, <AREA>, но их мало.

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

  • о завершении текста заголовка.

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

  • Тег <HTML>. Самый первый тег, который встречается в документе, должен быть тегом <HTML>. Данный тег сообщает веб-браузеру, что документ написан на языке HTML. Минимальный HTML-документ мог бы выглядеть так:
  • <html> …тело документа…

</html>

  • Таким образом, теги <HTML>
  • и </HTML>
  • образуют для HTML-документа такназываемый контейнер.
  • Тег<HEAD>. Структурно документ распадается на две части: заголовочную и основную, или тело документа. Заголовочная часть размещается между тегами <HEAD>
  • и </HEAD>, основная — между тегами <BODY>
  • и </BODY>.
  • Тег <TITLE>. Внутри контейнера <HEAD>
  • и </HEAD>
  • размещается единственный обязательный контейнер из тегов <TITLE>
  • и </TITLE>, содержащий текст заголовка.

Тег заголовочной части документа должен быть указан сразу после тега <HTML> и более нигде в теле документа. Данный тег представляет собой обобщенное описание документа. Следует избегать размещения какого-либо текста внутри тега <HEAD>. Открывающий тег <HEAD> указывается непосредственно перед тегом <TITLE> и другими тегами, описывающими документ, а закрывающий тег </HEAD>

  • сразу после окончания описания документа.

Большинство веб-браузеров отображают содержимое тега <TITLE> в заголовке окна, содержащего документ, и в файле закладок, если он поддерживается веб-браузером. Заголовок, ограниченный тегами <TITLE> и </TITLE>, размещается внутри тегов <HEAD>. Заголовок документа при отображении самого документа в окне браузера не виден.

Теги тела документа идентифицируют отображаемые в окне компоненты HTML-документа. Тело документа может содержать ссылки на другие документы, текст и другую форматированную информацию.

  • Тег <BODY>. Тело документа должно находиться между тегами <BODY>и </BODY>. Это та часть документа, которая отображает его текстовую и графическую информацию.

Следует заметить, что открывающие и закрывающие теги <HTML>, <HEAD> и <BODY> необязательны, но их настоятельно рекомендуется использовать, поскольку это позволяет веб-браузеру уверенно отделить друг от друга заголовочную и непосредственно смысловую части документа.

Тег <BODY> парный. Между открывающим тегом <BODY> и закрывающим тегом </BODY> размещаются все другие теги программы, составляющие основное содержание документа. Тег <BODY> предназначается для выделения той части документа, которая должна быть показана пользователю на экране.

При создании веб-страницы необходимо придерживаться определенных правил, которые перечислены ниже.

  • Следить за тем, чтобы веб-страницы не получились слишком широкими, и пользователям не приходилось пользоваться прокруткой. Типичной шириной экрана считается ширина в 640 пикселов.
  • Каждая веб-страница должна иметь заголовок.
  • Не перегружать страницу графикой.
  • Попытка визуально выделить все означает не выделить ничего.
  • Использовать свободное пространство для привлечения внимания.

Для создания HTML-страниц можно пользоваться любым текстовым редактором, но существуют и специализированные программы. Эти HTML-редакторыделятся на два типа: визуальные и невизуальные[7].

Визуальные HTML-редакторыобладают интуитивно понятным интерфейсом и не требуют много времени на освоение, но генерируют очень длинный, неоптимальный и малопонятный HTML-код, который потом трудно редактировать. К редакторам этого типа относится,например Microsoft FrontPage Express.

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

1.5 CSS — язык стилей

(Cascading Style Sheets — каскадные таблицы стилей) — одна из базовых технологий в современном Интернете. Нечасто можно встретить сайт, свёрстанный без примененения CSS.код — это список инструкций для браузера — как и где отображать элементы веб-страницы, написанный особым образом. Под «элементами» обычно подразумеваются теги XHTML/HTML и их содержимое.

Существуют три основных способа использования CSS совместно с HTML:

  • Вложение — CSS код прописывается непосредственно в нужном теге элемента с помощью атрибута Style
  • Встраивание — весь стилевой код для web-документа прописывается в его шапке (внутри тегов Head) с помощью элемента Style
  • Связывание — весь CSS код размещается (выносится) в отдельном внешнем файле, который подключается к документу с помощью элемента Link в его шапке

Одно правило в CSS коде состоит из двух элементов — свойство и его значение. Обязательным условием является отделение свойства от его значения двоеточием (рис. 1).

 язык запросов и система управления базами данных  1

Рисунок 1 — Схема формирования правила CSS

Главные свойства CSS, применимые сейчас[8]:radius — скругляет углы элемента на заданное значение — радиус. Пример:

  • foo {

border-radius: 10px;

  • }shadow — свойство из CSS2 (выкинутое в версии 2.1, возвращенное в CSS3), котороедобавляет тень к тексту;
  • можно указывать направление, количество размытия и цвет тени.

p {shadow: 1px 1px 2px #999;

  • }shadow — добавляет тень к элементу. Синтаксис тот же, что у свойства text-shadow.

Пример:

  • foo {

box-shadow: 1px 1px 2px #999;

}

opacity — определяет непрозрачность элемента. Значение 1 соответствует полнойнепрозрачности; значение 0 соответствует полной прозрачности.

Пример:

  • foo {: 0.5; /*.foo will be 50% transparent */

}- не свойство CSS, но, скорее, новая цветовая модель, введенная в CSS3, добавляющаявозможность задавать уровень прозрачности элемента вместе с его цветом в формате RGB.

Пример:

  • foo {: rgba(0, 0, 0, 0.75);
  • /* black at 75% opacity */

}

На сайтах почти всегда используется метод связывания CSS и html (внешний файл таблиц стилей).

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

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

Подлинный потенциал CSS — в том, что оно позволяет нам разрешатьраспространенные задачи дизайна более эффективно, используя меньше кода и получаярешение с большей степенью гибкости.

1.6 Оптимизация для поисковых систем

является аббревиатурой от Search Engine Optimization, что в переводе означает оптимизация под поисковые системы или просто поисковая оптимизация[9].

В Интернете есть несколько определений поисковой оптимизации:

— SEO это форма онлайн маркетинга, поисковая оптимизация или поисковый маркетинг это процесс создания сайта и его контента максимально релевантным как для поисковых систем, так и для пользователей. Успешный поисковый маркетинг (SEO, SEM) помогает сайту занимать высокие позиции по релевантным ключевым словам и фразам в результатах поиска.

— Поисковая оптимизация (SEO) — это процесс увеличения количества пользователей на web-сайт путем увеличения его ранга в результатах поиска в поисковых системах. Чем больше рейтинг сайта в поисковых результатах, тем больше вероятность того, что пользователь посетит ваш сайт. Практически, все пользователи Интернет не переходят далеко по страницам поисковых результатов, поэтому позиция сайта очень существенна для привлечения большего количества трафика.

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

Подытоживая вышеприведенные определения SEO, можно сказать, что поисковая оптимизация — это процесс работы над сайтом, его внутренними факторами, влияющими на ранжирование в поисковых системах — структурой, контентом, кодом HTML, его внешними факторами ранжирования — ссылками на сайт с целью увеличения релевантности ресурса определенным, заранее известным ключевым словам, увеличения популярности сайта для поисковых машин и, соответственно, увеличения позиций в поисковых результатах для привлечения большего количества посетителей на сайт.

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

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

К черным методам оптимизации относят такие методы, как:

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

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

  • Внутреннюю оптимизацию (on-page SEO) сайта или конкретной
  • Внешнее продвижение (off-page SEO).

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

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

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

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

1.7 Анализ существующих интернет-магазинов

На сегодняшний день существуют много современных интернет-магазинов одежды. При поиске в поисковике “Яндекс” по запросу “Интернет-магазин одежды”можно увидеть самые популярные сайты (рис 2).

 анализ существующих интернет магазинов 1

Рисунок 2 — Поиск по запросу “Интернет-магазин одежды”

Итак, три самых популярных сайта интернет-магазинов:

 анализ существующих интернет магазинов 2

Рисунок 3 — Главная страница интернет-магазина одежды Lamoda

www.lamoda.ru

 анализ существующих интернет магазинов 3

Рисунок 4 — Главная страница интернет-магазина одежды Visavis

www.visavis-fashion.ru

 анализ существующих интернет магазинов 4

Рисунок 5 — Главнаястраница интернет-магазина одежды Wildberries

www.wildberries.ru

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

Проект “Goodstore” будет разработан на основе структуры существующих интернет-магазинов. Будет создан каталог товаров, база данных, корзина покупателя, система оплаты, а так же раздел администрирования сайтов.

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

  • создать базу данных для хранения каталога товаров, содержащего названияотделов, категорий и товаров;
  • написать код на SQL (StructuredQueryLanguage) и PHP (HypertextPreprocessor) для доступа к этой базе данных и обеспечения работы каталога;
  • добавить в каталог товаров данные, определяющие атрибуты этих товаров,например цвет и размер;
  • принятьплатежиспомощью PayPal Website Payments Standard;
  • создать закрытый раздел сайта для администраторов, позволяющий имуправлять каталогом.

2.1 Установка XAMPP

XAMPP — это пакет, созданный ApacheFriends. Если на компьютере не установлены Apache, PHP, MySQL, то самый простой способ установить их — именно с помощьюXAMPP.

Для установки сервера XAMPP нужно скачать выполняемый файл с именем xampp-win32-5.5.19-0-VC11-installer.exe, запустить загруженный файл. Установить XAMPP во вложенную папку корневой папки диска, например C:\xampp. Также выбратьустановку Apache и MySQL как служб (рис. 6).

 установка  1

Рисунок 6 — Выбор настроек при установке XAMPP

В конце нужно подтвердить запуск XAMPP Control Panel, с помощью которой можно управлять установленными службами. Окно этой программы показано на рис. 7.

 установка  2

Рисунок 7 — Окно панели управления XAMPP: XAMPP Control Panel

Чтобы убедиться в том, что Apache установлен и работает, нужно в окнебраузера открыть страницу #»896847.files/image008.gif»>

Рисунок 8 — Проверка успешности установки Apache

Далее нужно создать папку “goodstore”, в которой будут размещаться все рабочие файлы проекта: C:\xampp\htdocs\goodstore\,по умолчанию Apache из XAMPP использует для обслуживания запросов клиентов папку: C:\xampp\htdocs\.

Создадим в папке goodstore файл с именем test.php со следующей строкой внутри:

  • <?php phpinfo();
  • ?>
  • ОткроемURL#»896847.files/image009.gif»>

Рисунок 9- Проверка успешного завершения установки Apache

Первый шаг к созданию электронного магазина Goodstore — маленький, но очень важный, поскольку он позволяет проверить работоспособность Apache, PHP и псевдонима goodstore. Если при открытии тестовой страницы возникли проблемы, прежде всего надо убедиться, что правильно установлен XAMPP.

2.2 Трехуровневая архитектура

В целом под архитектурой понимают разбиение на части кода приложения[1].

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

В частности, трехуровневая архитектура подразумевает разделение кода на триуровня:

  • уровень представления (presentationlayer);
  • уровень логики приложения (бизнес-уровень, или businesslayer);
  • уровень данных (datalayer).

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

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

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

 трехуровневая архитектура 1

Рисунок 10 — Простое представление трехуровневой архитектуры

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

2.3 Разделение кода и оформления с помощью Smarty

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

Еще хуже то, что PHP можно легко смешивать с HTML-кодом веб-страниц, поскольку PHP по умолчанию не содержит механизмов для четкого разделения кода на PHP и кода на HTML.

Смешивание кода на PHP и HTML приводит к двум проблемам:

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

Эти проблемы привели к появлению систем шаблонов, позволяющих разделять логику уровня представления и HTML-код. Smarty — это одна из самых популярных и эффективных систем шаблонов для PHP. Ее основное

назначение — именно разделение логики приложения (кода на PHP) и кода представления (HTML).

Дизайн-шаблон Smarty (файл .tpl с тегами HTML и тегами, специфичными дляSmarty) и соответствующий ему подключаемый файл Smarty (файл .php с кодом, взаимодействующим с шаблоном) образуют компонентный шаблон Smarty.

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

Для работы Smarty требует трех папок, которые нужно будет создать, -templates, templates_cиconfigs. Внутрипапкиgoodstoreсоздатьпапкуpresentation, авней — папкиtemplatesиtemplates_c. Впапкеpresentation будут находиться файлы уровня представления нашего приложения.

В папке goodstore создать папку include. В ней будут храниться конфигурационные файлы приложения. Внутри папки include создать папку configs — она будет использоваться для хранения конфигурационных данных Smarty.

Для Goodstoreприменим относительно простую, но эффективную структурусайта, которая позволит в дальнейшем легко вносить изменения и сосредоточиться на технических деталях.

Все страницы Goodstore, включая первую страницу, будут иметь структуру, показанную на рис. 11.

 разделение кода и оформления с помощью  1

Рисунок 11 — Структура веб-страниц сайта Goodstore

Чтобы как можно проще реализовать эту структуру, воспользуемся компонентными шаблонами Smarty.

2.4 Начало реализации проектаGoodstore

ВходнаястраницасайтаGoodstoreбудетгенерироватьсяфайламиindex.phpиstore_front.tpl. Создадимвпапкеgoodstoreвложеннуюпапкуimages, вэтойпапкебудетхранитсяизображениелоготипа (logo.tif) Goodstore, котороедолжноотображатьсянаглавнойстранице.

В папке goodstore/include/configs создадим файл site.conf и введем в него следующую строку:

site_title = «Goodstore: Demo Product Catalog from Beginning PHP andMySQL E-Commerce»

Впапкеgoodstore/presentation/templatesсоздадимфайлstore_front.tpl (приложение) — шаблон Smarty, содержащий заместители для трех основных элементов страниц — заголовка, списка отделов и ячейки с содержимым страниц.

Таблицы стилей CSS — мощный инструмент дляуправления оформлением HTML-страниц. Определения стилей CSS могут храниться в одном или несколькихфайлах с расширением .css либо даже помещаться внутрь самого HTML-файла, в котором они используются.Такой подход позволяет веб-дизайнерам при необходимости отделить определения стилей от документов, в которых эти определения используются.

Создадим в папке goodstore/styles файл goodstore.css и наберем в нем следующий код (листинг 5):

Листинг 5. Стили CSSдля оформления страницы

@import «reset-min.css»;

  • @import «base-min.css»;
  • @import «fonts-min.css»;
  • @import «grids-min.css»;{size: 85%;family: «century gothic»;}
  • yui-t2, #bd, #yui-main {index: -5;

}

  • yui-b, .yui-g {index: auto;

}

#header {top: 15px;align: right;

}

  • error_box {color: #ffffcc;: 1px solid #dc143c;: #DC143C;: 0 auto;: auto;: 5px;: relative;align: left;: 90%;index: 5;

}

Добавимвпапкуgoodstore/includeфайлconfig.phpв котором задаются значения некоторых глобальных константивведемвнегоследующийкод (листинг 6):

Листинг 6. Конфигурационный файл

<?php

define(‘SITE_ROOT’, dirname(dirname(__FILE__)));

  • // Папкиприложения(‘PRESENTATION_DIR’, SITE_ROOT . ‘/presentation/’);(‘BUSINESS_DIR’, SITE_ROOT . ‘/business/’);

// Настройки, необходимые для конфигурирования Smarty

define(‘SMARTY_DIR’, SITE_ROOT . ‘/libs/smarty/’);(‘TEMPLATE_DIR’, PRESENTATION_DIR . ‘templates’);(‘COMPILE_DIR’, PRESENTATION_DIR . ‘templates_c’);(‘CONFIG_DIR’, SITE_ROOT . ‘/include/configs’);

  • ?>
  • Функция dirname(__FILE__) возвращает имя папки, в которой находитсяуказанный файл, dirname(dirname((__FILE__)) возвращаетпапку, в которой находится папка с указанным файлом.

Это позволяет поместить в SITE_ROOT полный путь к goodstore.

В папке goodstore/presentation создадим файл с именем application.php и введем в него следующий код (листинг 7).

Листинг 7.Класс, расширяющий Smarty

<?php

// Ссылка на библиотеку Smarty

require_once SMARTY_DIR . ‘Smarty.class.php’;

/* Класс, расширяющий Smarty, используется для обработки и

отображения файлов Smarty */Application extends Smarty{

// Конструктор классаfunction __construct()

{

// ВызовконструктораSmarty::Smarty();

// Меняемпапкишаблоновпоумолчанию

$this->template_dir = TEMPLATE_DIR;

  • $this->compile_dir = COMPILE_DIR;
  • $this->config_dir = CONFIG_DIR;

}

}

?>

  • В этом файле расширяется класс Smarty классом-оберткой с именем Application, меняющим поведение Smarty по умолчанию. Конструктор класса Application конфигурирует Smarty на использование папок, созданных ранее.

Добавим в папку goodstore файл index.php (листинг 8).

Задача этого файла — загружать файл store_front.tpl с помощью класса Application, созданноговыше.

Листинг 8. Файл index.php

<?php

// Подключаем служебные файлы

require_once ‘include/config.php’;

  • // Загружаемшаблонстраницыприложения_once PRESENTATION_DIR . ‘application.php’;

// Загружаемфайлшаблонов Smarty

$application = new Application();

// Отображаемстраницу

$application->display(‘store_front.tpl’);

  • ?>
  • А теперь можно посмотреть, как все это работает,открыть в окне браузерассылку #»896847.files/image012.gif»>

Рисунок 12 — Работающее приложение Goodstore

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

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

В контексте рабочего веб-приложения ошибки могут возникать неожиданно поразным причинам, например из-за сбоев программного обеспечения (сбои операционных систем и СУБД, действия вирусов и т.д.) или сбоев аппаратуры.

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

Добавим в файл include/config.php (листинг 9) следующие переменные конфигурации.

Листинг 9. Добавленные переменные конфигурации

// Эти значения должны быть равны true на этапе разработки

define(‘IS_WARNING_FATAL’, true);

  • define(‘DEBUGGING’, true);

// Типы ошибок, о которых должны составляться сообщения

define(‘ERROR_TYPES’, E_ALL);

// Настройки отправки сообщений администраторам по электронной почте

define(‘SEND_ERROR_MAIL’, false);(‘ADMIN_ERROR_MAIL’, ‘goodstore.shop@yandex.ru’);(‘SENDMAIL_FROM’, ‘Errors@example.com’);_set(‘sendmail_from’, SENDMAIL_FROM);

// По умолчанию мы не записываем сообщения в журнал

define(‘LOG_ERRORS’, false);(‘LOG_ERRORS_FILE’, ‘c:\\goodstore\\errors_log.txt’); // Windows

/* Общее сообщение об ошибке, которое должно отображаться вместо

подробной информации (если DEBUGGING равно false) */

define(‘SITE_GENERIC_ERROR_MESSAGE’, ‘<h1>Godstore Error!</h1>’);

  • ?>
  • В папке goodstore создадим вложенную папку business, в этой папке создадим файл error_handler.php (приложение А) и наберем в нем код класса ErrorHandler, который обрабатывает ошибки.

Внесем изменения в файл index.php, чтобы задействовать только что созданный файл error_handler.php и выбрать метод-обработчик ошибок:

  • .._once BUSINESS_DIR . ‘error_handler.php’;

// Задаемобработчикошибок

ErrorHandler::SetHandler();

  • Чтобы протестировать обработчик ошибок, добавим в файл index.php

// Пытаемся загрузить несуществующий файл

require_once ‘inexistent_file.php’;

  • Далее загрузим страничку в браузере (рис. 13)

 начало реализации проекта  1

Рисунок 13 — Сообщение об ошибке с последовательностью вызовов функций

Метод обработки ошибок, Handler(), работает следующим образом:

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

Менее серьезные ошибки позволят приложению продолжить выполнение.

2.5 Создание каталога товаров

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

Создадим в phpMyAdmin новую базу данных goodstore. Теперь добавим в базу данных нового пользователя. Уровень данных в приложении будет работать с базой данных, используя идентификатор этого пользователя. Создадим пользователя с именем goodstoreadmin (и такимже паролем).

У этого пользователя будет право полного доступа к базе данных

goodstore, но не к другим базам данных.

Во вкладке SQLвведем следующий SQL-запрос (листинг 10):

Листинг 10. Запрос на создание нового пользователя в базе данных

  • Create goodstoreadmin userALL PRIVILEGES ON `goodstore`.*’goodstoreadmin’@’localhost’ IDENTIFIED’goodstoreadmin’

WITH GRANT OPTION;

  • После создания базы данных и нового пользователя, можно создавать таблицы.С помощью phpMyAdmin создадим таблицуdepartment (листинг 11), в ней будут храниться данные об отделах и заполним ее данными (листинг 12):

Листинг 11. Создание таблицы department

  • СоздаемтаблицуdepartmenTABLE `departmen` (

`departmen_id` INT NOT NULL AUTO_INCREMENT,

`name` VARCHAR(100) NOT NULL,

`description` VARCHAR(1000),KEY (`departmen_id`)

ENGINE=MyISAM;

  • Листинг 12. Заполнение данными таблицы department
  • Заполняемданнымитаблицуdepartment

INSERT INTO `departmen` (`departmen_id`, `name`, `description`) VALUES

(1, ‘Одежда’,

‘Верхняя одежда, блузки, брюки, платья, юбки’),

(2, ‘Обувь’,

‘Зимняя, осенняя, летняя’),

(3, ‘Аксессуары’, ‘Сумки, шарфы, шапки’);

  • Эта таблица предназначена для формирования списка отделов и заполненияшаблона Smarty этим списком.

На практике обычно удобнее взаимодействовать с базой данных с помощью набора хранимых процедур (stored procedures)[1, 3 — 5].

Хранимая процедура — это просто набор операторов SQL, сохраненный под определенным именем, по которому этот набор можно вызывать. Хранимые процедуры в MySQL, аналогично функциям в PHP, могут принимать аргументы и возвращать значения. Пользоватьсяхранимыми процедурами проще — достаточно указать имя нужной процедуры изадать значения для ее параметров.

При разработке приложения Goodstore будем обращаться к данным исключительно с помощью хранимых процедур, хранящихся в базе данных goodstore.

Синтаксис для создания хранимых процедур имеет вид

DELIMITER $$PROCEDURE <name>(<param1 type>, <param2 type> … )

<code>$$;

  • Перваяхранимаяпроцедура, будетназыватьсяcatalog_get_departments_list (листинг 13).

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

Листинг 13. Хранимаяпроцедура catalog_get_departments_list

  • Созданиехранимойпроцедурыcatalog_get_departments_listPROCEDURE catalog_get_departments_list()department_id, name FROM department ORDER BY department_id;$$

Для отображения списка отделов нам понадобится реализовать на уровне логики приложения два класса

— Класс DatabaseHandler будет хранить общую функциональность, отвечающую за доступ к базе данных. Этот класс мы будем в дальнейшем постоянноиспользовать, обращаясь к базе данных, чтобы избежать ошибок и нестыковок, связанных с реализацией одновременно нескольких механизмов доступа к данным.

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

2.5.1 Установка соединения с MySQL

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

Есть два основных подхода к работе с соединениями.

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

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

  • Закрываем соединение с базой данных сразу же после выполнения запроса.

Недостаток — накладные расходы на частое открытие и закрытие соединений.

Альтернативный подход, будем использовать в Goodstore:

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

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

Теперь можно поговорить о практической реализации выбранного подхода — открытии и закрытии соединений и выполнении запросов с помощью PHP PDO[1].

Классы PDO позволяют обращаться к различным источникам данных с помощью одного и того же API (Applications Programming Interface — интерфейса программирования приложений).

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

Функциональность класса PDO позволяет устанавливать соединения с серверами MySQL и выполнять SQL-запросы. За открытие соединения отвечает конструктор класса PDO, который в качестве параметров получает строку соединения ссервером базы данных и (необязательно) аргумент, указывающий, будет ли создаваемое соединение постоянным. В строке соединения содержится вся информация, необходимая для установки соединения с сервером MySQL. Объект PDO создается конструктором следующим образом

$dbh = newPDO(‘mysql:dbname=’ . $db_name . ‘;host=’ . $db_host,

$db_user,

$db_pass,(PDO::ATTR_PERSISTENT => $persistent));

Как видно из приведенного фрагмента кода, для установки соединенияконструктору нужно передать пять переменных:

  • $db_user с именем пользователя
  • $db_pass с паролем
  • $db_host с именем хоста сервера MySQL
  • $db_name с именем базы данных, к которой вы хотите обращаться
  • $persistent (true, если мы хотим создать постоянное соединение, илиfalse — в противном случае)

Чтобы закрыть соединение с базой данных, нужно присвоить переменной $dbhзначение null.

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

try

{

// Открываем соединение

$dbh = newPDO(‘mysql:dbname=’ . $db_name . ‘;host=’ . $db_host,

$db_user, $db_pass);

// Закрываемсоединение

$dbh = null;

}(PDOException $e)

{echo ‘Connection failed: ‘ . $e->getMessage();}

Затем перехватываются и обрабатываются исключения, которые могут генерироваться в коде доступа к данным, и передается информация об ошибках.

Первое, что нужно создать, — это класс DatabaseHandler, в котором будетсосредоточена функциональность, используемая другими механизмами из уровнялогики приложения. Затем еще один класс уровня логики приложения,Catalog, использующий функциональность класса DatabaseHandler для реализациифункциональности, используемой на уровне представления. В классе Catalog будет содержаться метод GetDepartments() (он будет использоваться для генерации списка отделов), а также GetCategories() и некоторые другие.

Добавим имя пользователя и пароль для доступа к базе данных в конец файлаgoodstore/include/config.php(листинг 14).

Листинг 14. Добавление имя пользователя и пароля

// Параметры соединения с базой данных(‘DB_PERSISTENCY’, ‘true’);

  • define(‘DB_SERVER’, ‘localhost’);(‘DB_USERNAME’, ‘goodstoreadmin’);(‘DB_PASSWORD’, ‘goodstoreadmin’);(‘DB_DATABASE’, ‘goodstore’);(‘PDO_DSN’, ‘mysql:host=’ . DB_SERVER . ‘;dbname=’ . DB_DATABASE);

— Впапке goodstore/business создадимновыйфайлсименем database_handler.php исоздадимвнемкласс DatabaseHandler. На данный момент в классе будут только конструктор (объявленный как private, что делает невозможным создание экземпляров класса) и статический

метод GetHandler().

Этот метод создает новое соединение с базой данных, сохраняет его в переменную-член класса $m_Handler и возвращает объект класса.

Добавим в класс DatabaseHandler несколько методов(приложение А):

  • Close() — вызывается,когда понадобится закрыть соединение с базой данных;
  • Execute() — используется для выполнения запросов, не возвращающих данные
  • GetAll() — позволяет получить все строки, возвращаемые запросом SELECT
  • GetRow() — используется для выполнения запросов SELECT, возвращающиходну строку
  • GetOne() — похож на GetRow(), но возвращающий только одно значение из запроса SELEC

В папке business создадим файл catalog.php, в котором создадим класс уровня логики приложения,Catalog, использующий функциональность класса DatabaseHandler для реализациифункциональности, используемой на уровне представления (листинг 15)

Листинг 15. Класс Catalog

<?php

// Класс уровня логики приложения для считывания информации

// о каталоге товаровCatalog

{

// Получаемсписокотделовstatic function GetDepartments()

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_departments_list()’;

  • // Выполняем запрос и получаем результатыDatabaseHandler::GetAll($sql);

}

}

?>

  • Чтобы сделать класс DatabaseHandler доступным приложению, файл database_handler.php нужно включить в index.php. Нужно добавить в файлindex.phpследующие строчки

// Загружаемдескрипторбазыданных_once BUSINESS_DIR . ‘database_handler.php’;

  • // Закрываем соединение с базой данных::Close();
  • ?>

2.5.2 Отображение списка отделов

Итак, все, что осталось сделать, чтобы список отделов отображался на веб-странице, — это создать уровень представления.

Функциональность уровня представления можно реализовать в виде отдельного компонентного шаблона — departments_list. Затем просто включить файл этогошаблона — departments_list.tpl — в основной шаблон Smarty (templates/store_front.tpl).

Первым шагом нужно добавить в файл goodstore.css в папке goodstore/stylesстили приведенные ниже (листинг 16).

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

Листинг 16. Стили CSS

div.yui-bdiv.box {

color: #333333;: 1px solid #c6e1ec;top: 15px;

  • }.yui-b div p.box-title {: #0590C7;bottom: 2px solid #c6e1ec;: #FFFFFF;: block;size: 93%;weight: bold;: 1px;: 2px 10px;
  • }{: #0590C7;
  • }:hover { color: #ff0000;
  • }.selected {weight: bold;
  • }.yui-b div ul {: 0;
  • }.yui-b div ul li {bottom: 1px solid #fff;style-type: none;
  • }.yui-b div ul li a {: #333333;: block;decoration: none;: 3px 10px;
  • }.yui-b div ul li a:hover {: #c6e1ec;: #333333;

}

Добавимвфайлpresentation/application.phpвконструкторклассаApplicationдвестроки. ЭтистрокиконфигурируютпапкисподключаемымифайламиSmarty.

$this->plugins_dir[0] = SMARTY_DIR . ‘plugins’;

  • $this->plugins_dir[1] = PRESENTATION_DIR . ‘smarty_plugins’;
  • Теперьсоздадимфайлшаблона Smarty длякомпонентногошаблона departments_list. Он должен находиться в папке presentation/templates и называться departments_list.tpl (приложение А).

Этот файл отвечает за генерацию визуального оформления списка отделов.

Создимвпапке presentation папку smarty_plugins. В ней будут хранитьсяподключаемые файлы Smarty.Внутри папки smarty_pluginsсоздадим файл function.load_presentation_object.php и добавим в него следующий код (листинг 17).

Листинг17. Файлfunction.load_presentation_object.php

<?php

// Подключаемые функции из подключаемых файлов должны

// именоваться smarty_имя_типаsmarty_function_load_presentation_object($params, $smarty)

{_once PRESENTATION_DIR . $params[‘filename’] . ‘.php’;

$className = str_replace(‘ ‘, »,(str_replace(‘_’, ‘ ‘,

$params[‘filename’])));

// Создаемобъектпредставления

$obj = new $className();(method_exists($obj, ‘init’))

{

$obj->init();

}

// Присваиваемпеременнуюшаблона

$smarty->assign($params[‘assign’], $obj);

}

?>

  • Впапке presentationсоздадимфайл departments_list.php (приложениеА).

    Далее необходимо внести изменение в файл index.php, добавить ссылку на класс Catalog из уровня логики приложения:

// Загружаем уровень логики приложения

require_onceBUSINESS_DIR . ‘catalog.php’;

  • Теперь можно проверить работу, загрузим в браузере страницу #»896847.files/image014.gif»>

Рисунок 14 — Сайт Goodstore с динамически генерируемым списком отделов

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

2.6 Создание модели данных с помощью ALLFUSION ERWIN DATA MODELER

ERwin Data Modeler — CASE-средство для проектирования и документирования баз данных, которое позволяет создавать, документировать и сопровождать базы данных, хранилища и витрины данных.ERwin Data Modeler (ERwin) позволяет наглядно отображать сложные структуры данных.

Разработаем модель в ERwin Data Modeler 7. Работа с программой начинается с создания новой модели, для которой нужно указать тип и целевую СУБД.позволяет создавать логическую, физическую модели и модель, совмещающую логический и физический уровни.

Логический уровень — это абстрактный взгляд на данные, на нем данные представляются так, как выглядят в реальном мире, и могут называться так, как они называются в реальном мире (например «Постоянный клиент» или «Заказ»).

Объекты модели, представляемые на логическом уровне, называются сущностями и атрибутами. Логическая модель данных является универсальной и никак не связана с конкретной реализацией СУБД.

Физический уровень зависит от конкретной СУБД. В физической модели содержится информация о всех объектах БД. Физическая модель зависит от конкретной реализации СУБД. Одной и той же логической модели могут соответствовать несколько разных физических моделей.

Для создания на логическом уровне сущностей и связей между ними предназначена панель Toolbox.

После создания сущности ей нужно задать атрибуты. Для этого нужно дважды щелкнуть по ней или в контекстном меню выбрать пункт Attributes (рис. 15).

 создание модели данных с помощью  1

Рисунок 15 — Окноатрибутов выбранной сущности

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

Получившаяся логическая схема базы данных для проекта Goodstore (рис. 16):

 создание модели данных с помощью  2

Рисунок 16 — Созданная схема базы данных

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

2.7 Создание и заполнение новых таблиц

Для начала нужно создать три новых таблицы для каталога товаров и заполнить их данными

  • category
  • product
  • product_category

Между этими тремя таблицами будут отношения двух часто встречающихся видов — “один-ко-многим” (one-to-many) и “многие-ко-многим” (many-to-many).

Один-ко-многим — одна запись из какой-то таблицы соответствует нескольким записям из другой таблицы (но не наоборот).

Многие-ко-многим — записи в каждой из таблиц могут соответствовать нескольким записям из другой таблицы.

Хотя отношение “многие-ко-многим” часто встречается в базах данных, егонельзя физически реализовать с помощью только двух таблиц. Поэтому в большинстве РСУБД (включая MySQL) для реализации такого отношения используется дополнительная таблица, которая называется таблицей соединения (junction table)или связующей таблицей (linking table).

Она позволяет представить отношение“многие-ко-многим” как два отношения “один-ко-многим”. Например, она позволитсвязать каждый товар с произвольным количеством категорий, а каждую категорию — с произвольным количеством товаров.

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

С помощью SQL-запросов создадим таблицы product (приложение Б), category (приложение Б) и product_category (приложение Б).

Далее их нужно заполнить данными, воспользуемся интерфейсом phpMyAdmin (рис. 17).

 создание и заполнение новых таблиц 1

Рисунок 17 — Заполненная таблица product

Для реализации отношений “многие-ко-многим” используется вспомогательная таблица, которая называется таблицей соединений. В данном случае она называется product_category. В ней содержатся пары значенийproduct_id и category_id, связывающие определенные товары и категории.

Создание хранимых процедур

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

  • catalog_count_products_in_category
  • catalog_get_products_in_category
  • catalog_count_products_on_department
  • catalog_get_products_on_department
  • catalog_count_products_on_catalog
  • catalog_get_products_on_catalog
  • catalog_get_product_details
  • catalog_get_product_locations

Имя каждой процедуры кратко описывает ее назначение. Это упростит дальнейшуюотладку.Создадим эти процедуры с помощью вкладки SQL в phpMyAdmin,задавая в качестве разделителя символы $$.

Добавим на уровень логики приложения несколько методов,предназначенных для вызова только что созданных нами хранимых процедур в класс Catalog (расположенным в файлеbusiness/catalog.php) (приложение А)

  • GetDepartmentDetails()
  • GetCategoriesInDepartment()
  • GetCategoryDetails()
  • HowManyPages()
  • GetProductsInCategory()
  • GetProductsOnDepartment()
  • GetProductsOnCatalog()
  • GetProductDetails()
  • GetProductLocations()

Преждечемнаписатьметодыуровнялогикиприложения, нужнообновитьсодержимоефайла include/config.php, добавиввнегоконстанты SHORT_PRODUCT_DESCRIPTION_LENGTH и PRODUCTS_PER_PAGE.

// Задаем параметры, используемые при генерации списков товаров

define(‘SHORT_PRODUCT_DESCRIPTION_LENGTH’, 150);

  • define(‘PRODUCTS_PER_PAGE’, 4);

Кроме того, нужно внести изменения в файл index.php.

<?php

// Активизируемсеанс

session_start()

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

2.8 Отображение информации об отделе и категориях

Добавим в файл стилей goodstore.css из папки styles два следующих стиля. Они понадобятся для отображения названия отдела и его описания.

  • title {

border-left: 15px solid #0590C7;left: 10px;

}

  • description {style: italic;

}

Создадим файл шаблона с именем blank.tpl в папке presentation/templates и поместите в этот файл строку

{* Smarty blank page *}

Добавим файл шаблона с именем department.tpl (листинг 18) в папку presentation/templates и поместим в него следующий код

Листинг 18. Файл шаблона

{* department.tpl *}

{load_presentation_objectfilename=»department» assign=»obj»}

<h1>

  • <p>
  • Два элемента объекта представления, $obj->mName и $obj->mDescription,содержат название и описание выбранного отдела.

Создадим объект представления Department в файле department.php (приложение).

Теперь необходимомодифицировать файлы presentation/templates/store_front.tpl (приложение А) и presentation/store_front.php (приложение А), добавив в них несколько строчек программы, чтобы только что созданныйкомпонентный шаблон загружался, когда в строке запроса присутствует параметр DepatmentId.

Загрузим страницу в браузере, для проверки работы программы (рис. 18).

Произведем аналогичные действия для отображения информации о категории: создадим файлы categories_list.tpl (приложение А) и categories_list.php (приложение А), модифицируем файл store_front.tpl, добавив необходимые строчки.

 отображение информации об отделе и категориях 1

Рисунок 18 — Информация о выбранном отделе

Загрузим страничку в браузере, должны отобразиться категории и информация о них (рис. 19).

 отображение информации об отделе и категориях 2

Рисунок 19 — Информация о выбранной категории

Когда посетитель выбирает отдел из списка, отображается список категорийэтого отдела. Чтобы список категорий мог отображаться, созданный шаблонSmarty categories_list содержит раздел, перебирающий элементы списка категорий. В этом разделе содержатся ссылки наindex.php, но они будут создавать запросы с параметром CategoryId, сообщая, накакой категории щелкнул посетитель.

2.9 Отображение списка товаров и содержимого главной страницы

Для того, что бы на сайте интернет-магазина отображались товары, понадобятся фото этих товаров. Для этого в папке goodstoreсоздадим папку product_images и поместим в нее все необходимые изображения, а так же в базе данных в таблице productукажем названия этих изображений.

Добавим в файл goodstore.css, находящийся в папке styles, следующие стили (листинг 19).

Листинг 19. Стили CSSдля отображения списка товаров

  • product-list tbody tr td {: none;: 0;: 50%;

}

  • product-list tbody tr td p img {: 2px solid #c6e1ec;: right;: 0 10px;align: top;

}

  • product-title {left: 10px solid #0590C7;left: 5px;

}

  • section {: block;

}

  • price {weight: bold;

}

  • old-price { color: #ff0000;weight: normal;decoration: line-through;

}

Впапке presentation/templates создадимновыйфайлдизайн-шаблона Smarty сименем products_list.tpl (приложениеА).

Для шаблона products_list.tpl создадим объект представления, файл с именем products_list.php (приложение А).

Создадимфайлpresentation/link.php (приложение А)идобавьтевнего класс Linkи методToCategory() (листинг 20)

Листинг 20. Метод ToCategory()static function ToCategory($departmentId, $categoryId)

{

$link = ‘index.php?DepartmentId=’ . $departmentId .

‘&CategoryId=’ . $categoryId;self::Build($link);self::Build($link);

}

Вставимвкласс Link новыеметоды ToDepartment(), ToProduct(), добавимпараметр $Page икодподдержкистраницвметоды ToDepartment() и ToCategory().

Загрузим страницу в браузере и выберем одну из категорий (рис. 20).

 отображение списка товаров и содержимого главной страницы 1

Рисунок 20 — Отображение списка товаров

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

Для начала создадим файл дизайн-шаблона Smarty. Этофайлсименем first_page_contents.tpl впапке presentation/templates. Поместимвнегоследующийкод (листинг 21).

Листинг 21. Файл дизайн-шаблона для главной страницы

{* first_page_contents.tpl *}

<p class=»description»>

Добро пожаловать на сайт магазина женской одежды GoodStore!

<pclass=»description»>

По всем интересующим Вас вопросам, а так же вопросам

доставки и оплаты обращаться по электронному адресу администратора:

goodstore.shop@yandex.ru или по телефону 8-938-444-68-12

</p>

  • </p>
  • <p>

Мы надеемся, вам понравится

наш ассортимент товаров!

Сейчас действуют скидки на зимние коллекции.

</p>

  • {include file=»products_list.tpl»}

Внесемизменениявфайлыstore_front.tpl, products_list.phpиlink.php. Далееоткроемпроектвбраузере (рис. 21).

 отображение списка товаров и содержимого главной страницы 2

Рисунок 21 — Главная страница с рекламируемыми товарами

Собственно список товаров по-прежнему отображается с помощью компонентного шаблона products_list. Но теперь он загружается не из файла department.tpl, а из нового файла шаблона — first_page_contents.tpl.

Атрибуты товаров

Для реализации атрибутов товаров (цвет, размер), создадим три таблицы (attribute, attribute_value и product_attribute) и хранимую процедуруcatalog_get_product_attributes. В таблице attribute будут храниться названия атрибутов.Таблица attribute_value хранит возможные значения атрибутов для каждойгруппы атрибутов. Между таблицами attribute и attribute_value установлено отношение “один-ко-многим”.Таблица product_attribute обеспечивает выполнение отношения “многие-ко-многим” между таблицами product и attribute_value.

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

Добавимнеобходимыйкодвфайлpresentation\templates\products_list.tpl (приложение А).

Далее добавим две строчки в файл presentation/products_list.php (приложение А)

$this->mProducts[$i][‘attributes’] =::GetProductAttributes($this->mProducts[$i][‘product_id’]);

  • Модифицируемфайлpresentation/templates/product.tpl (приложение А), добавленный код генерирует списокзначений атрибутов для страницы со сведениями о товаре.

Добавим следующие строчки в метод init() класса Product в файле presentation/product.php (приложение А)

$this->mProduct[‘attributes’] =::GetProductAttributes($this->mProduct[‘product_id’]);

  • Добавим в файл styles/goodstore.css следующий стиль:
  • attributes {: both;: block;
  • top: 5px;

}

Откроем в браузере страницу #»896847.files/image022.gif»>

Рисунок 22 — Страница товаров с атрибутами

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

2.10 Интеграция корзины и прием платежей

Чтобы принимать платежи, нужно добавить на сайт два важных элемента: кнопки “Добавить в корзину” для добавления товара в корзину (по одной для каждого товара) и кнопку “Показать корзину” для просмотра корзины (по одной на страницу).

PayPal позволяет

легко реализовать оба данных элемента.

В файл config.php из папки includeдобавим следующие объявления констант (листинг 22).

Листинг 22. Объявления констант для PayPal

// КонфигурацияPayPal

define(‘PAYPAL_URL’, ‘https://www.paypal.com/cgi-bin/webscr’);(‘PAYPAL_EMAIL’, ‘goodstore.shop@yandex.ru’);(‘PAYPAL_CURRENCY_CODE’, ‘USD’);(‘PAYPAL_RETURN_URL’, ‘#»896847.files/image023.gif»>

Рисунок 23 — Страница Goodstore с кнопками Добавить в корзину и Показать корзину

ЗагрузимсайтGoodstoreи посмотрим результат. На рис.23 изображен сайт с добавленными кнопками: Добавить в корзину и Показать корзину. На рис.24 изображена корзина покупателя с добавленным товаром.

 интеграция корзины и прием платежей 1

Рисунок 24 — Корзина покупателя с добавленным товаром

После щелчка на кнопке “Добавить в корзину” веб-браузер пользователя получит перенаправление с кодом HTTP 302 на ссылку “Добавить в корзину”в PayPal. Эта ссылка будет вести на страницу корзины покупателя.

2.11 Администрирование каталога

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

2.11.1 Отделы и категории

Чтобы предотвратить несанкционированный доступ к интерфейсу администратора, начнем с создания формы для ввода идентификатора пользователя и пароля и разрешим доступ к интерфейсу администратора только пользователям с заданными идентификаторами и паролями.

Далее нужно будет создать административную часть сайта (часто ее называют панелью управления (control panel)).

Главная страница этой части будет содержаться в файле admin.php (приложение А), с которым будет связан шаблон (store_admin.php (приложение А)).Кроме того, понадобятся шаблон главного меню (admin_menu.tpl (приложение А)), используемогодля навигации в административной части, шаблон, отвечающий за аутентификацию (admin_login (приложение А)), и два компонентных шаблона для администрирования каталога (admin_departments.tpl (приложение А)иadmin_categories.tpl (приложение А)).

Добавимвфайлыfirst_page_contents.tpl (приложение А) иfirst_page_contents.php (приложение А) код, который необходим для добавления на главную страницу ссылки, ведущей на страницу администрирования (рис. 25).

 отделы и категории 1

Рисунок 25 — Страница входа на административную часть сайта

Для реализации администрирования отделов на уровне логики представления создадим файлы admin_departments.tpl (приложение А) и admin_departments.php (приложение А),модифицируем файлы link.php иstore_admin.php, чтобы обеспечить загрузку только что созданного компонентного

шаблона admin_departments.

Добавьте код в класс Catalogвфайлеbusiness/catalog.php.

С помощью phpMyAdmin создадим четыре хранимые процедуры:

  • catalog_get_departments()
  • catalog_add_department()
  • catalog_update_department()
  • catalog_delete_department()

Работа страницы администрирования отделов представлена на рис. 26.

 отделы и категории 2

Рисунок 26 — Страница администрирования отделов

Администрирование категорий основано на тех же концепциях и механизмах, что и администрирование отделов. Создадим файл шаблона admin_categories.tpl (приложение А) затем файл admin_categories.php (приложение А), изменим файл link.php и добавим в конец класса Link следующий метод (листинг 23).

Листинг 23. Метод ToDepartmentCategoriesAdmin()

// Создает ссылку на страницу администрирования категорий

public static function ToDepartmentCategoriesAdmin($departmentId)

{

$link = ‘Page=Categories&DepartmentId=’ . $departmentId;self::ToAdmin($link);

}

Откроемфайл business/catalog.php идобавимвкласс Catalog новыеметоды. Модифицируем метод init() класса StoreAdmin в файле presentation/store_admin.php длязагрузкиновогокомпонентногошаблона. А также создадим необходимые хранимые процедуры. Результат представлен на рис.27.

 отделы и категории 3

Рисунок 27 — Страница администрирования категорий

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

2.11.2 Товары и атрибуты

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

Создадим страницу управления атрибутами товаров. Она будет доступна по ссылке PRODUCT ATTRIBUTES ADMIN в менюадминистрирования.

Начнем с создания компонентного шаблона admin_attributes, состоящий из файлов admin_attributes.tpl (приложение А) и admin_attributes.php (приложение А).

Этот шаблон реализует страницу редактирования названий атрибутов (рис. 28).Создадим компонентный шаблон admin_attribute_values, состоящий из файлов admin_attribute_values.tpl (приложение А)иadmin_attribute_values.php (приложение А).

Этотшаблонреализуетстраницу редактирования значений атрибутов (рис. 29).

Добавили ссылки на новые элементы в шаблон admin_menu (содержащий ссылки на все административные страницы сайта) и поместим в класс Link новые методы для генерации ссылок.

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

Перейдем к администрированию товаров. Для начала создадим базовую функциональность администрирования товаров в шаблоне Smarty admin_products (этотшаблон состоит из файлов admin_products.tpl (приложение А) и admin_products.php (приложение А)).

Создадим ссылку на новую страницу из шаблона store_admin. Реализуем работающие с товарами служебные методы уровня логики приложения и хранимые процедуры в базе данных.

 товары и атрибуты 1

Рисунок 28 — Страница редактирования названий атрибутов

 товары и атрибуты 2

Рисунок 29 — Страница редактирования значений атрибутов

Загрузим раздел администрирования в браузере и щелкнем на кнопке “Редактировать продукт” (рис. 30).

 товары и атрибуты 3

Рисунок 30 — Редактирование товаров

Теперь можно перейти к администрированию описаний товаров. Создадимфайлadmin_product_details.tpl (приложение А), добавим в файлbusiness/catalog.phpэлемент $mProductDisplayOptions (листинг 24) в класс Catalog

Листинг 24. Элемент $mProductDisplayOptions

// Определяетместаотображениятовара

public static $mProductDisplayOptions = array (‘Default’,//0

‘On Catalog’, // 1

‘On Department’, // 2

‘On Both’); // 3

Создадимвпапке presentation файл admin_product_details.php (приложениеА), вфайлеlink.php добавимвконецкласса Link следующийметод (листинг 25).

Листинг 25. Метод ToProductAdmin()

// Создает ссылку на страницу администрирования информации о товарах

public static function ToProductAdmin($departmentId, $categoryId,

$productId)

{

$link = ‘Page=ProductDetails&DepartmentId=’ . $departmentId .

‘&CategoryId=’ . $categoryId . ‘&ProductId=’ . $productId;self::ToAdmin($link);

}

Модифицируемметодinit() классаStoreAdminвфайлеstore_admin.phpдлязагрузкишаблона admin_product_details , добавивследующиестрочки:elseif ($admin_page == ‘ProductDetails’)

$this->mContentsCell = ‘admin_product_details.tpl’;

  • На уровне логики приложения добавим в класс Catalog в файле business/catalog.php следующие методы:
  • UpdateProduct — для обновления сведений о товаре
  • DeleteProduct — для полного удаления товара из каталога
  • RemoveProductFromCategory — для удаления товара из категории
  • GetCategories — для получения полного списка категорий из каталога
  • GetProductInfo — для получения сведений о товаре
  • GetCategoriesForProduct — для получения списка категорий, к которым относится заданный товар
  • SetProductDisplayOption — для задания режима отображения товара
  • AssignProductToCategory — для зачисления товара в категорию
  • MoveProductToCategory — для перемещения товара в другую категорию
  • GetAttributesNotAssignedToProduct — для получения из таблицы attribute_values всех значений атрибутов, не назначенных ни одному товару
  • AssignAttributeValueToProduct — для присвоения значения атрибута товару
  • RemoveProductAttributeValue — для удаления связи между товаром и значением атрибута из таблицы product_attribute
  • SetImage1 — для изменения имени файла с изображением для заданного товара
  • SetThumbnail — для изменения имени файла с уменьшенным изображением

На уровне данныхнужно создать хранимые процедуры, используемые толькочто созданными методами уровня логики приложения (приложение Б).

  • catalog_update_product()
  • catalog_delete_product()
  • catalog_remove_product_from_category()
  • catalog_get_categories()
  • catalog_get_product_info()
  • catalog_get_categories_for_product()
  • catalog_set_product_display_option()
  • catalog_assign_product_to_category()
  • catalog_move_product_to_category()
  • catalog_get_attributes_not_assigned_to_product()
  • catalog_assign_attribute_value_to_product()
  • catalog_remove_product_attribute_value()
  • catalog_set_image()
  • catalog_set_thumbnail()

Теперь можно загрузить страницу администрирования товаров в браузере и перейти к редактированию описания товара (рис. 31).

 товары и атрибуты 4

Рисунок 31 — Редактирование описания товара

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

На данный момент сайт снабжен всеми необходимыми инструментами администрирования каталога.

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

Заключение

В ходе выполнения работы была достигнута основная цель — разработан интернет-магазин.

Были изучены основные принципы и инструменты построения интернет-магазина:

  • в качестве web-серверабыл выбран сервер XAMPP, так как в его состав входят необходимые инструменты для разработки интернет-магазина, установка XAMPPбыстрая и не сложная, удобный интерфейс и надежная работа;
  • для создания базы данных, хранящей необходимую информацию для функционирования интернет-магазина, была выбрана СУБД MySQL.

MySQL отличатся хорошей скоростью работы, надежностью, гибкостью и при этом распространяется совершенно бесплатно;

  • в качестве языка программирования веб-приложений, был выбран PHP, предоставляющий возможность создания веб-страниц, управляемых базами данных, и поддерживающий СУБД MySQL.

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

Разработанный интернет-магазин был протестирован локально. Полученные результаты соответствовали ожидаемым. Были сделаны проверки возможных ошибок, недочетов — система функционирует надежно, без сбоев.

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

1. Дари К., Баланеску Э. PHP и MySQL: создание интернет-магазина: Пер. с англ.- М.: Издательский дом“Вильямс”, 2011. — 640с.

  • Савельева Н.В. Язык программирования РНР. — М.: Интернет Университет Информационных Технологий, 2015. — 211с.
  • Веллинг Л., Томсон Л.

MySQL. Учебное пособие: Пер. с англ. — М.: Издательский дом“Вильямс”, 2015. — 304с.

  • Гольцман В. MySQL 5.0. Библиотека программиста. — Санкт-Петербург, 2010. — 253с.
  • Фиайли К.SQL: Пер.

с англ. — М.: ДМК Пресс, 2003. — 456 с.

  • Комолова Н., ЯковлеваЕ. HTML: Самоучитель. 2-е изд. — СПб.: Питер, 2011. — 288 с.
  • Полонская Е.

Язык HTML. Самоучитель. : — М.: Издательский дом “Вильямс”, 2003.- 320с.

  • Сидерхолм Д. CSS3 для веб-дизайнеров. — Манн, Иванов и Фербер, 2012. — 125с.
  • Иванов И.

SEO: Поисковая Оптимизация от А до Я. — Самоиздательство, 2012. — 587с.

Приложение А

Листинги файлов программ

Файл store_front.tpl

{* smarty *}

{config_load file=»site.conf»}

{load_presentation_object filename=»store_front» assign=»obj»}

<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Transitional//EN»

«http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd»>

  • <html>
  • <head>
  • <title>{#site_title#}</title>
  • <meta http-equiv=»Content-Type» content=»text/html;
  • charset=UTF-8″ />
  • <link type=»text/css» rel=»stylesheet»=»{$obj->mSiteUrl}styles/goodstore.css» />
  • </head>
  • <body>
  • <div id=»doc»>
  • <div id=»bd»>
  • <div id=»yui-main»>
  • <div>
  • <div id=»header»>
  • <a href=»{$obj->mSiteUrl}»>
  • <img src=»{$obj->mSiteUrl}images/logo.tif» alt=»goodstore logo» />
  • </a>
  • </div>
  • <div id=»contents»>
  • {include file=$obj->mContentsCell}

</div>

  • </div>
  • </div>
  • <div>
  • {include file=»departments_list.tpl»}

{include file=$obj->mCategoriesCell}

<div>

  • <form target=»_self» method=»post»=»{$smarty.const.PAYPAL_URL}»>
  • <input type=»hidden» name=»cmd» value=»_cart» />
  • <input type=»hidden» name=»business»=»{$smarty.const.PAYPAL_EMAIL}» />
  • <input type=»hidden» name=»display» value=»1″ />
  • <input type=»hidden» name=»shopping_url»=»{$obj->mPayPalContinueShoppingLink}» />
  • <input type=»hidden» name=»return»=»{$smarty.const.PAYPAL_RETURN_URL}» />
  • <input type=»hidden» name=»cancel_return»=»{$smarty.const.PAYPAL_CANCEL_RETURN_URL}» />
  • <input type=»submit» name=»view_cart» value=»Показатькорзину» />
  • </form>
  • </div>
  • </div>
  • </div>
  • </div>
  • </body>
  • </html>
  • Файлgoodstore.css

@import «reset-min.css»;

  • @import «base-min.css»;
  • @import «fonts-min.css»;
  • @import «grids-min.css»;{size: 85%;family: «century gothic»;}
  • yui-t2, #bd, #yui-main {index: -5;}
  • yui-b, .yui-g {index: auto;}

#header {top: 15px;align: right;}

  • error_box {color: #ffffcc;: 1px solid #dc143c;: #DC143C;: 0 auto;: auto;: 5px;: relative;align: left;: 90%;index: 5;}.yui-b div.box {: #333333;: 1px solid #c6e1ec;top: 15px;
  • }.yui-b div p.box-title {: #0590C7;bottom: 2px solid #c6e1ec;: #FFFFFF;: block;size: 93%;weight: bold;: 1px;: 2px 10px;}{: #0590C7;
  • }:hover {: #ff0000;
  • }.selected {weight: bold;
  • }.yui-b div ul {: 0;
  • }.yui-b div ul li {bottom: 1px solid #fff;style-type: none;
  • }.yui-b div ul li a {: #333333;: block;decoration: none;: 3px 10px;
  • }.yui-b div ul li a:hover {: #c6e1ec;: #333333;

}

  • title {left: 15px solid #0590C7;left: 10px;

}

  • description {style: century gothic;

}

  • product-list tbody tr td {: none;: 0;: 50%;

}

  • product-list tbody tr td p img {: 2px solid #c6e1ec;: right;: 0 10px;align: top;

}

  • product-title {left: 10px solid #0590C7;left: 5px;

}

  • section {: block;

}

  • price {weight: bold;

}

  • old-price {: #ff0000;weight: normal;decoration: line-through;

}

  • product-image {: 2px solid #c6e1ec;
  • }{: 0px;: 0px 0px 0px 5px;
  • }li {: #0590C7;style-type: none;: 0px;: 5px 0px;

}

  • attributes {: both;: block;top: 5px;
  • }.yui-b div form {: 5px 10px;
  • }, select, textarea {family: «century gothic»;size: 85%;
  • }.yui-b div form.add-product-form

{: 0;: 0;

}

  • add-product-form p

{: 0;: 0 0 10px 0;

}

  • view-cart

{: 10px;align: center;

}

  • login {: #333333;: block;: 1px solid #c6e1ec;: 50px auto;: 325px;

}

  • login form p {: 0 10px;
  • }{: block;

}

  • error {: #ff0000;size: 85%;family: «century gothic»;

}

  • login-title {: #0590c7;bottom: 2px solid #c6e1ec;: #ffffff;: block;size: 93%;family: «century gothic»;: 1px;: 2px 10px;

}

  • no-items-found {: #ff0000;
  • }.tss-table {: 100%;
  • }.tss-table th {: #0590c7;;: none;bottom: 3px solid #c6e1ec;: #ffffff;align: left;
  • }.tss-table td {: none;bottom: 1px solid #0590c7;

}

  • words {: #ff0000;
  • }.borderless-table {: 100%;

}

  • borderless-table td {: none;left: 0;

}

  • bold-text {size: 93%;weight: century gothic;}

Файлconfig.php

<?php

// вSITE_ROOTсодержитсяполныйпутькпапкеgoodstore(‘SITE_ROOT’, dirname(dirname(__FILE__)));

  • // Папки приложения(‘PRESENTATION_DIR’, SITE_ROOT . ‘/presentation/’);(‘BUSINESS_DIR’, SITE_ROOT . ‘/business/’);

// Настройки, необходимые для конфигурирования Smarty

define(‘SMARTY_DIR’, SITE_ROOT . ‘/libs/smarty/’);(‘TEMPLATE_DIR’, PRESENTATION_DIR . ‘templates’);(‘COMPILE_DIR’, PRESENTATION_DIR . ‘templates_c’);(‘CONFIG_DIR’, SITE_ROOT . ‘/include/configs’);

// Эти значения должны быть равны true на этапе разработки

define(‘IS_WARNING_FATAL’, true);(‘DEBUGGING’, true);

// Типы ошибок, о которых должны составляться сообщения

define(‘ERROR_TYPES’, E_ALL);

// Настройки отправки сообщений администраторам по электронной почте

define(‘SEND_ERROR_MAIL’, false);(‘ADMIN_ERROR_MAIL’, ‘goodstore.shop@yandex.ru ‘);(‘SENDMAIL_FROM’, ‘Errors@example.com’);_set(‘sendmail_from’, SENDMAIL_FROM);

// По умолчанию мы не записываем сообщения в журнал

define(‘LOG_ERRORS’, false);(‘LOG_ERRORS_FILE’, ‘c:\\xampp\\htdocs\\goodstore\\errors_log.txt’); // Windows

// define(‘LOG_ERRORS_FILE’, ‘/home/username/goodstore/errors.log’); // Linux

// Параметры соединения с базой данных

define(‘DB_PERSISTENCY’, ‘true’);

  • define(‘DB_SERVER’, ‘localhost’);(‘DB_USERNAME’, ‘goodstoreadmin’);(‘DB_PASSWORD’, ‘goodstoreadmin’);(‘DB_DATABASE’, ‘goodstore’);(‘PDO_DSN’, ‘mysql:host=’ . DB_SERVER . ‘;dbname=’ . DB_DATABASE);

/* Общее сообщение об ошибке, которое должно отображаться вместо

подробной информации (если DEBUGGING равно false) */

define(‘SITE_GENERIC_ERROR_MESSAGE’, ‘<h1>Good Store Error!</h1>’);

// Порт HTTP-сервера (можно пропустить, если используется порт 80)

define(‘HTTP_SERVER_PORT’, ’80’);

/* Имя виртуальной директории, в которой располагается сайт, например:

‘/goodstore/’ если сайт работает из папки

‘/’ если сайт работает из папки http://www.example.com/ */

define(‘VIRTUAL_LOCATION’, ‘/goodstore/’);

// Задаем параметры, используемые при генерации списков товаров

define(‘SHORT_PRODUCT_DESCRIPTION_LENGTH’, 150);(‘PRODUCTS_PER_PAGE’, 4);

  • // Конфигурация PayPal(‘PAYPAL_URL’, ‘https://www.paypal.com/cgi-bin/webscr’);(‘PAYPAL_EMAIL’, ‘goodstore.shop@yandex.ru’);(‘PAYPAL_CURRENCY_CODE’, ‘USD’);(‘PAYPAL_RETURN_URL’, ‘http://localhost/goodstore’);(‘PAYPAL_CANCEL_RETURN_URL’, ‘http://localhost/goodstore’);

// Если эта константа не установлена в no, доступ к

// страницам администрирования

//возможен только с помощью SSL(‘USE_SSL’, ‘yes’);

// Идентификатор и пароль администратора

define(‘ADMIN_USERNAME’, ‘goodstore’);

  • define(‘ADMIN_PASSWORD’, ‘goodstore’);
  • ?>
  • Файл application.php

<?php

// Ссылканабиблиотеку Smarty_once SMARTY_DIR . ‘Smarty.class.php’;

/* Класс, расширяющий Smarty, используется для обработки и

отображенияфайлов Smarty */Application extends Smarty

{

// Конструкторклассаfunction __construct()

{

// Вызовконструктора Smarty::Smarty();

// Меняемпапкишаблоновпоумолчанию

$this->template_dir = TEMPLATE_DIR;

  • $this->compile_dir = COMPILE_DIR;
  • $this->config_dir = CONFIG_DIR;
  • $this->plugins_dir[0] = SMARTY_DIR . ‘plugins’;
  • $this->plugins_dir[1] = PRESENTATION_DIR . ‘smarty_plugins’;

}

}

?>

  • Файл index.php

<?php

// Активизируем сеанс

//session_start()

// Подключаем служебные файлы

require_once ‘include/config.php’;_once BUSINESS_DIR . ‘error_handler.php’;

  • //Задаем обработчик ошибок::SetHandler();
  • // Загружаем шаблон страницы приложения_once PRESENTATION_DIR .

‘application.php’;_once PRESENTATION_DIR . ‘link.php’;

  • //Загружаем дескриптор базы данных_once BUSINESS_DIR . ‘database_handler.php’;

// Загружаем уровень логики приложения

require_once BUSINESS_DIR . ‘catalog.php’;

// Загружаем файл шаблонов Smarty

$application = new Application();

// Отображаем страницу

$application->display(‘store_front.tpl’);

// Закрываем соединение с базой данных

DatabaseHandler::Close();

// Пытаемся загрузить несуществующий файл

//require_once ‘inexistent_file.php’;

  • ?>
  • Файл error_handler.php

<?php

{

// Закрытый конструктор, не позволяющий непосредственно

// создавать объекты класса

privatefunction __construct()

{

}

/* Выбираем метод ErrorHandler::Handler в качестве метода обработки ошибок */

public static function SetHandler($errTypes = ERROR_TYPES)

{set_error_handler(array (‘ErrorHandler’, ‘Handler’), $errTypes);

}

// Метод обработки ошибокstatic function Handler($errNo, $errStr, $errFile, $errLine)

{

/* Первые два элемента массива трассировки нам неинтересны:

  • ErrorHandler.GetBacktrace

ErrorHandler.Handler */

$backtrace = ErrorHandler::GetBacktrace(2);

// Сообщения об ошибках, которые будут выводиться, отправляться по

// электронной почте или записываться в журнал

$error_message = «\nERRNO: $errNo\nTEXT: $errStr» .

«\nLOCATION: $errFile, line » .

«\nShowing backtrace:\n$backtrace\n\n»;

// Отправляем сообщения об ошибках, если SEND_ERROR_MAIL равно true

if (SEND_ERROR_MAIL == true)_log($error_message, 1, ADMIN_ERROR_MAIL, «From: » ._FROM . «\r\nTo: » . ADMIN_ERROR_MAIL);

// Записываем сообщения в журнал, если LOG_ERRORS равно true

if (LOG_ERRORS == true)_log($error_message, 3, LOG_ERRORS_FILE);

/* Выполнение не прекращается при предупреждениях,

если IS_WARNING_FATAL равно false. Ошибки E_NOTICE и E_USER_NOTICE

тоже не приводят к прекращению выполнения */

if (($errNo == E_WARNING && IS_WARNING_FATAL == false) ||

($errNo == E_NOTICE || $errNo == E_USER_NOTICE))

// Если ошибка не фатальная…

{

// Выводим сообщение, только если DEBUGGING равно true

if (DEBUGGING == true)'<div>

}

else

// Если ошибка фатальная…

{

// Выводим сообщение об ошибке

if (DEBUGGING == true)'<div>

// Останавливаем обработку запроса

exit();

}

}

// Составляем список вызовов

public static function GetBacktrace($irrelevantFirstEntries)

{

$s = »;

  • $MAXSTRLEN = 64;
  • $trace_array = debug_backtrace();($i = 0;
  • $i <
  • $irrelevantFirstEntries;
  • $i++)_shift($trace_array);
  • $tabs = sizeof($trace_array) — 1;($trace_array as $arr)

{

$tabs -= 1;(isset ($arr[‘class’]))

$s .= $arr[‘class’] . ‘.’;

  • $args = array ();(!empty ($arr[‘args’]))($arr[‘args’]as $v)

{(is_null($v))

$args[] = ‘null’;(is_array($v))

$args[] = ‘Array[‘ . sizeof($v) . ‘]’;(is_object($v))

$args[] = ‘Object: ‘ . get_class($v);(is_bool($v))

$args[] = $v ? ‘true’ : ‘false’;

{

$v = (string)@$v;

  • $str = htmlspecialchars(substr($v, 0, $MAXSTRLEN));(strlen($v) >
  • $MAXSTRLEN)

$str .= ‘…’;

  • $args[] = ‘»‘ . $str . ‘»‘;

}

}

$s .= $arr[‘function’] . ‘(‘ . implode(‘, ‘, $args) . ‘)’;

  • $line = (isset ($arr[‘line’]) ? $arr[‘line’]: ‘unknown’);
  • $file = (isset ($arr[‘file’]) ? $arr[‘file’]: ‘unknown’);
  • $s .= sprintf(‘ # line %4d, file: %s’, $line, $file);
  • $s .= «\n»;
  • }$s;

}

}

?>

  • Файлdatabase_handler.php

<?php

// Класс, предоставляющий базовую функциональность доступа к данным

classDatabaseHandler

{

// Переменная для хранения экземпляра класса PDO

privatestatic $_mHandler;

// private-конструктор, не позволяющий напрямую создавать объекты класса

privatefunction __construct()

{

}

// Возвращает проинициализированный дескриптор базы данных

privatestaticfunctionGetHandler()

{

// Создаем соединение с базой данных, только если его еще нет

if (!isset(self::$_mHandler))

{

// Выполняем код, перехватывая потенциальные исключения

try

{

// Создаем новый экземпляр класса PDO

self::$_mHandler =PDO(PDO_DSN, DB_USERNAME, DB_PASSWORD,(PDO::ATTR_PERSISTENT => DB_PERSISTENCY));

  • // Настраиваем PDO на генерацию исключений::$_mHandler->setAttribute(PDO::ATTR_ERRMODE,::ERRMODE_EXCEPTION);

}(PDOException $e)

{

// Закрываем дескриптор и генерируем ошибку

self::Close();

  • trigger_error($e->getMessage(), E_USER_ERROR);

}

}

// Возвращаем дескриптор базы данныхself::$_mHandler;

}

// Очищаем экземпляр класса PDOstatic function Close()

{::$_mHandler = null;

}

// Метод-обертка для PDOStatement::execute()static function Execute($sqlQuery, $params = null)

{

// Пытаемся выполнить SQL-запрос или хранимую процедуру

try

{

// Получаем дескриптор базы данных

$database_handler = self::GetHandler();

// Подготавливаем запрос к выполнению

$statement_handler = $database_handler->prepare($sqlQuery);

// Выполняем запрос

$statement_handler->execute($params);

}

// Генерируем ошибку, если при выполнении SQL-запроса возникло исключение

catch(PDOException $e)

{

// Закрываем дескриптор базы данных и генерируем ошибку

self::Close();_error($e->getMessage(), E_USER_ERROR);

}

}

// Метод-обертка для PDOStatement::fetchAll()static function GetAll($sqlQuery, $params = null,

$fetchStyle = PDO::FETCH_ASSOC)

{

// Инициализируем возвращаемое значение в null

$result = null;

// Пытаемся выполнить SQL-запрос или хранимую процедуру

try

{

// Получаем дескриптор базы данных

$database_handler = self::GetHandler();

// Подготавливаем запрос к выполнению

$statement_handler = $database_handler->prepare($sqlQuery);

// Выполняем запрос

$statement_handler->execute($params);

// Получаем результат

$result = $statement_handler->fetchAll($fetchStyle);

}

// Генерируем ошибку, если при выполнении SQL-запроса возникло исключение

catch(PDOException $e)

{

// Закрываем дескриптор базы данных и генерируем ошибку

self::Close();_error($e->getMessage(), E_USER_ERROR);}

// Возвращаем результаты запроса

return $result;

}

// Метод-обертка для PDOStatement::fetch()static function GetRow($sqlQuery, $params = null,

$fetchStyle = PDO::FETCH_ASSOC)

{

// Инициализируем возвращаемое значение

$result = null;

// Пытаемся выполнить SQL-запрос или хранимую процедуру

try

{

// Получаем дескриптор базы данных

$database_handler = self::GetHandler();

// Готовим запрос к выполнению

$statement_handler = $database_handler->prepare($sqlQuery);

// Выполняем запрос

$statement_handler->execute($params);

// Получаем результат

$result = $statement_handler->fetch($fetchStyle);

}

// Генерируем ошибку, если при выполнении SQL-запроса возникло исключение

catch(PDOException $e)

{

// Закрываем дескриптор базы данных и генерируем ошибку

self::Close();_error($e->getMessage(), E_USER_ERROR);

}

// Возвращаем результаты выполнения запроса

return $result;

}

// Возвращает значение первого столбца из строки

public static function GetOne($sqlQuery, $params = null)

{

// Инициализируем возвращаемое значение

$result = null;

// Пытаемся выполнить SQL-запрос или хранимую процедуру

try

{

// Получаем дескриптор базы данных

$database_handler = self::GetHandler();

// Готовим запрос к выполнению

$statement_handler = $database_handler->prepare($sqlQuery);

// Выполняем запрос

$statement_handler->execute($params);

// Получаем результат

$result = $statement_handler->fetch(PDO::FETCH_NUM);

/* Сохраняем первое значение из множества (первый столбец первой строки)в переменной $result */

$result = $result[0];

}

// Генерируем ошибку, если при выполнении SQL-запроса возникло исключение

catch(PDOException $e)

{

// Закрываем дескриптор базы данных и генерируем ошибку

self::Close();_error($e->getMessage(), E_USER_ERROR);

}

// Возвращаем результаты выполнения запроса

return $result;

}

}

?>

  • Файл catalog.php

<?php

// Класс уровня логики приложения для считывания информации

// о каталоге товаров

classCatalog

{

// Определяет места отображения товара

public static $mProductDisplayOptions = array (‘Default’, // 0

‘On Catalog’, // 1

‘On Department’, // 2

‘On Both’); // 3

// Получаем список отделовstatic function GetDepartments()

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_departments_list()’;

// Выполняем запрос и получаем результаты

returnDatabaseHandler::GetAll($sql);

}

// Возвращает подробные сведения о выбранном отделе

public static function GetDepartmentDetails($departmentId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_department_details(:department_id)’;

// Создаем массив параметров

$params = array (‘:department_id’ => $departmentId);

  • // Выполняем запрос и возвращаем результатDatabaseHandler::GetRow($sql, $params);

}

// Возвращает список категорий, относящихся к выбранному отделу

public static function GetCategoriesInDepartment($departmentId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_categories_list(:department_id)’;

// Создаем массив параметров

$params = array (‘:department_id’ => $departmentId);

  • // Выполняем запрос и возвращаем результатDatabaseHandler::GetAll($sql, $params);

}

// Возвращает название и описание выбранной категории

public static function GetCategoryDetails($categoryId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_category_details(:category_id)’;

// Создаем массив параметров

$params = array (‘:category_id’ => $categoryId);

  • // Выполняем запрос и возвращаем результатDatabaseHandler::GetRow($sql, $params);

}

/* Вычисляет, сколько страниц понадобится для отображения всех товаров -количество товаров возвращает запрос $countSql */

private static function HowManyPages($countSql, $countSqlParams)

{

// Создаем хеш для SQL-запроса

$queryHashCode = md5($countSql . var_export($countSqlParams, true));

// Проверяем, есть ли результаты выполнения запроса в кэше

if (isset ($_SESSION[‘last_count_hash’]) &&($_SESSION[‘how_many_pages’]) &&

$_SESSION[‘last_count_hash’] === $queryHashCode)

{

// Извлекаем кэшированное значение

$how_many_pages = $_SESSION[‘how_many_pages’];

}

{

// Выполняем запрос

$items_count = DatabaseHandler::GetOne($countSql, $countSqlParams);

// Вычисляем количество страниц

$how_many_pages = ceil($items_count / PRODUCTS_PER_PAGE);

// Сохраняем данные в сеансовых переменных

$_SESSION[‘last_count_hash’] = $queryHashCode;

  • $_SESSION[‘how_many_pages’] = $how_many_pages;

}

// Возвращаем количество страниц

return $how_many_pages;

}

// Возвращает список товаров, принадлежащих к заданной категории

public static function GetProductsInCategory(

$categoryId, $pageNo, &$rHowManyPages)

{

// Запрос, возвращающий количество товаров в категории

$sql = ‘CALL catalog_count_products_in_category(:category_id)’;

// Создаем массив параметров

$params = array (‘:category_id’ => $categoryId);

// Определяем, сколько страниц понадобится для отображения товаров

$rHowManyPages = Catalog::HowManyPages($sql, $params);

// Определяем, какой товар будет первым

$start_item = ($pageNo — 1) * PRODUCTS_PER_PAGE;

// Получаем список товаров

$sql = ‘CALL catalog_get_products_in_category(:category_id, :short_product_description_length,:products_per_page,

:start_item)’;

// Создаем массив параметров

$params = array (

‘:category_id’ => $categoryId,

‘:short_product_description_length’ =>_PRODUCT_DESCRIPTION_LENGTH,

‘:products_per_page’ => PRODUCTS_PER_PAGE,

‘:start_item’ => $start_item);

  • // Выполняем запрос и возвращаем результатDatabaseHandler::GetAll($sql, $params);

}

// Возвращает список товаров для страницы отдела

public static function GetProductsOnDepartment(

$departmentId, $pageNo, &$rHowManyPages)

{

// Запрос, возвращающий количество товаров для страницы отдела

$sql = ‘CALL catalog_count_products_on_department(:department_id)’;

// Создаем массив параметров

$params = array (‘:department_id’ => $departmentId);

// Определяем, сколько страниц понадобится для отображения товаров

$rHowManyPages = Catalog::HowManyPages($sql, $params);

// Определяем, какой товар будет первым

$start_item = ($pageNo — 1) * PRODUCTS_PER_PAGE;

// Получаем список товаров

$sql = ‘CALL catalog_get_products_on_department(

:department_id, :short_product_description_length,

:products_per_page, :start_item)’;

// Создаеммассивпараметров

$params = array ( ‘:department_id’ => $departmentId, ‘:short_product_description_length’ =>_PRODUCT_DESCRIPTION_LENGTH,

‘:products_per_page’ => PRODUCTS_PER_PAGE,

‘:start_item’ => $start_item);

  • // Выполняем запрос и возвращаем результатDatabaseHandler::GetAll($sql, $params);

}

// Возвращает список товаров для главной страницы каталога

public static function GetProductsOnCatalog($pageNo, &$rHowManyPages)

{

// Запрос, возвращающий количество товаров для главной страницы каталога

$sql = ‘CALL catalog_count_products_on_catalog()’;

// Определяем, сколько страниц понадобится для отображения товаров

$rHowManyPages = Catalog::HowManyPages($sql, null);

// Определяем, какой товар будет первым

$start_item = ($pageNo — 1) * PRODUCTS_PER_PAGE;

// Получаем список товаров

$sql = ‘CALL catalog_get_products_on_catalog(

:short_product_description_length,

:products_per_page, :start_item)’;

// Создаеммассивпараметров

$params = array (‘:short_product_description_length’ =>_PRODUCT_DESCRIPTION_LENGTH,

‘:products_per_page’ => PRODUCTS_PER_PAGE,

‘:start_item’ => $start_item);

  • // Выполняем запрос и возвращаем результатDatabaseHandler::GetAll($sql, $params);

}

// Возвращает подробную информацию о товареstatic function GetProductDetails($productId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_product_details(:product_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId);

  • // Выполняем запрос и возвращаем результатDatabaseHandler::GetRow($sql, $params);

}

// Возвращает список отделов и категорий, к которым принадлежит товар

public static function GetProductLocations($productId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_product_locations(:product_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId);

  • // Выполняем запрос и возвращаем результатDatabaseHandler::GetAll($sql, $params);

}

// Извлекаем атрибуты товаровstatic function GetProductAttributes($productId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_product_attributes(:product_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetAll($sql, $params);

}

// Извлекает из базы данных названия и описания всех отделов

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_departments()’;

// Выполняем запрос и возвращаем результаты

returnDatabaseHandler::GetAll($sql);

}

// Добавляет отделstatic function AddDepartment($departmentName, $departmentDescription)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_add_department(:department_name,

:department_description)’;

// Создаем массив параметров

$params = array (‘:department_name’ => $departmentName,

‘:department_description’ => $departmentDescription);

  • // Выполняем запрос::Execute($sql, $params);

}

// Обновляет сведения об отделеstatic function UpdateDepartment($departmentId, $departmentName,$departmentDescription)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_update_department(:department_id, :department_name,:department_description)’;

// Создаем массив параметров

$params = array (‘:department_id’ => $departmentId,

‘:department_name’ => $departmentName,

‘:department_description’ => $departmentDescription);

  • // Выполняем запрос::Execute($sql, $params);

}

// Удаляет отделstatic function DeleteDepartment($departmentId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_delete_department(:department_id)’;

// Создаем массив параметров

$params = array (‘:department_id’ => $departmentId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetOne($sql, $params);

}

// Возвращает список категорий отделаstatic function GetDepartmentCategories($departmentId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_department_categories(:department_id)’;

// Создаем массив параметров

$params = array (‘:department_id’ => $departmentId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetAll($sql, $params);

}

// Добавляет новую категориюstatic function AddCategory($departmentId, $categoryName,

$categoryDescription)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_add_category(:department_id, :category_name,:category_description)’;

// Создаеммассивпараметров

$params = array (‘:department_id’ => $departmentId,

‘:category_name’ => $categoryName,

‘:category_description’ => $categoryDescription);

  • // Выполняем запрос::Execute($sql, $params);

}

// Обновляет категориюstatic function UpdateCategory($categoryId, $categoryName, $categoryDescription)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_update_category(:category_id, :category_name,:category_description)’;

// Создаеммассивпараметров

$params = array (‘:category_id’ => $categoryId,

‘:category_name’ => $categoryName,

‘:category_description’ => $categoryDescription);

  • // Выполняем запрос::Execute($sql, $params);

}

// Удаляет категориюstatic function DeleteCategory($categoryId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_delete_category(:category_id)’;

// Создаем массив параметров

$params = array (‘:category_id’ => $categoryId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetOne($sql, $params);

}

// Возвращает все атрибутыstatic function GetAttributes()

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_attributes()’;

// Выполняем запрос и возвращаем результаты

returnDatabaseHandler::GetAll($sql);

}

// Добавляет атрибутstatic function AddAttribute($attributeName)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_add_attribute(:attribute_name)’;

// Создаем массив параметров

$params = array (‘:attribute_name’ => $attributeName);

  • // Выполняем запрос::Execute($sql, $params);

}

// Обновляет имя атрибутаstatic function UpdateAttribute($attributeId, $attributeName)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_update_attribute(:attribute_id, :attribute_name)’;

// Создаем массив параметров

$params = array (‘:attribute_id’ => $attributeId,

‘:attribute_name’ => $attributeName);

  • // Выполняем запрос::Execute($sql, $params);

}

// Удаляет атрибутstatic function DeleteAttribute($attributeId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_delete_attribute(:attribute_id)’;

// Создаем массив параметров

$params = array (‘:attribute_id’ => $attributeId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetOne($sql, $params);

}

// Возвращает сведения о выбранном атрибутеstatic function GetAttributeDetails($attributeId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_attribute_details(:attribute_id)’;

// Создаем массив параметров

$params = array (‘:attribute_id’ => $attributeId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetRow($sql, $params);

}

// Возвращает значения атрибутаstatic function GetAttributeValues($attributeId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_attribute_values(:attribute_id)’;

// Создаем массив параметров

$params = array (‘:attribute_id’ => $attributeId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetAll($sql, $params);

}

// Добавляет значение атрибутаstatic function AddAttributeValue($attributeId, $attributeValue)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_add_attribute_value(:attribute_id,:value)’;

// Создаем массив параметров

$params = array (‘:attribute_id’ => $attributeId,’:value’ => $attributeValue);

  • // Выполняем запрос::Execute($sql, $params);

}

// Обновляет значение атрибутаstatic function UpdateAttributeValue(

$attributeValueId, $attributeValue)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_update_attribute_value(

:attribute_value_id, :value)’;

// Создаем массив параметров

$params = array (‘:attribute_value_id’ => $attributeValueId,

‘:value’ => $attributeValue);

  • // Выполняем запрос::Execute($sql, $params);

}

// Удаляет значение атрибутаstatic function DeleteAttributeValue($attributeValueId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_delete_attribute_value(:attribute_value_id)’;

// Создаем массив параметров

$params = array (‘:attribute_value_id’ => $attributeValueId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetOne($sql, $params);

}

// Получаем товары заданной категорииstatic function GetCategoryProducts($categoryId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_category_products(:category_id)’;

// Создаем массив параметров

$params = array (‘:category_id’ => $categoryId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetAll($sql, $params);

}

// Создаем товар и зачисляем его в категорию

public static function AddProductToCategory($categoryId, $productName, $productDescription, $productPrice)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_add_product_to_category(:category_id, :product_name,:product_description, :product_price)’;

// Создаем массив параметров

$params = array (‘:category_id’ => $categoryId,

‘:product_name’ => $productName,

‘:product_description’ => $productDescription,’:product_price’ => $productPrice);

  • // Выполняем запрос::Execute($sql, $params);

}

// Обновляет сведения о товареstatic function UpdateProduct($productId, $productName,

$productDescription, $productPrice,$productDiscountedPrice)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_update_product(:product_id, :product_name,:product_description, :product_price,

:product_discounted_price)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId,

‘:product_name’ => $productName,

‘:product_description’ => $productDescription,

‘:product_price’ => $productPrice,

‘:product_discounted_price’ => $productDiscountedPrice);

  • // Выполняем запрос::Execute($sql, $params);

}

// Удаляет товар из каталогаstatic function DeleteProduct($productId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_delete_product(:product_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId);

  • // Выполняем запрос::Execute($sql, $params);

}

// Удаляет товар из категорииstatic function RemoveProductFromCategory($productId, $categoryId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_remove_product_from_category( :product_id, :category_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId,

‘:category_id’ => $categoryId);

// Выполняем запрос и возвращаем результаты

return DatabaseHandler::GetOne($sql, $params);

}

// Возвращает список категорийstatic function GetCategories()

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_categories()’;

// Выполняем запрос и возвращаем результаты

returnDatabaseHandler::GetAll($sql);

}

// Возвращает сведения о товареstatic function GetProductInfo($productId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_product_info(:product_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetRow($sql, $params);

}

// Возвращает список категорий, к которым относится товар

public static function GetCategoriesForProduct($productId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_get_categories_for_product(:product_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetAll($sql, $params);

}

// Включает товар в категориюstatic function SetProductDisplayOption($productId, $display)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_set_product_display_option(

:product_id, :display)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId,

‘:display’ => $display);

  • // Выполняем запрос::Execute($sql, $params);

}

// Включает товар в категориюstatic function AssignProductToCategory($productId, $categoryId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_assign_product_to_category(

:product_id, :category_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId,

‘:category_id’ => $categoryId);

  • // Выполняем запрос::Execute($sql, $params);

}

// Перемещает товар из одной категории в другую

public static function MoveProductToCategory($productId, $sourceCategoryId,$targetCategoryId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_move_product_to_category(:product_id,

:source_category_id, :target_category_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId,

‘:source_category_id’ => $sourceCategoryId,

‘:target_category_id’ => $targetCategoryId);

  • // Выполняем запрос::Execute($sql, $params);

}

// Возвращает атрибуты, не присвоенные никаким товарам

public static function GetAttributesNotAssignedToProduct($productId)

{

// Составляем SQL-запрос

$sql = ‘CALL_get_attributes_not_assigned_to_product(:product_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId);

  • // Выполняем запрос и возвращаем результатыDatabaseHandler::GetAll($sql, $params);

}

// Присваивает значение атрибута указанному товаруstatic function AssignAttributeValueToProduct($productId,

$attributeValueId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_assign_attribute_value_to_product(

:product_id, :attribute_value_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId,

‘:attribute_value_id’ => $attributeValueId);

  • // Выполняем запрос::Execute($sql, $params);

}

// Удаляет значение атрибута для товараstatic function RemoveProductAttributeValue($productId,

$attributeValueId)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_remove_product_attribute_value(

:product_id, :attribute_value_id)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId,

‘:attribute_value_id’ => $attributeValueId);

  • // Выполняем запрос::Execute($sql, $params);

}

// Изменяет имя файла изображения товара в базе данных

public static function SetImage($productId, $imageName)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_set_image(:product_id, :image_name)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId, ‘:image_name’ =>

  • $imageName);
  • // Выполняем запрос::Execute($sql, $params);

}

// Изменяет имя файла второго изображения товара в базе данных

public static function SetImage2($productId, $imageName)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_set_image_2(:product_id, :image_name)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId, ‘:image_name’ =>

  • $imageName);
  • // Выполняем запрос::Execute($sql, $params);

}

// Изменяет имя файла уменьшенного изображения товара в базе данных

public static function SetThumbnail($productId, $thumbnailName)

{

// Составляем SQL-запрос

$sql = ‘CALL catalog_set_thumbnail(:product_id, :thumbnail_name)’;

// Создаем массив параметров

$params = array (‘:product_id’ => $productId,

‘:thumbnail_name’ => $thumbnailName);

  • // Выполняем запрос::Execute($sql, $params);

}

}

?>

  • Файл departments_list.tpl

{* departments_list.tpl *}

{load_presentation_object filename=»departments_list» assign=»obj»}

{* Начало списка отделов *}

<divclass=»box»>

  • <p>
  • <ul>

{* Перебираем элементы списка отделов *}

{section name=i loop=$obj->mDepartments}

{assignvar=selectedvalue=»»}

{* Проверяем, выделен ли отдел, чтобы определить, какой

стиль CSS использовать *}

{if ($obj->mSelectedDepartment ==

$obj->mDepartments[i].department_id)}

{assign var=selected value=»class=\»selected\»»}

{/if}

<li>

{* Генерируем ссылку для нового отдела в списке *}

<a {$selected} href=»{$obj->mDepartments[i].link_to_department}»>

  • {$obj->mDepartments[i].name}

</a>

  • </li>

{/section}

</ul>

  • </div>

{* Конец списка отделов *}

Файл function.load_presentation_object.php

<?php

// Подключаемые функции из подключаемых файлов должны

// именоваться smarty_имя_типаsmarty_function_load_presentation_object($params, $smarty)

{_once PRESENTATION_DIR . $params[‘filename’] . ‘.php’;

  • $className = str_replace(‘ ‘, »,ucfirst(str_replace(‘_’, ‘ ‘, $params[‘filename’])));

// Создаем объект представления

$obj = new $className();

{

$obj->init();

}

// Присваиваемпеременнуюшаблона

$smarty->assign($params[‘assign’], $obj);

}

?>

  • Файлdepartments_list.php

<?php

// Управляет списком отделов

classDepartmentsList

{

/* Общественные переменные, доступные в departments_list.tpl шаблона Smarty*/

public $mSelectedDepartment = 0;$mDepartments;

// Constructor reads query string parameterfunction __construct()

{

/* ЕслиDepartmentIDсуществуетвстрокезапроса, мыпосещаем

отдел */(isset ($_GET[‘DepartmentId’]))

$this->mSelectedDepartment = (int)$_GET[‘DepartmentId’];(isset($_GET[‘ProductId’]) &&($_SESSION[‘link_to_continue_shopping’]))

{

$continue_shopping =::QueryStringToArray($_SESSION[‘link_to_continue_shopping’]);(array_key_exists(‘DepartmentId’, $continue_shopping))

$this->mSelectedDepartment =

(int)$continue_shopping[‘DepartmentId’];

}

}

/* Вызов метода бизнес-уровня, чтобы прочитать список отделов и создать свои ссылки */

public function init()

{

$this->mDepartments = Catalog::GetDepartments();

  • // Создаем ссылкина отдел($i = 0;
  • $i <
  • count($this->mDepartments);
  • $i++)

$this->mDepartments[$i][‘link_to_department’] =::ToDepartment($this->mDepartments[$i][‘department_id’]);

}

}

?>

  • Файл link.php

<?phpLink

{static function Build($link, $type = ‘http’)

{

$base = (($type == ‘http’ || USE_SSL == ‘no’) ? ‘http://’ : ‘https://’) .getenv(‘SERVER_NAME’);

  • // Если константа HTTP_SERVER_PORT определена и значение //отличается от используемого по умолчанию…

if (defined(‘HTTP_SERVER_PORT’) && HTTP_SERVER_PORT != ’80’ &&($base, ‘https’) === false)

{

// Добавляемномерпорта

$base .= ‘:’ . HTTP_SERVER_PORT;

}

$link = $base . VIRTUAL_LOCATION . $link;

  • // Escape-символы для htmlhtmlspecialchars($link, ENT_QUOTES);

}static function ToDepartment($departmentId, $page = 1)

{

$link = ‘index.php?DepartmentId=’ . $departmentId;($page > 1)

$link .= ‘&Page=’ . $page;self::Build($link);

}static function ToCategory($departmentId, $categoryId, $page = 1)

{

$link = ‘index.php?DepartmentId=’ . $departmentId .

‘&CategoryId=’ . $categoryId;

  • if ($page > 1)

$link .= ‘&Page=’ . $page;self::Build($link);//self::Build($link);

}static function ToProduct($productId)

{self::Build(‘index.php?ProductId=’ . $productId);

}static function ToIndex($page = 1)

{

$link = »;($page > 1)

$link .= ‘index.php?Page=’ . $page;self::Build($link);

}static function QueryStringToArray($queryString)

{

$result = array();($queryString != »)

{

$elements = explode(‘&’, $queryString);($elements as $key => $value)

{

$element = explode(‘=’, $value);

  • $result[urldecode($element[0])] =($element[1]) ? urldecode($element[1]) : »;

}

}

return $result;

}

// Создание ссылки на страницу поиска

public static function ToSearch()

{self::Build(‘index.php?Search’);

}

// Создание ссылки на страницу с результатами поиска

public static function ToSearchResults($searchString, $allWords,

$page = 1)

{

$link = ‘search-results/find’;(empty($searchString))

$link .= ‘/’;

  • $link .= ‘-‘ . self::CleanUrlText($searchString) . ‘/’;
  • $link .= ‘all-words-‘ . $allWords . ‘/’;($page >
  • 1)

$link .= ‘page-‘ . $page . ‘/’;::Build($link);

}

// ПеренаправлениеправильногоURLstatic function CheckRequest()

{

$proper_url = »;(isset ($_GET[‘Search’]) || isset($_GET[‘SearchResults’]) ||($_GET[‘AddProduct’]))

{;

}

// ПолучаемнадлежащееURLдлястраницкатегорий(isset ($_GET[‘DepartmentId’]) && isset ($_GET[‘CategoryId’]))

{(isset ($_GET[‘Page’]))

$proper_url = self::ToCategory($_GET[‘DepartmentId’],

$_GET[‘CategoryId’], $_GET[‘Page’]);

$proper_url = self::ToCategory($_GET[‘DepartmentId’],

$_GET[‘CategoryId’]);

}

// Получаем надлежащее URL

elseif (isset ($_GET[‘DepartmentId’]))

{(isset ($_GET[‘Page’]))

$proper_url = self::ToDepartment($_GET[‘DepartmentId’],

$_GET[‘Page’]);

  • $proper_url = self::ToDepartment($_GET[‘DepartmentId’]);

}

// Получаем надлежащее URL

elseif (isset ($_GET[‘ProductId’]))

{

$proper_url = self::ToProduct($_GET[‘ProductId’]);

}

// Получаем надлежащее URL домашней страницы

else

{(isset($_GET[‘Page’]))

$proper_url = self::ToIndex($_GET[‘Page’]);

  • $proper_url = self::ToIndex();

}

/* Удалить виртуальное место из запрашиваемого URL

так чтобы мы могли сравнить пути */

$requested_url = self::Build(str_replace(VIRTUAL_LOCATION, »,

$_SERVER[‘REQUEST_URI’]));(strstr($proper_url, ‘/-‘))

{

// Очистить выходной буфер

ob_clean();

// Загрузить страницу 404

include ‘404.php’;

// Очистить выходной буфер и остановить выполнение

flush();_flush();_end_clean();();

}($requested_url != $proper_url)

{_clean();(‘HTTP/1.1 301 Moved Permanently’);(‘Location: ‘ . $proper_url);();_flush();_end_clean();();

}

}

// Создает ссылку Add to Cartstatic function ToAddProduct($productId)

{self::Build(‘index.php?AddProduct=’ . $productId);

}

// Создает ссылку на страницу администрирования

public static function ToAdmin($params = »)

{

$link = ‘admin.php’;($params != »)

$link .= ‘?’ . $params;self::Build($link, ‘https’);

}

// Создает ссылку для выходаstatic function ToLogout()

{self::ToAdmin(‘Page=Logout’);

}

// Создание ссылки на страницу администрирования отделов

public static function ToDepartmentsAdmin()

{self::ToAdmin(‘Page=Departments’);

}

// Создает ссылку на страницу администрирования категорий

public static function ToDepartmentCategoriesAdmin($departmentId)

{

$link = ‘Page=Categories&DepartmentId=’ . $departmentId;self::ToAdmin($link);

}

// Создаем ссылку на страницу администрирования атрибутов

public static function ToAttributesAdmin()

{self::ToAdmin(‘Page=Attributes’);

}

// Создает ссылку на страницу администрирования значений атрибутов

public static function ToAttributeValuesAdmin($attributeId)

{

$link = ‘Page=AttributeValues&AttributeId=’ . $attributeId;self::ToAdmin($link);

}

// Создает ссылку на страницу администрирования товаров

public static function ToCategoryProductsAdmin($departmentId, $categoryId)

{

$link = ‘Page=Products&DepartmentId=’ . $departmentId .

‘&CategoryId=’ . $categoryId;::ToAdmin($link);

}

// Создает ссылку на страницу администрирования информации о товарах

public static function ToProductAdmin($departmentId, $categoryId,$productId)

{

$link = ‘Page=ProductDetails&DepartmentId=’ . $departmentId .

‘&CategoryId=’ . $categoryId . ‘&ProductId=’ . $productId;

  • ‘&CategoryId=’ . $categoryId . ‘&ProductId=’ . $productId;self::ToAdmin($link);

}

}

?>

  • Файл store_front.php

<?phpStoreFront

{$mSiteUrl;

// Определяем файл шаблона для содержимого страницы

public $mContentsCell = ‘first_page_contents.tpl’;

// Определяем файл шаблона для ячеек категорий

public $mCategoriesCell = ‘blank.tpl’;

  • // Заголовок страницы $mPageTitle;

// Ссылка PayPal для возврата в магазин

public $mPayPalContinueShoppingLink;

// Конструктор классаfunction __construct()

{

$this->mSiteUrl = Link::Build(»);

}

// Инициализируем объект представления

publicfunctioninit()

{

// Создаем ссылку для возврата в магазин в корзине покупателя PayPal

if (!isset ($_GET[‘AddProduct’]))

{

/* Сохраняем текущий запрос, необходимый для работы ссылки в paypal,возвращающей в магазин */

$_SESSION[‘paypal_continue_shopping’] =::Build(str_replace(VIRTUAL_LOCATION, »,

$_SERVER[‘REQUEST_URI’]));

  • $this->mPayPalContinueShoppingLink =

$_SESSION[‘paypal_continue_shopping’];

}

// ЕслинажатакнопкаAddtoCart, подготавливаемпеременные //PayPal

{

// Очищаем буфер вывода

ob_clean();

  • $product_id = 0;

// Получаем идентификатор товара, который добавляется в корзину

if (isset ($_GET[‘AddProduct’]))

$product_id = (int)$_GET[‘AddProduct’];_error(‘AddProduct not set’);

  • $selected_attribute_groups = array ();
  • $selected_attribute_values = array ();

// Получаем атрибуты выбранного товара, если таковые есть

foreach ($_POST as $key => $value)

{

// Если в массиве POST есть поля, начинающиеся с «attr_»

if (substr($key, 0, 5) == ‘attr_’)

{

// Получаем имя и значение выбранного атрибута

$selected_attribute_groups[] = substr($key, strlen(‘attr_’));

  • $selected_attribute_values[] = $_POST[$key];

}

}

// Получаем сведения о товаре

$product = Catalog::GetProductDetails($product_id);

// Генерируем URL для PayPal, чтобы добавить товар в корзину

$paypal_url = PAYPAL_URL . ‘?cmd=_cart&business=’ . PAYPAL_EMAIL .’&item_name=’ . rawurlencode($product[‘name’]);(count($selected_attribute_groups) > 0)

$paypal_url .= ‘&on0=’ . implode(‘/’, $selected_attribute_groups) .

‘&os0=’ . implode(‘/’, $selected_attribute_values);

  • $paypal_url .=’&amount=’ . ($product[‘discounted_price’] == 0 ?

$product[‘price’] : $product[‘discounted_price’]) .’&currency_code=’ . PAYPAL_CURRENCY_CODE . ‘&add=1′ .’&shopping_url=’ .($_SESSION[‘paypal_continue_shopping’]) .

‘&return=’ . rawurlencode(PAYPAL_RETURN_URL) .

‘&cancel_return=’ . rawurlencode(PAYPAL_CANCEL_RETURN_URL);

// Выполняем перенаправление на страницу корзины PayPal

header(‘HTTP/1.1 302 Found’);(‘Location: ‘ . $paypal_url);

// Очищаем выходной буфер и завершаем выполнение

flush();_flush();_end_clean();();

}

// Загружаем подробные сведения об отделе на страницу отдела

if (isset ($_GET[‘DepartmentId’]))

{

$this->mContentsCell = ‘department.tpl’;

  • $this->mCategoriesCell = ‘categories_list.tpl’;
  • }(isset($_GET[‘ProductId’]) &&($_SESSION[‘link_to_continue_shopping’]) &&($_SESSION[‘link_to_continue_shopping’], ‘DepartmentId’, 0)

!== false)

{

$this->mCategoriesCell = ‘categories_list.tpl’;

}

// Загружаем сведения о товаре на страницу товара

if (isset ($_GET[‘ProductId’]))

$this->mContentsCell = ‘product.tpl’;

// Загружаем страницу с результатами поиска, если выполнялся поиск

elseif (isset ($_GET[‘SearchResults’]))

$this->mContentsCell = ‘search_results.tpl’;

}

// Возвращает заголовок страницы

privatefunction _GetPageTitle()

{

$page_title = ‘Goodstore: ‘ .

‘Demo Product Catalog from Beginning PHP and MySQL E-Commerce’;(isset ($_GET[‘DepartmentId’]) && isset ($_GET[‘CategoryId’]))

{

$page_title = ‘Goodstore: ‘ .::GetDepartmentName($_GET[‘DepartmentId’]) . ‘ — ‘ .::GetCategoryName($_GET[‘CategoryId’]);(isset ($_GET[‘Page’]) && ((int)$_GET[‘Page’]) > 1)

$page_title .= ‘ — Page ‘ . ((int)$_GET[‘Page’]);

}(isset ($_GET[‘DepartmentId’]))

{

$page_title = ‘Goodstore: ‘ .::GetDepartmentName($_GET[‘DepartmentId’]);(isset ($_GET[‘Page’]) && ((int)$_GET[‘Page’]) > 1)

$page_title .= ‘ — Page ‘ . ((int)$_GET[‘Page’]);

}(isset ($_GET[‘ProductId’]))

{

$page_title = ‘Goodstore: ‘ .::GetProductName($_GET[‘ProductId’]);

}(isset ($_GET[‘SearchResults’]))

{

$page_title = ‘Goodstore: «‘;

  • $page_title .= trim(str_replace(‘-‘, ‘ ‘, $_GET[‘SearchString’])) . ‘» (‘;
  • $all_words = isset ($_GET[‘AllWords’]) ? $_GET[‘AllWords’] : ‘off’;
  • $page_title .= (($all_words == ‘on’) ? ‘all’ : ‘any’) .

‘-words search’;(isset ($_GET[‘Page’]) && ((int)$_GET[‘Page’]) > 1)

$page_title .= ‘, page ‘ . ((int)$_GET[‘Page’]);

  • $page_title .= ‘)’;

}

{(isset ($_GET[‘Page’]) && ((int)$_GET[‘Page’]) > 1)

$page_title .= ‘ — Page ‘ . ((int)$_GET[‘Page’]);

  • }$page_title;

}

}

?>

  • Файл blank.tpl

{* Smarty blank page *}

Файл department.tpl

{* department.tpl *}

{load_presentation_object filename=»department» assign=»obj»}

<h1>

  • <p>
  • {include file=»products_list.tpl»}

Файл department.php

<?php

// Занимается извлечением сведений об отделе

class Department

{

// Public-переменныедляшаблонов Smarty$mName;$mDescription;

  • // Private-элементы$_mDepartmentId;$_mCategoryId;

// Конструкторклассаfunction __construct()

{

// В строке запроса должен присутствовать параметр DepartmentId

if (isset ($_GET[‘DepartmentId’]))

$this->_mDepartmentId = (int)$_GET[‘DepartmentId’];_error(‘DepartmentId not set’);

/* Если CategoryId есть в строке запроса, мы сохраняем его значение(преобразуя его в integer для защиты от некорректных значений) */

if (isset ($_GET[‘CategoryId’]))

$this->_mCategoryId = (int)$_GET[‘CategoryId’];

}function init()

{

// Еслипосещаемотдел…

$department_details =::GetDepartmentDetails($this->_mDepartmentId);

  • $this->mName = $department_details[‘name’];
  • $this->mDescription = $department_details[‘description’];
  • // Еслипосещаемкатегорию…(isset ($this->_mCategoryId))

{

$category_details =::GetCategoryDetails($this->_mCategoryId);

  • $this->mName = $this->mName . ‘ &raquo;
  • ‘ .

$category_details[‘name’];

  • $this->mDescription = $category_details[‘description’];

}

}

}

?>

  • Файл categories_list.tpl

{* categories_list.tpl *}

{load_presentation_object filename=»categories_list» assign=»obj»}

{* Start categories list *}

<div>

  • <pclass=»box-title»>Выберите категорию товаров</p>
  • <ul>
  • {section name=i loop=$obj->mCategories}

{assign var=selected value=»»}

{if ($obj->mSelectedCategory == $obj->mCategories[i].category_id)}

{assign var=selected value=»class=\»selected\»»}

{/if}

<li>

  • <a {$selected} href=»{$obj->mCategories[i].link_to_category}»>
  • {$obj->mCategories[i].name}

</a>

  • </li>

{/section}

</ul>

  • </div>

{* End categories list *}

Файлcategories_list.php

<?php

classCategoriesList

{

// Public-переменные дл¤ шаблона smarty$mSelectedCategory = 0;$mSelectedDepartment = 0;$mCategories;

// Конструкторсчитываетпараметризстрокизапросаfunction __construct()

{(isset ($_GET[‘DepartmentId’]))

$this->mSelectedDepartment = (int)$_GET[‘DepartmentId’];_error(‘DepartmentId not set’);(isset ($_GET[‘CategoryId’]))

$this->mSelectedCategory = (int)$_GET[‘CategoryId’];

}function init()

{

$this->mCategories =::GetCategoriesInDepartment($this->mSelectedDepartment);

  • // Генерируем ссылки дл¤ страниц категорий($i = 0;
  • $i <
  • count($this->mCategories);
  • $i++)

$this->mCategories[$i][‘link_to_category’] =::ToCategory($this->mSelectedDepartment,

$this->mCategories[$i][‘category_id’]);

}

}

?>

  • Файл products_list.tpl

{* products_list.tpl *}

{load_presentation_object filename=»products_list» assign=»obj»}

{if $obj->mSearchDescription != «»}

<p>

{/if}

{if $obj->mrTotalPages > 1}

<p>{$obj->mPage} of {$obj->mrTotalPages}

{if $obj->mLinkToPreviousPage}

<a href=»{$obj->mLinkToPreviousPage}»>Previous</a>

{else}

{/if}

{if $obj->mLinkToNextPage}

<a href=»{$obj->mLinkToNextPage}»>Next</a>

{else}

{/if}

</p>

{/if}

{if $obj->mProducts}

<table>

  • <tbody>
  • {section name=k loop=$obj->mProducts}

{if $smarty.section.k.index % 2 == 0}

<tr>

{/if}

<td valign=»top»>

  • <h3>
  • <a href=»{$obj->mProducts[k].link_to_product}»>
  • {$obj->mProducts[k].name}

</a>

  • </h3>
  • <p>
  • {if $obj->mProducts[k].thumbnail neq «»}

<a href=»{$obj->mProducts[k].link_to_product}»>

  • <img src=»{$obj->mProducts[k].thumbnail}»=»{$obj->mProducts[k].name}» />
  • </a>

{/if}

{$obj->mProducts[k].description}

</p>

  • <p>

Цена:

  • {if $obj->mProducts[k].discounted_price != 0}

<span>

  • <span>

{else}

<span>

{/if}

</p>

{* Форма Add to Cart *}

<form>

{* Генерируем список значений атрибутов *}

<p>

{* Просматриваем список атрибутов и их значений *}

{section name=l loop=$obj->mProducts[k].attributes}

{* Генерируемновыйтег select? *}

{if $smarty.section.l.first ||

$obj->mProducts[k].attributes[l].attribute_name !==

$obj->mProducts[k].attributes[l.index_prev].attribute_name}

{$obj->mProducts[k].attributes[l].attribute_name}:

  • <select name=»attr_{$obj->mProducts[k].attributes[l].attribute_name}»>

{/if}

{* Генерируем новый тег option *}

<option value=»{$obj->mProducts[k].attributes[l].attribute_value}»>

  • {$obj->mProducts[k].attributes[l].attribute_value}

</option>

{* Закрываемтег select? *}

{if $smarty.section.l.last ||

$obj->mProducts[k].attributes[l].attribute_name !==

$obj->mProducts[k].attributes[l.index_next].attribute_name}

</select>

{/if}

{/section}

</p>

{* Добавляемкнопкудляотправкиформы *}

<p>

  • <input type=»submit» name=»submit» value=»Добавитьвкорзину» />
  • </p>
  • </form>
  • </td>
  • {if $smarty.section.k.index % 2 != 0 && !$smarty.section.k.first ||

$smarty.section.k.last}

</tr>

{/if}

{/section}

</tbody>

  • </table>

{/if}

Файл products_list.php

<?phpProductsList

{

// Public-переменные, доступныеизшаблонаSmarty$mPage = 1;$mrTotalPages;$mLinkToNextPage;$mLinkToPreviousPage;$mProducts;$mSearchDescription;$mAllWords = ‘off’;$mSearchString;

  • // Private-переменные$_mDepartmentId;$_mCategoryId;

// Конструкторклассаfunction __construct()

{

// Получаем DepartmentId из строки запроса и преобразуем его в int

if (isset ($_GET[‘DepartmentId’]))

$this->_mDepartmentId = (int)$_GET[‘DepartmentId’];

// Получаем CategoryId из строки запроса и преобразуем его в int

if (isset ($_GET[‘CategoryId’]))

$this->_mCategoryId = (int)$_GET[‘CategoryId’];

// Получаем номер страницы из строки запроса и преобразуем его в int

if (isset ($_GET[‘Page’]))

$this->mPage = (int)$_GET[‘Page’];($this->mPage < 1)_error(‘Incorrect Page value’);

// Сохраняемадресстраницы, посещеннойпоследней

$_SESSION[‘link_to_continue_shopping’] = $_SERVER[‘QUERY_STRING’];

// Получаем поисковую строку и параметр AllWords из строки запроса

if (isset ($_GET[‘SearchResults’]))

{

$this->mSearchString = trim(str_replace(‘-‘, ‘ ‘,

$_GET[‘SearchString’]));

  • $this->mAllWords = isset ($_GET[‘AllWords’]) ? $_GET[‘AllWords’] : ‘off’;

}

}()

{

/* Если выполнялся поиск, получаем список товаров, вызывая

метод уровня логики приложения Search() */

if (isset ($this->mSearchString))

{

// Получаемрезультатыпоиска

$search_results = Catalog::Search($this->mSearchString,

$this->mAllWords,

$this->mPage,

$this->mrTotalPages);

// Получаемсписоктоваров

$this->mProducts = $search_results[‘products’];

  • // Составляемзаголовокдляспискатоваров(count($search_results[‘accepted_words’]) > 0)

$this->mSearchDescription =

‘<p>

  • ($this->mAllWords == ‘on’ ? ‘all’ : ‘any’) . ‘</font>’
  • ‘ of these words: <font>
  • implode(‘, ‘, $search_results[‘accepted_words’]) .

‘</font></p>’;(count($search_results[‘ignored_words’]) > 0)

$this->mSearchDescription .=

‘<p>

  • implode(‘, ‘, $search_results[‘ignored_words’]) .

‘</font></p>’;(!(count($search_results[‘products’]) > 0))

$this->mSearchDescription .=

‘<p>

}

/* Если посетитель просматривает категорию, получаем список ее товаров,вызывая метод уровня логики приложения GetProductsInCategory() */

if (isset ($this->_mCategoryId))

$this->mProducts = Catalog::GetProductsInCategory(

$this->_mCategoryId, $this->mPage, $this->mrTotalPages);

/* Если посетитель просматривает отдел, получаем список его товаров,вызывая метод уровня логики приложения GetProductsOnDepartment() */

elseif (isset ($this->_mDepartmentId))

$this->mProducts = Catalog::GetProductsOnDepartment(

$this->_mDepartmentId, $this->mPage, $this->mrTotalPages); /* Еслипосетительпросматриваетпервуюстраницу, получаемсписоктоваров,вызываяметодуровнялогикиприложения GetProductsOnCatalog() */

$this->mProducts = Catalog::GetProductsOnCatalog(

$this->mPage, $this->mrTotalPages);

/* Если список товаров разбит на несколько страниц, отображаем

навигационные элементы управления */

if ($this->mrTotalPages> 1)

{

// Создаемссылку Next($this->mPage < $this->mrTotalPages)

{(isset($_GET[‘SearchResults’]))

$this->mLinkToNextPage =::ToSearchResults($this->mSearchString, $this->mAllWords,$this->mPage + 1);(isset($this->_mCategoryId))

$this->mLinkToNextPage =::ToCategory($this->_mDepartmentId, $this->_mCategoryId,$this->mPage + 1);(isset($this->_mDepartmentId))

$this->mLinkToNextPage =::ToDepartment($this->_mDepartmentId, $this->mPage + 1);

else

$this->mLinkToNextPage = Link::ToIndex($this->mPage + 1);

}

// Создаемссылку Previous($this->mPage > 1)

{

if (isset($_GET[‘SearchResults’]))

$this->mLinkToPreviousPage =::ToSearchResults($this->mSearchString, $this->mAllWords, $this->mPage — 1);(isset($this->_mCategoryId))

$this->mLinkToPreviousPage =::ToCategory($this->_mDepartmentId, $this->_mCategoryId,$this->mPage — 1);(isset($this->_mDepartmentId))

$this->mLinkToPreviousPage =::ToDepartment($this->_mDepartmentId, $this->mPage — 1);

else

$this->mLinkToPreviousPage = Link::ToIndex($this->mPage — 1);

  • }($this->mPage >
  • $this->mrTotalPages && !empty($this->mrTotalPages))

{_clean();’404.php’;();_flush();_end_clean();();

}

}

// Генерируемссылкинастраницытоваров($i = 0; $i < count($this->mProducts); $i++)

{

$this->mProducts[$i][‘link_to_product’] =::ToProduct($this->mProducts[$i][‘product_id’]);($this->mProducts[$i][‘thumbnail’])

$this->mProducts[$i][‘thumbnail’] =::Build(‘product_images/’ .

$this->mProducts[$i][‘thumbnail’]);

// Генерируемссылку Add to Cart

$this->mProducts[$i][‘link_to_add_product’] =::ToAddProduct($this->mProducts[$i][‘product_id’]);

  • $this->mProducts[$i][‘attributes’] =::GetProductAttributes($this->mProducts[$i][‘product_id’]);

}

}

}

?>

  • Файл first_page_contents.tpl

{* first_page_contents.tpl *}

<pclass=»description»>

Добро пожаловать на сайт магазина женской одежды GoodStore!

<pclass=»description»>

По всем интересующим Вас вопросам, а так же вопросам

доставки и оплаты обращаться по электронному адресу администратора:

goodstore.shop@yandex.ru или по телефону 8-938-444-68-12

</p>

  • </p>
  • <p>

Мы надеемся, вам понравится

наш ассортимент товаров!

Сейчас действуют скидки на зимние коллекции.

</p>

  • {include file=»products_list.tpl»}

{* first_page_contents.tpl *}

{load_presentation_object filename=»first_page_contents» assign=»obj»}

<p>

  • </p>
  • <p>
  • </p>
  • <p>Доступ <ahref=»{$obj->mLinkToAdmin}»>к странице администрирования</a>.</p>
  • Файлproduct.tpl

{load_presentation_object filename=»product» assign=»obj»}

<h1>

  • {if $obj->mProduct.image}

<img>

{/if}

{if $obj->mProduct.image_2}

<img>

{/if}

<p>

  • <p>

Цена:

  • {if $obj->mProduct.discounted_price != 0}

<span>

  • <span>

{else}

<span>

{/if}

</p>

{* Генерируем список значений атрибутов *}

<pclass=»attributes»>

{* Просматриваем список атрибутов и их значений *}

{section name=k loop=$obj->mProduct.attributes}

{* Генерируем новый тег select? *}

{if $smarty.section.k.first ||

$obj->mProduct.attributes[k].attribute_name !==

$obj->mProduct.attributes[k.index_prev].attribute_name}

{$obj->mProduct.attributes[k].attribute_name}:

  • <select name=»attr_{$obj->mProduct.attributes[k].attribute_name}»>

{/if}

{* Генерируем новый тег option *}

<option value=»{$obj->mProduct.attributes[k].attribute_value}»>

  • {$obj->mProduct.attributes[k].attribute_value}

</option>

{* Закрываем тег select? *}

{if $smarty.section.k.last ||

$obj->mProduct.attributes[k].attribute_name !==

$obj->mProduct.attributes[k.index_next].attribute_name}

</select>

{/if}

{/section}

</p>

{* Добавляем кнопку для отправки формы *}

<p>

  • <input type=»submit» name=»submit» value=»Добавить в корзину» />
  • </p>
  • </form>
  • {if $obj->mLinkToContinueShopping}

<a href=»{$obj->mLinkToContinueShopping}»>Продолжить покупки</a>

{/if}

{*<h2>Find similar products in our catalog:</h2>*}

<ol>

  • {section name=i loop=$obj->mLocations}

<li>

{strip}

<a href=»{$obj->mLocations[i].link_to_department}»>

  • {$obj->mLocations[i].department_name}

</a>

{/strip}

&raquo;

{strip}

<a href=»{$obj->mLocations[i].link_to_category}»>

  • {$obj->mLocations[i].category_name}

</a>

{/strip}

</li>

{/section}

</ol>

  • Файлproduct.php

<?php

// Отвечает за отображение подробных сведений о товаре

classProduct

{

// Public-переменные для использования в шаблоне Smarty

public $mProduct;$mProductLocations;$mLinkToContinueShopping;$mLocations;

  • // Private-переменная$_mProductId;

// Конструктор классаfunction __construct()

{

// Инициализация переменной(isset ($_GET[‘ProductId’]))

$this->_mProductId = (int)$_GET[‘ProductId’];_error(‘ProductId not set’);

}

publicfunctioninit()

{

// Получаем сведения о товаре из уровня логики приложения

$this->mProduct = Catalog::GetProductDetails($this->_mProductId);(isset ($_SESSION[‘link_to_continue_shopping’]))

{

$continue_shopping = Link::QueryStringToArray($_SESSION[‘link_to_continue_shopping’];

  • $page = 1;(isset ($continue_shopping[‘Page’]))

$page = (int)$continue_shopping[‘Page’];(isset ($continue_shopping[‘CategoryId’]))

$this->mLinkToContinueShopping = Link::ToCategory((int)$continue_shopping[‘DepartmentId’], (int)$continue_shopping[‘CategoryId’], $page);(isset ($continue_shopping[‘DepartmentId’]))

$this->mLinkToContinueShopping = Link::ToDepartment((int)$continue_shopping[‘DepartmentId’], $page);

elseif (isset ($continue_shopping[‘SearchResults’]))

$this->mLinkToContinueShopping =::ToSearchResults((str_replace(‘-‘, ‘ ‘,$continue_shopping[‘SearchString’])),

$continue_shopping[‘AllWords’], $page);

  • $this->mLinkToContinueShopping = Link::ToIndex($page);
  • }($this->mProduct[‘image’])

$this->mProduct[‘image’] =::Build(‘product_images/’ . $this->mProduct[‘image’]);($this->mProduct[‘image_2’])

$this->mProduct[‘image_2’] =::Build(‘product_images/’ . $this->mProduct[‘image_2’]);

  • $this->mProduct[‘attributes’] =::GetProductAttributes($this->mProduct[‘product_id’]);
  • $this->mLocations = Catalog::GetProductLocations($this->_mProductId);

// Генерируем ссылку Add to Cart

$this->mProduct[‘link_to_add_product’] =::ToAddProduct($this->_mProductId);

// Генерируем ссылки на страницы отдела и категории

for ($i = 0; $i < count($this->mLocations); $i++)

{

$this->mLocations[$i][‘link_to_department’] =::ToDepartment($this->mLocations[$i][‘department_id’]);

  • $this->mLocations[$i][‘link_to_category’] =::ToCategory($this->mLocations[$i][‘department_id’],

$this->mLocations[$i][‘category_id’]);

}

}

}

?>

  • Файлfirst_page_contents.php

<?phpFirstPageContents

{$mLinkToAdmin;function __construct()

{

$this->mLinkToAdmin = Link::ToAdmin();

}

}

?>

  • Файл admin.php

<?php

// Запускаем сеанс_start();

// Создаем буфер вывода

ob_start();

  • // Включаемвспомогательныефайлы_once ‘include/config.php’;_once BUSINESS_DIR . ‘error_handler.php’;
  • // Задаем обработчик ошибок::SetHandler();

// Загружаем дескриптор базы данных

require_once BUSINESS_DIR . ‘database_handler.php’;

  • // Загружаем код уровня логики приложения_once BUSINESS_DIR . ‘catalog.php’;

// Загружаем файл шаблона Smarty

$application = new Application();

// Отображаем страницу

$application->display(‘store_admin.tpl’);

// Закрываем соединение с базой данных

DatabaseHandler::Close();

// Выводим содержимое буфера

flush();

  • ob_flush();
  • ob_end_clean();
  • ?>
  • Файл store_admin.tpl

{load_presentation_object filename=»store_admin» assign=»obj»}

<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Transitional//EN»

«http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd»>

  • <html>
  • <head>
  • <title>Demo Store Admin from Beginning PHP and MySQL E-Commerce</title>
  • <meta http-equiv=»Content-Type» content=»text/html;
  • charset=UTF-8″ />
  • <link href=»{$obj->mSiteUrl}styles/goodstore.css» type=»text/css»=»stylesheet» />
  • </head>
  • <body>
  • <div id=»doc»>
  • <div id=»bd»>
  • <div>
  • {include file=$obj->mMenuCell}

</div>

  • <div>
  • {include file=$obj->mContentsCell}

</div>

  • </div>
  • </div>
  • </body>
  • </html>
  • Файл store_admin.php

<?phpStoreAdmin

{

public $mSiteUrl;

// Определяем файл шаблона для меню

public $mMenuCell = ‘blank.tpl’;

// Определяем файл шаблона для содержимого страницы

public $mContentsCell = ‘blank.tpl’;

// Конструктор классаfunction __construct()

{

$this->mSiteUrl = Link::Build(», ‘https’);

// Разрешаем доступ к этой странице только через HTTPS,

// если USE_SSL установлена в значение yes

if (USE_SSL == ‘yes’ && getenv(‘HTTPS’) != ‘on’)

{(‘Location: https://’ . getenv(‘SERVER_NAME’) .(‘REQUEST_URI’));();

}

}function init()

{

// Если аутентификация не выполнялась, загружаем шаблон admin_login

if (!(isset ($_SESSION[‘admin_logged’])) ||

$_SESSION[‘admin_logged’] != true)

$this->mContentsCell = ‘admin_login.tpl’;

{

// Если аутентификация проведена, загружаем

// меню страницы администрирования

$this->mMenuCell = ‘admin_menu.tpl’;

  • // При выходе…(isset ($_GET[‘Page’]) && ($_GET[‘Page’] == ‘Logout’))

{($_SESSION[‘admin_logged’]);(‘Location: ‘ . Link::ToAdmin());

  • exit();

}

// Если значение Page не задано явно, подразумеваем страницу Departments

$admin_page = isset ($_GET[‘Page’]) ? $_GET[‘Page’] : ‘Departments’;

  • // Выбираем, какую страницу администрирования загружать…

if ($admin_page == ‘Departments’)

$this->mContentsCell = ‘admin_departments.tpl’;($admin_page == ‘Categories’)

$this->mContentsCell = ‘admin_categories.tpl’;($admin_page == ‘Attributes’)

$this->mContentsCell = ‘admin_attributes.tpl’;($admin_page == ‘AttributeValues’)

$this->mContentsCell = ‘admin_attribute_values.tpl’;($admin_page == ‘Products’)

$this->mContentsCell = ‘admin_products.tpl’;($admin_page == ‘ProductDetails’)

$this->mContentsCell = ‘admin_product_details.tpl’;

}

}

}

?>

  • Файл admin_login.tpl

{* admin_login.tpl *}

{load_presentation_object filename=»admin_login» assign=»obj»}

<div>

  • <p>
  • <form method=»post» action=»{$obj->mLinkToAdmin}»>
  • <p>

Введите данные для входа или вернитесь назад

<a href=»{$obj->mLinkToIndex}»>в магазин</a>.

</p>

  • {if $obj->mLoginMessage neq «»}

<p>

{/if}

<p>

  • <label for=»username»>Логин:</label>
  • <input type=»text» name=»username» size=»35″ value=»{$obj->mUsername}» />
  • </p>
  • <p>
  • <label for=»password»>Пароль:</label>
  • <input type=»password» name=»password» size=»35″ value=»» />
  • </p>
  • <p>
  • <input type=»submit» name=»submit» value=»Войти» />
  • </p>
  • </form>
  • </div>
  • Файл admin_login.php

<?php

// Класс, отвечающий за аутентификацию администраторов

classAdminLogin

{

// Public-переменные, доступные в шаблонах Smarty

public $mUsername;$mLoginMessage = »;$mLinkToAdmin;$mLinkToIndex;

// Конструктор класса __construct()

{

// Проверяем правильность ввода идентификатора пользователя и пароля

if (isset ($_POST[‘submit’]))

{($_POST[‘username’] == ADMIN_USERNAME

&& $_POST[‘password’] == ADMIN_PASSWORD)

{

$_SESSION[‘admin_logged’] = true;(‘Location: ‘ . Link::ToAdmin());();

}

else

{

$this->mLoginMessage = ‘Войти не удалось, пожалуйста, попробуйте еще раз:’;

}

$this->mLinkToAdmin = Link::ToAdmin();

  • $this->mLinkToIndex = Link::ToIndex();

}

}

}

?>

  • Файлadmin_menu.tpl

{* admin_menu.tpl *}

{load_presentation_object filename=»admin_menu» assign=»obj»}

<h1>Администрирование Goodstore</h1>

  • <p>
  • |

<a href=»{$obj->mLinkToStoreAdmin}»>АДМИНИСТРИРОВАНИЕ КАТАЛОГА</a> |

<a href=»{$obj->mLinkToAttributesAdmin}»>АДМИНИСТРИРОВАНИЕ АТРИБУТОВ ТОВАРОВ</a> |

<a href=»{$obj->mLinkToStoreFront}»>ВИТРИНА</a> |

<a href=»{$obj->mLinkToLogout}»>ВЫЙТИ</a> |

</p>

  • Файлadmin_menu.php

<?phpAdminMenu

{$mLinkToStoreAdmin;$mLinkToAttributesAdmin;$mLinkToStoreFront;$mLinkToLogout;function __construct()

{

$this->mLinkToStoreAdmin = Link::ToAdmin();

  • $this->mLinkToAttributesAdmin = Link::ToAttributesAdmin();
  • $this->mLinkToStoreFront = Link::ToIndex();
  • $this->mLinkToLogout = Link::ToLogout();

}

}

?>

  • Файл admin_departments.tpl

{* admin_departments.tpl *}

{load_presentation_object filename=»admin_departments» assign=»obj»}

<form method=»post»=»{$obj->mLinkToDepartmentsAdmin}»>

  • <h3>Редактировать отделы Goodstore:</h3>
  • {if $obj->mErrorMessage}<p>
  • {if $obj->mDepartmentsCount eq 0}

<p>

{else}

<table>

  • <tr>
  • <thwidth=»200″>Название отдела</th>
  • <th>Описание отдела</th>
  • <th width=»240″>&nbsp;</th>
  • </tr>
  • {section name=i loop=$obj->mDepartments}

{if $obj->mEditItem == $obj->mDepartments[i].department_id}

<tr>

  • <td>
  • <input type=»text» name=»name»=»{$obj->mDepartments[i].name}» size=»30″ />
  • </td>
  • <td>

{strip}

<textarea name=»description» rows=»3″ cols=»60″>

  • {$obj->mDepartments[i].description}

</textarea>

{/strip}

</td>

  • <td>
  • <input type=»submit»=»submit_edit_cat_{$obj->mDepartments[i].department_id}»=»Редактировать категорию» />
  • <inputtype=»submit»

name=»submit_update_dept_{$obj->mDepartments[i].department_id}»=»Обновить» />

  • <input type=»submit» name=»cancel» value=»Отменить» />
  • <input type=»submit»=»submit_delete_dept_{$obj->mDepartments[i].department_id}»=»Удалить» />
  • </td>
  • </tr>

{else}

<tr>

  • <td>{$obj->mDepartments[i].name}</td>
  • <td>{$obj->mDepartments[i].description}</td>
  • <td>
  • <input type=»submit»=»submit_edit_cat_{$obj->mDepartments[i].department_id}»=»Редактировать категорию» />
  • <inputtype=»submit»

name=»submit_edit_dept_{$obj->mDepartments[i].department_id}»=»Редактировать отдел» />

  • <inputtype=»submit»

name=»submit_delete_dept_{$obj->mDepartments[i].department_id}»=»Удалить» />

  • </td>
  • </tr>

{/if}

{/section}

</table>

{/if}

<h3>Добавить новый отдел:</h3>

  • <p>
  • <input type=»text» name=»department_name» value=»[название]» size=»30″ />
  • <input type=»text» name=»department_description» value=»[описание]»=»60″ />
  • <input type=»submit» name=»submit_add_dept_0″ value=»Добавить» />
  • </p>
  • </form>
  • Файлadmin_departments.php

<?php

// Класс, обеспечивающий функциональность администрирования отделов

class AdminDepartments

{

// Public-переменные, доступные в шаблоне Smarty

public $mDepartmentsCount;$mDepartments;$mErrorMessage;$mEditItem;$mLinkToDepartmentsAdmin;

  • // Private-переменные$_mAction;$_mActionedDepartmentId;

// Конструктор класса __construct()

{

// Просматриваем список переданных переменных

foreach ($_POST as $key => $value)

// При щелчке на кнопке отправки…

if (substr($key, 0, 6) == ‘submit’)

{

/* Получаем позицию последнего символа ‘_’ из имени кнопки,

например, strrpos(‘submit_edit_dept_1’, ‘_’) вернет значение 17 */

$last_underscore = strrpos($key, ‘_’);

/* Получаем область действия из имени кнопки

(например, ‘edit_dep’ из ‘submit_edit_dept_1’) */

$this->_mAction = substr($key, strlen(‘submit_’),

$last_underscore — strlen(‘submit_’));

/* Получаем идентификатор отдела, к которому относится нажатая кнопка(цифру в конце имени кнопки),например, ‘1’ из ‘submit_edit_dept_1’ */

$this->_mActionedDepartmentId = substr($key, $last_underscore + 1);;

}

$this->mLinkToDepartmentsAdmin = Link::ToDepartmentsAdmin();

}

publicfunctioninit()

{

// При добавлении нового отдела…

if ($this->_mAction == ‘add_dept’)

{

$department_name = $_POST[‘department_name’];

  • $department_description = $_POST[‘department_description’];($department_name == null)

$this->mErrorMessage = ‘Department name required’;($this->mErrorMessage == null)

{::AddDepartment($department_name, $department_description);(‘Location: ‘ . $this->mLinkToDepartmentsAdmin);

}

}

// При редактировании существующего отдела…

if ($this->_mAction == ‘edit_dept’)

$this->mEditItem = $this->_mActionedDepartmentId;

  • // При обновлении отдела…($this->_mAction == ‘update_dept’)

{

$department_name = $_POST[‘name’];

  • $department_description = $_POST[‘description’];($department_name == null)

$this->mErrorMessage = ‘Department name required’;($this->mErrorMessage == null)

{::UpdateDepartment($this->_mActionedDepartmentId,

$department_name, $department_description);(‘Location: ‘ . $this->mLinkToDepartmentsAdmin);

}

}

// При удалении отдела…($this->_mAction == ‘delete_dept’)

{

$status = Catalog::DeleteDepartment($this->_mActionedDepartmentId);($status < 0)

$this->mErrorMessage = ‘Department not empty’;(‘Location: ‘ . $this->mLinkToDepartmentsAdmin);

}

// При редактировании категорий отдела…

if ($this->_mAction == ‘edit_cat’)

{(‘Location: ‘ ._decode(::ToDepartmentCategoriesAdmin(

$this->_mActionedDepartmentId)));();

}

// Загружаем список отделов

$this->mDepartments = Catalog::GetDepartmentsWithDescriptions();

  • $this->mDepartmentsCount = count($this->mDepartments);

}

}

?>

  • Файл admin_categories.tpl

{* admin_categories.tpl *}

{load_presentation_object filename=»admin_categories» assign=»obj»}

<form method=»post»=»{$obj->mLinkToDepartmentCategoriesAdmin}»>

  • <h3>
  • Редактирование категорий для отдела: {$obj->mDepartmentName} [

<a href=»{$obj->mLinkToDepartmentsAdmin}»>вернуться к отделам …</a>]

</h3>

  • {if $obj->mErrorMessage}<p>
  • {if $obj->mCategoriesCount eq 0}

<p>

{else}

<table>

  • <tr>
  • <thwidth=»200″>Название категории</th>
  • <th>Описание категории</th>
  • <th width=»240″>&nbsp;</th>
  • </tr>
  • {section name=i loop=$obj->mCategories}

{if $obj->mEditItem == $obj->mCategories[i].category_id}

<tr>

  • <td>
  • <input type=»text» name=»name»=»{$obj->mCategories[i].name}» size=»30″ />
  • </td>
  • <td>

{strip}

<textarea name=»description» rows=»3″ cols=»60″>

  • {$obj->mCategories[i].description}

</textarea>

{/strip}

</td>

  • <td>
  • <input type=»submit»=»submit_edit_prod_{$obj->mCategories[i].category_id}»=»Редактировать продукт» />
  • <inputtype=»submit»

name=»submit_update_cat_{$obj->mCategories[i].category_id}»=»Обновить» />

  • <input type=»submit» name=»cancel» value=»Отменить» />
  • <input type=»submit»=»submit_delete_cat_{$obj->mCategories[i].category_id}»=»Удалить» />
  • </td>
  • </tr>

{else}

<tr>

  • <td>{$obj->mCategories[i].name}</td>
  • <td>{$obj->mCategories[i].description}</td>
  • <td>
  • <input type=»submit»=»submit_edit_cat_{$obj->mCategories[i].category_id}»=»Редактировать» />
  • <input type=»submit»=»submit_edit_prod_{$obj->mCategories[i].category_id}»=»Редактировать продукт» />
  • <inputtype=»submit»

name=»submit_delete_cat_{$obj->mCategories[i].category_id}»=»Удалить» />

  • </td>
  • </tr>

{/if}

{/section}

</table>

{/if}

<h3>Добавить новую категорию:</h3>

  • <input type=»text» name=»category_name» value=»[название]» size=»30″ />
  • <input type=»text» name=»category_description» value=»[описание]»=»60″ >
  • <input type=»submit» name=»submit_add_cat_0″ value=»Добавить» />
  • </form>
  • Файл admin_categories.php

<?php

// Класс, обеспечивающий администрирование категорий

classAdminCategories

{

// Public-переменные, доступные в шаблоне Smarty

public $mCategoriesCount;$mCategories;$mErrorMessage;$mEditItem;$mDepartmentId;$mDepartmentName;$mLinkToDepartmentsAdmin;$mLinkToDepartmentCategoriesAdmin;

  • // Private-переменные$_mAction;$_mActionedCategoryId;

// Конструктор классаfunction __construct()

{(isset ($_GET[‘DepartmentId’]))

$this->mDepartmentId = (int)$_GET[‘DepartmentId’];_error(‘DepartmentId not set’);

$department_details = Catalog::GetDepartmentDetails(

$this->mDepartmentName = $department_details[‘name’];($_POST as $key => $value)

// При щелчке на кнопке…(substr($key, 0, 6) == ‘submit’)

{

/* Получаем позицию последнего символа ‘_’ из имени нажатой

кнопки, например e.g strrpos(‘submit_edit_cat_1’, ‘_’) is 16 */

$last_underscore = strrpos($key, ‘_’);

/* Узнаем тип нажатой кнопки

(например, ‘edit_cat’ из ‘submit_edit_cat_1’) */

$this->_mAction = substr($key, strlen(‘submit_’),

$last_underscore — strlen(‘submit_’));

/* Получаем идентификатор категории, для которой нажата кнопка

(номер в конце имени нажатой кнопки),

например, ‘1’ из ‘submit_edit_cat_1’ */

$this->_mActionedCategoryId = (int)substr($key, $last_underscore + 1);;

}

$this->mLinkToDepartmentsAdmin = Link::ToDepartmentsAdmin();

  • $this->mLinkToDepartmentCategoriesAdmin =::ToDepartmentCategoriesAdmin($this->mDepartmentId);

}

publicfunctioninit()

{

// При добавлении новой категории…

if ($this->_mAction == ‘add_cat’)

{

$category_name = $_POST[‘category_name’];

  • $category_description = $_POST[‘category_description’];($category_name == null)

$this->mErrorMessage = ‘Category name is empty’;($this->mErrorMessage == null)

{::AddCategory($this->mDepartmentId, $category_name,

$category_description);(‘Location: ‘ ._decode(

$this->mLinkToDepartmentCategoriesAdmin));

}

}

// При редактировании существующей категории…($this->_mAction == ‘edit_cat’)

{

$this->mEditItem = $this->_mActionedCategoryId;

}

// При обновлении категории…($this->_mAction == ‘update_cat’)

{

$category_name = $_POST[‘name’];

  • $category_description = $_POST[‘description’];($category_name == null)

$this->mErrorMessage = ‘Category name is empty’;($this->mErrorMessage == null)

{::UpdateCategory($this->_mActionedCategoryId, $category_name,$category_description);(‘Location: ‘ .html specialchars_decode(

$this->mLinkToDepartmentCategoriesAdmin));

}

}

// При удалении категории…($this->_mAction == ‘delete_cat’)

{

$status = Catalog::DeleteCategory($this->_mActionedCategoryId);($status < 0)

$this->mErrorMessage = ‘Category not empty’;(‘Location: ‘ ._decode(

$this->mLinkToDepartmentCategoriesAdmin));

}

// При редактировании товаров из категории …

if ($this->_mAction == ‘edit_prod’)

{(‘Location: ‘ ._decode(::ToCategoryProductsAdmin($this->mDepartmentId,

$this->_mActionedCategoryId)));();

}

// Загружаем список категорий

$this->mCategories =::GetDepartmentCategories($this->mDepartmentId);

  • $this->mCategoriesCount = count($this->mCategories);

}

}

?>

  • Файлadmin_attributes.tpl

{* admin_attributes.tpl *}

{load_presentation_object filename=»admin_attributes» assign=»obj»}

<form method=»post»=»{$obj->mLinkToAttributesAdmin}»>

  • <h3>Редактирование атрибутов продуктов Goodstore:</h3>
  • {if $obj->mErrorMessage}<p>
  • {if $obj->mAttributesCount eq 0}

<p>

Нет продуктов с атрибутами в базе данных!

</p>

{else}

<table>

  • <tr>
  • <th>Название атрибута</th>
  • <th width=»240″>&nbsp;</th>
  • </tr>
  • {section name=i loop=$obj->mAttributes}

{if $obj->mEditItem == $obj->mAttributes[i].attribute_id}

<tr>

  • <td>
  • <input type=»text» name=»name»=»{$obj->mAttributes[i].name}» size=»30″ />
  • </td>
  • <td>
  • <input type=»submit»=»submit_edit_attr_val_{$obj->mAttributes[i].attribute_id}»

value=»Редактировать значение атрибута» />

  • <input type=»submit»

name=»submit_update_attr_{$obj->mAttributes[i].attribute_id}»=»Обновить» />

  • <input type=»submit» name=»cancel» value=»Отменить» />
  • <input type=»submit»=»submit_delete_attr_{$obj->mAttributes[i].attribute_id}»=»Удалить» />
  • </td>
  • </tr>

{else}

<tr>

  • <td>{$obj->mAttributes[i].name}</td>
  • <td>
  • <input type=»submit»=»submit_edit_attr_{$obj->mAttributes[i].attribute_id}»=»Редактироватьатрибут» />
  • <input type=»submit»=»submit_edit_val_{$obj->mAttributes[i].attribute_id}»

value=»Редактировать значение атрибута» />

  • <input type=»submit»

name=»submit_delete_attr_{$obj->mAttributes[i].attribute_id}»=»Удалить» />

  • </td>
  • </tr>

{/if}

{/section}

</table>

{/if}

<h3>Добавитьновыйатрибут:</h3>

  • <p>
  • <input type=»text» name=»attribute_name» value=»[название]» size=»30″ />
  • <input type=»submit» name=»submit_add_attr_0″ value=»Добавить» />
  • </p>
  • </form>
  • Файл admin_attributes.php

<?php

// Класс, обеспечивающий администрирование атрибутов

classAdminAttributes

{

// Public-переменные, доступные в шаблоне Smarty

public $mAttributesCount;$mAttributes;$mErrorMessage;$mEditItem;$mLinkToAttributesAdmin;

  • // Private-переменные$_mAction;$_mActionedAttributeId;

// Конструктор класса __construct()

{

// Просматриваем список переданных переменных

foreach ($_POST as $key => $value)

// Если нажата кнопка отправки…

if (substr($key, 0, 6) == ‘submit’)

{

/* Получаем позицию последнего символа ‘_’ из имени кнопки,

например, strrpos(‘submit_edit_attr_1’, ‘_’) вернет значение 17 */

$last_underscore = strrpos($key, ‘_’);

/* Получаем область действия кнопки

(например, ‘edit_attr’ из ‘submit_edit_attr_1’) */

$this->_mAction = substr($key, strlen(‘submit_’),

$last_underscore — strlen(‘submit_’));

/* Получаем идентификатор атрибута, к которому относится кнопка

(номер в конце имени этой кнопки), например,

‘1’ из ‘submit_edit_attr_1’ */

$this->_mActionedAttributeId = substr($key, $last_underscore + 1);;

}

$this->mLinkToAttributesAdmin = Link::ToAttributesAdmin();

}

publicfunctioninit()

{

// При добавлении нового атрибута…

if ($this->_mAction == ‘add_attr’)

{

$attribute_name = $_POST[‘attribute_name’];($attribute_name == null)

$this->mErrorMessage = ‘Attribute name required’;($this->mErrorMessage == null)

{::AddAttribute($attribute_name);(‘Location: ‘ . $this->mLinkToAttributesAdmin);

}

}

// При редактировании существующего атрибута…

if ($this->_mAction == ‘edit_attr’)

$this->mEditItem = $this->_mActionedAttributeId;

  • // При обновлении атрибута…($this->_mAction == ‘update_attr’)

{

$attribute_name = $_POST[‘name’];($attribute_name == null)

$this->mErrorMessage = ‘Attribute name required’;($this->mErrorMessage == null)

{::UpdateAttribute($this->_mActionedAttributeId,

$attribute_name);(‘Location: ‘ . $this->mLinkToAttributesAdmin);

}

}

// При удалении атрибута…($this->_mAction == ‘delete_attr’)

{

$status = Catalog::DeleteAttribute($this->_mActionedAttributeId);($status < 0)

$this->mErrorMessage =

‘Attribute has one or more values and cannot be deleted’;(‘Location: ‘ . $this->mLinkToAttributesAdmin);

}

// При редактировании значений атрибута…

if ($this->_mAction == ‘edit_val’)

{(‘Location: ‘ ._decode(::ToAttributeValuesAdmin(

$this->_mActionedAttributeId)));();

}

// Загружаем список атрибутов

$this->mAttributes = Catalog::GetAttributes();

  • $this->mAttributesCount = count($this->mAttributes);

}

}

?>

  • Файл admin_attribute_values.tpl

{* admin_attribute_values.tpl *}

{load_presentation_object filename=»admin_attribute_values» assign=»obj»}

<form method=»post»=»{$obj->mLinkToAttributeValuesAdmin}»>

  • <h3>
  • Редактирование значений атрибутов: {$obj->mAttributeName} [

<ahref=»{$obj->mLinkToAttributesAdmin}»>вернуться к атрибутам …</a> ]

</h3>

  • {if $obj->mErrorMessage}<p>
  • {if $obj->mAttributeValuesCount eq 0}

<p>

{else}

<table>

  • <tr>
  • <th>Значение атрибута</th>
  • <th width=»170″>&nbsp;</th>
  • </tr>
  • {section name=i loop=$obj->mAttributeValues}

{if $obj->mEditItem == $obj->mAttributeValues[i].attribute_value_id}

<tr>

  • <td>
  • <input type=»text» name=»value»=»{$obj->mAttributeValues[i].value}» size=»30″ />
  • </td>
  • <td>
  • <input type=»submit»=»submit_update_val_{$obj->mAttributeValues[i].attribute_value_id}» value=»Обновить» />
  • <input type=»submit» name=»cancel» value=»Отменить» />
  • <input type=»submit» name=»submit_delete_val_{$obj->mAttributeValues[i].attribute_value_id}» value=»Удалить» />
  • </td>
  • </tr>

{else}

<tr>

  • <td>{$obj->mAttributeValues[i].value}</td>
  • <td>
  • <input type=»submit» name=»submit_edit_val_{$obj->mAttributeValues[i].attribute_value_id}» value=»Редактировать» />
  • <input type=»submit» name=»submit_delete_val_{$obj->mAttributeValues[i].attribute_value_id}» value=»Удалить» />
  • </td>
  • </tr>

{/if}

{/section}

</table>

{/if}

<h3>Добавить новое значение атрибута:</h3>

  • <input type=»text» name=»attribute_value» value=»[значение]» size=»30″ />
  • <input type=»submit» name=»submit_add_val_0″ value=»Добавить» />
  • </form>
  • Файл admin_attribute_values.php

<?php

// Класс, обеспечивающий администрирование значений атрибутов

class AdminAttributeValues

{

// Public-переменные, доступные в шаблоне Smarty$mAttributeValuesCount;$mAttributeValues;$mErrorMessage;$mEditItem;$mAttributeId;$mAttributeName;$mLinkToAttributeAdmin;$mLinkToAttributeValuesAdmin;

  • // Private-переменные$_mAction;$_mActionedAttributeValueId;

// Конструктор классаfunction __construct()

{(isset ($_GET[‘AttributeId’]))

$this->mAttributeId = (int)$_GET[‘AttributeId’];_error(‘AttributeId not set’);

$attribute_details = Catalog::GetAttributeDetails

($this->mAttributeId);

  • $this->mAttributeName = $attribute_details[‘name’];($_POST as $key =>
  • $value)

// Если нажата кнопка отправки…

if (substr($key, 0, 6) == ‘submit’)

{

/* Получаем позицию последнего символа ‘_’ из имени кнопки,например, strrpos(‘submit_edit_val_1’, ‘_’) вернет значение 16*/

$last_underscore = strrpos($key, ‘_’);

/* Получаем область действия кнопки

(например, ‘edit_cat’ from ‘submit_edit_val_1’) */

$this->_mAction = substr($key, strlen(‘submit_’),

$last_underscore — strlen(‘submit_’));

/* Получаем идентификатор значения атрибута, к которому

относилась нажатая кнопка (номер в конце имени кнопки),

например, ‘1’ из ‘submit_edit_val_1’ */

$this->_mActionedAttributeValueId =

(int)substr($key, $last_underscore + 1);;

}

$this->mLinkToAttributesAdmin = Link::ToAttributesAdmin();

  • $this->mLinkToAttributeValuesAdmin =::ToAttributeValuesAdmin($this->mAttributeId);

}

publicfunctioninit()

{

// При добавлении нового значения атрибута…

if ($this->_mAction == ‘add_val’)

{

$attribute_value = $_POST[‘attribute_value’];($attribute_value == null)

$this->mErrorMessage = ‘Attribute value is empty’;($this->mErrorMessage == null)

{::AddAttributeValue($this->mAttributeId, $attribute_value);(‘Location: ‘ ._decode(

$this->mLinkToAttributeValuesAdmin));

}

}

// При редактировании существующего значения атрибута…

if ($this->_mAction == ‘edit_val’)

{

$this->mEditItem = $this->_mActionedAttributeValueId;

}

// При обновлении значения атрибута…($this->_mAction == ‘update_val’)

{

$attribute_value = $_POST[‘value’];($attribute_value == null)

$this->mErrorMessage = ‘Attribute value is empty’;($this->mErrorMessage == null)

{::UpdateAttributeValue(

$this->_mActionedAttributeValueId, $attribute_value);(‘Location: ‘ ._decode(

$this->mLinkToAttributeValuesAdmin));

}

}

// При удалении значения атрибута…($this->_mAction == ‘delete_val’)

{

$status =::DeleteAttributeValue($this->_mActionedAttributeValueId);($status < 0)

$this->mErrorMessage = ‘Cannot delete this attribute value. ‘ .’One or more products are using it!’;(‘Location: ‘ ._decode(

$this->mLinkToAttributeValuesAdmin));

}

// Загружаем список значений атрибута

$this->mAttributeValues =::GetAttributeValues($this->mAttributeId);

  • $this->mAttributeValuesCount = count($this->mAttributeValues);

}

}

?>

  • Файлadmin_products.tpl

{* admin_products.tpl *}

{load_presentation_object filename=»admin_products» assign=»obj»}

<form method=»post»=»{$obj->mLinkToCategoryProductsAdmin}»>

  • <h3>
  • Редактирование продуктов: {$obj->mCategoryName} [

<a href=»{$obj->mLinkToDepartmentCategoriesAdmin}»>

  • вернутьсяккатегориям …</a>
  • ]

</h3>

  • {if $obj->mErrorMessage}<p>
  • {if $obj->mProductsCount eq 0}

<p>Нетпродуктоввэтойкатегории!</p>

{else}

<table>

  • <tr>
  • <th>Название</th>
  • <th>Описание</th>
  • <th>Цена</th>
  • <th>Скидка</th>
  • <th width=»80″>&nbsp;</th>
  • </tr>
  • {section name=i loop=$obj->mProducts}

<tr>

  • <td>{$obj->mProducts[i].name}</td>
  • <td>{$obj->mProducts[i].description}</td>
  • <td>{$obj->mProducts[i].price}</td>
  • <td>{$obj->mProducts[i].discounted_price}</td>
  • <td>
  • <input type=»submit»=»submit_edit_prod_{$obj->mProducts[i].product_id}»=»Редактировать» />
  • </td>
  • </tr>

{/section}

</table>

{/if}

<h3>Добавить новый продукт:</h3>

  • <input type=»text» name=»product_name» value=»[название]» size=»30″ />
  • <input type=»text» name=»product_description» value=»[описание]»=»60″ />
  • <input type=»text» name=»product_price» value=»[цена]» size=»10″ />
  • <input type=»submit» name=»submit_add_prod_0″ value=»Добавить» />
  • </form>
  • Файлadmin_products.php

<?php

// Класс, отвечающий за администрирование товаров категории

classAdminProducts

{

// Public-переменные, доступные в шаблоне Smarty

public $mProductsCount;$mProducts;$mErrorMessage;$mDepartmentId;$mCategoryId;$mCategoryName;$mLinkToDepartmentCategoriesAdmin;$mLinkToCategoryProductsAdmin;

  • // Private-переменные$_mAction;$_mActionedProductId;

// Конструктор классаfunction __construct()

{(isset ($_GET[‘DepartmentId’]))

$this->mDepartmentId = (int)$_GET[‘DepartmentId’];_error(‘DepartmentId not set’);(isset ($_GET[‘CategoryId’]))

$this->mCategoryId = (int)$_GET[‘CategoryId’];_error(‘CategoryId not set’);

  • $category_details = Catalog::GetCategoryDetails($this->mCategoryId);
  • $this->mCategoryName = $category_details[‘name’];($_POST as $key =>
  • $value)

// Если нажата кнопка отправки…

if (substr($key, 0, 6) == ‘submit’)

{

например, strrpos(‘submit_edit_prod_1’, ‘_’) вернет значение 17 */

$last_underscore = strrpos($key, ‘_’);

/* Получаем область действия кнопки

(например, ‘edit_prod’ из ‘submit_edit_prod_1’) */

$this->_mAction = substr($key, strlen(‘submit_’),

$last_underscore — strlen(‘submit_’));

/* Получаем идентификатор атрибута, к которому относится кнопка

(номер в конце имени этой кнопки), например,

‘1’ из ‘submit_edit_prod_1’ */

$this->_mActionedProductId = (int)substr($key, $last_underscore + 1);;

}

$this->mLinkToDepartmentCategoriesAdmin =::ToDepartmentCategoriesAdmin($this->mDepartmentId);

  • $this->mLinkToCategoryProductsAdmin =::ToCategoryProductsAdmin($this->mDepartmentId,

$this->mCategoryId);

}function init()

{

// При добавлении нового товара…

if ($this->_mAction == ‘add_prod’)

{

$product_name = $_POST[‘product_name’];

  • $product_description = $_POST[‘product_description’];
  • $product_price = $_POST[‘product_price’];($product_name == null)

$this->mErrorMessage = ‘Product name is empty’;($product_description == null)

$this->mErrorMessage = ‘Product description is empty’;($product_price == null || !is_numeric($product_price))

$this->mErrorMessage = ‘Product price must be a number!’;($this->mErrorMessage == null)

{::AddProductToCategory($this->mCategoryId, $product_name,

$product_description, $product_price);(‘Location: ‘ .html specialchars_decode(

$this->mLinkToCategoryProductsAdmin));

}

}

// Еслимыхотимпросмотретьсведенияотоваре($this->_mAction == ‘edit_prod’)

{(‘Location: ‘ ._decode(::ToProductAdmin($this->mDepartmentId,

$this->mCategoryId,

$this->_mActionedProductId)));();

}

$this->mProducts = Catalog::GetCategoryProducts($this->mCategoryId);

  • $this->mProductsCount = count($this->mProducts);

}

}

?>

  • Файлadmin_product_details.tpl

{* admin_product_details.tpl *}

{load_presentation_object filename=»admin_product_details» assign=»obj»}

<form enctype=»multipart/form-data» method=»post»=»{$obj->mLinkToProductDetailsAdmin}»>

  • <h3>
  • Редактирование товара: ID #{$obj->mProduct.product_id} &mdash;
  • {$obj->mProduct.name} [

<a href=»{$obj->mLinkToCategoryProductsAdmin}»>

  • вернуться к товарам …</a>
  • ]

</h3>

  • {if $obj->mErrorMessage}<p>
  • <table>
  • <tbody>
  • <tr>
  • <td valign=»top»>
  • <p>

Название товара:

  • </p>
  • <p>
  • <input type=»text» name=»name»=»{$obj->mProduct.name}» size=»30″ />
  • </p>
  • <p>

Описание товара:

  • </p>
  • <p>

{strip}

<textarea name=»description» rows=»3″ cols=»60″>

  • {$obj->mProduct.description}

</textarea>

{/strip}

</p>

  • <p>

Цена:

  • </p>
  • <p>
  • <input type=»text» name=»price»=»{$obj->mProduct.price}» size=»5″ />
  • </p>
  • <p>

Скидка:

  • </p>
  • <p>
  • <input type=»text» name=»discounted_price»=»{$obj->mProduct.discounted_price}» size=»5″ />
  • </p>
  • <p>
  • <input type=»submit» name=»UpdateProductInfo»=»Обновить» />
  • </p>
  • </td>
  • <td valign=»top»>
  • <p>
  • <fontclass=»bold-text»>Товар относится к категории:</font>
  • {$obj->mProductCategoriesString}

</p>

  • <p>

Удалить этот товар:

  • </p>
  • <p>
  • {html_options name=»TargetCategoryIdRemove»=$obj->mRemoveFromCategories}

<input type=»submit» name=»RemoveFromCategory» value=»Удалить»

{if $obj->mRemoveFromCategoryButtonDisabled}=»disabled» {/if}/>

  • </p>
  • <p>

Отправить товар в эту категорию:

  • </p>
  • <p>
  • {html_options name=»TargetCategoryIdAssign»=$obj->mAssignOrMoveTo}

<input type=»submit» name=»Assign» value=»Отправить» />

  • </p>
  • <p>

Переместить товар этой категории:

  • </p>
  • <p>
  • {html_options name=»TargetCategoryIdMove»=$obj->mAssignOrMoveTo}

<input type=»submit» name=»Move» value=»Переместить» />

  • <input type=»submit» name=»RemoveFromCatalog»=»Удалить товар из каталога»

{if !$obj->mRemoveFromCategoryButtonDisabled}=»disabled» {/if}/>

  • </p>
  • {if $obj->mProductAttributes}

<p>

Атрибуты товара:

  • </p>
  • <p>
  • {html_options name=»TargetAttributeValueIdRemove»=$obj->mProductAttributes}

<input type=»submit» name=»RemoveAttributeValue»=»Удалить» />

  • </p>

{/if}

{if $obj->mCatalogAttributes}

<pclass=»bold-text»>

Связать атрибут товара:

  • </p>
  • <p>
  • {html_options name=»TargetAttributeValueIdAssign»=$obj->mCatalogAttributes}

<input type=»submit» name=»AssignAttributeValue»=»Связать» />

  • </p>

{/if}

<p>

Установить параметр отображения для данного товара:

  • </p>
  • <p>
  • {html_options name=»ProductDisplay»=$obj->mProductDisplayOptions=$obj->mProduct.display}

<input type=»submit» name=»SetProductDisplayOption» value=»Установить» />

  • </p>
  • </td>
  • </tr>
  • </tbody>
  • </table>
  • <p>
  • <font>
  • <input name=»ImageUpload» type=»file» value=»Загрузить» />
  • <input type=»submit» name=»Upload» value=»Загрузить» />
  • </p>
  • {if $obj->mProduct.image}

<p>

  • <img src=»product_images/{$obj->mProduct.image}»=»0″ alt=»{$obj->mProduct.name} image» />
  • </p>

{/if}

<p>

  • <font>
  • <input name=»Image2Upload» type=»file» value=»Загрузить» />
  • <input type=»submit» name=»Upload» value=»Загрузить» />
  • </p>
  • {if $obj->mProduct.image_2}

<p>

  • <img src=»product_images/{$obj->mProduct.image_2}»=»0″ alt=»{$obj->mProduct.name} image 2″ />
  • </p>

{/if}

<p>

  • <font>
  • $obj->mProduct.thumbnail}

<input name=»ThumbnailUpload» type=»file» value=»Загрузить» />

  • <input type=»submit» name=»Upload» value=»Загрузить» />
  • </p>
  • {if $obj->mProduct.thumbnail}

<p>

  • <img src=»product_images/{$obj->mProduct.thumbnail}»=»0″ alt=»{$obj->mProduct.name} thumbnail» />
  • </p>

{/if}

</form>

  • Файлadmin_product_details.php

<?php

// Класс, отвечающий за администрирование сведений о товарах

class AdminProductDetails

{

// Public-элементы$mProduct;$mErrorMessage;$mProductCategoriesString;$mProductDisplayOptions;$mProductAttributes;$mCatalogAttributes;$mAssignOrMoveTo;$mRemoveFromCategories;$mRemoveFromCategoryButtonDisabled = false;$mLinkToCategoryProductsAdmin;$mLinkToProductDetailsAdmin;

  • // Private-элементы$_mProductId;$_mCategoryId;$_mDepartmentId;

// Конструктор классаfunction __construct()

{

// В строке запроса должен присутствовать DepartmentId

if (!isset ($_GET[‘DepartmentId’]))_error(‘DepartmentId not set’);

  • $this->_mDepartmentId = (int)$_GET[‘DepartmentId’];

// В строке запроса должен присутствовать CategoryId

if (!isset ($_GET[‘CategoryId’]))_error(‘CategoryId not set’);

  • $this->_mCategoryId = (int)$_GET[‘CategoryId’];

// В строке запроса должен присутствовать ProductId

if (!isset ($_GET[‘ProductId’]))_error(‘ProductId not set’);

  • $this->_mProductId = (int)$_GET[‘ProductId’];
  • $this->mProductDisplayOptions = Catalog::$mProductDisplayOptions;
  • $this->mLinkToCategoryProductsAdmin =::ToCategoryProductsAdmin($this->_mDepartmentId,

$this->_mCategoryId);

  • $this->mLinkToProductDetailsAdmin =Link::ToProductAdmin

($this->_mDepartmentId,

$this->_mCategoryId,

$this->_mProductId);

}function init()

{

// При загрузке изображения товара…

if (isset ($_POST[‘Upload’]))

{

/* Проверяем, есть ли доступ на запись в папку product_images */

if (!is_writeable(SITE_ROOT . ‘/product_images/’))

{«Can’t write to the product_images folder»;();

}

// Если код ошибки — 0, файл успешно загружен

if ($_FILES[‘ImageUpload’][‘error’] == 0)

{

/* ИспользуемфункциюPHPmove_uploaded_fileдляперемещения

загруженного файла из временной папки в папку product_images */

move_uploaded_file($_FILES[‘ImageUpload’][‘tmp_name’],_ROOT . ‘/product_images/’ .

$_FILES[‘ImageUpload’][‘name’]);

// Обновляем информацию о товаре в базе данных

Catalog::SetImage($this->_mProductId,

$_FILES[‘ImageUpload’][‘name’]);

}

// Если код ошибки — 0, файл успешно загружен

if ($_FILES[‘Image2Upload’][‘error’] == 0)

{

/* ИспользуемфункциюPHPmove_uploaded_fileдляперемещения

загруженного файла из временной папки в папку product_images */

move_uploaded_file($_FILES[‘Image2Upload’][‘tmp_name’],_ROOT . ‘/product_images/’ .

$_FILES[‘Image2Upload’][‘name’]);

// Обновляем информацию о товаре в базе данных

Catalog::SetImage2($this->_mProductId,

$_FILES[‘Image2Upload’][‘name’]);

}

// Если код ошибки — 0, файл успешно загружен

if ($_FILES[‘ThumbnailUpload’][‘error’] == 0)

{

// Перемещаем загруженный файл в папку product_images

move_uploaded_file($_FILES[‘ThumbnailUpload’][‘tmp_name’],_ROOT . ‘/product_images/’ .

$_FILES[‘ThumbnailUpload’][‘name’]);

// Обновляем информацию о товаре в базе данных

Catalog::SetThumbnail($this->_mProductId,

$_FILES[‘ThumbnailUpload’][‘name’]);

}

}

// При обновлении информации о товаре…

if (isset ($_POST[‘UpdateProductInfo’]))

{

$product_name = $_POST[‘name’];

  • $product_description = $_POST[‘description’];
  • $product_price = $_POST[‘price’];
  • $product_discounted_price = $_POST[‘discounted_price’];($product_name == null)

$this->mErrorMessage = ‘Product name is empty’;($product_description == null)

$this->mErrorMessage = ‘Product description is empty’;($product_price == null || !is_numeric($product_price))

$this->mErrorMessage = ‘Product price must be a number!’;($product_discounted_price == null ||

!is_numeric($product_discounted_price))

$this->mErrorMessage = ‘Product discounted price must be a number!’;($this->mErrorMessage == null)::UpdateProduct($this->_mProductId, $product_name,

$product_description, $product_price, $product_discounted_price);

}

// При удалении товара из категории…

if (isset ($_POST[‘RemoveFromCategory’]))

{

$target_category_id = $_POST[‘TargetCategoryIdRemove’];

$still_exists = Catalog::RemoveProductFromCategory(

$this->_mProductId, $target_category_id);($still_exists == 0)

{(‘Location: ‘ ._decode(

$this->mLinkToCategoryProductsAdmin));();

}

}

// При задании режима отображения товара…

if (isset ($_POST[‘SetProductDisplayOption’]))

{

$product_display = $_POST[‘ProductDisplay’];::SetProductDisplayOption($this->_mProductId,

$product_display);

}

// При удалении товара из каталога…

if (isset ($_POST[‘RemoveFromCatalog’]))

{::DeleteProduct($this->_mProductId);(‘Location: ‘ ._decode(

$this->mLinkToCategoryProductsAdmin));();

}

// При зачислении товара в другую категорию…(isset ($_POST[‘Assign’]))

{

$target_category_id = $_POST[‘TargetCategoryIdAssign’];::AssignProductToCategory($this->_mProductId,

$target_category_id);

}

// При переносе товара в другую категорию…

if (isset ($_POST[‘Move’]))

{

$target_category_id = $_POST[‘TargetCategoryIdMove’];::MoveProductToCategory($this->_mProductId,

$this->_mCategoryId, $target_category_id);(‘Location: ‘ ._decode(::ToProductAdmin($this->_mDepartmentId,

$target_category_id,

$this->_mProductId)));

  • exit();

}

// При присвоении товару значения атрибута…

if (isset ($_POST[‘AssignAttributeValue’]))

{

$target_attribute_value_id = $_POST[‘TargetAttributeValueIdAssign’];::AssignAttributeValueToProduct($this->_mProductId, $target_attribute_value_id);

}

// При удалении значения атрибута из товара…

if (isset ($_POST[‘RemoveAttributeValue’]))

{

$target_attribute_value_id = $_POST[‘TargetAttributeValueIdRemove’];::RemoveProductAttributeValue($this->_mProductId, $target_attribute_value_id);

}

// Получаем информацию о товаре

$this->mProduct = Catalog::GetProductInfo($this->_mProductId);

$product_categories = Catalog::GetCategoriesForProduct(

$this->_mProductId);

  • $product_attributes =::GetProductAttributes($this->_mProductId);($i = 0;
  • $i <
  • count($product_attributes);
  • $i++)

$this->mProductAttributes[

$product_attributes[$i][‘attribute_value_id’]] =

$product_attributes[$i][‘attribute_name’] . ‘: ‘ .

$product_attributes[$i][‘attribute_value’];

  • $catalog_attributes =::GetAttributesNotAssignedToProduct($this->_mProductId);($i = 0;
  • $i <
  • count($catalog_attributes);
  • $i++)

$this->mCatalogAttributes[

$catalog_attributes[$i][‘attribute_value_id’]] =

$catalog_attributes[$i][‘attribute_name’] . ‘: ‘ .

$catalog_attributes[$i][‘attribute_value’];(count($product_categories) == 1)

$this->mRemoveFromCategoryButtonDisabled = true;

// Отображаем категории, к которым принадлежит товар

for ($i = 0; $i < count($product_categories); $i++)

$temp1[$product_categories[$i][‘category_id’]] =

$product_categories[$i][‘name’];

  • $this->mRemoveFromCategories = $temp1;
  • $this->mProductCategoriesString = implode(‘, ‘, $temp1);
  • $all_categories = Catalog::GetCategories();($i = 0;
  • $i <
  • count($all_categories);
  • $i++)

$temp2[$all_categories[$i][‘category_id’]] =

$all_categories[$i][‘name’];

  • $this->mAssignOrMoveTo = array_diff($temp2, $temp1);

}

}

?>

Приложение Б

Листинги SQL-запросов

Запрос 1

  • CreategoodstoreadminuserALL PRIVILEGES ON `goodstore`.*’goodstoreadmin’@’localhost’ IDENTIFIED’goodstoreadmin’GRANT OPTION;

Запрос 2

  • СоздаемтаблицуdepartmentTABLE `department` (

`department_id` INT NOT NULL AUTO_INCREMENT,

`name` VARCHAR(100) NOT NULL,

`description` VARCHAR(1000),KEY (`department_id`)

ENGINE=MyISAM;

Запрос 3

  • ЗаполняемданнымитаблицуdepartmentINTO `departmen` (`departmen_id`, `name`, `description`) VALUES

(1, ‘Одежда’, ‘Верхняя одежда, блузки, брюки, платья, юбки’),

(2, ‘Обувь’,’Зимняя, осенняя, летняя’),

(3, ‘Аксессуары’, ‘Сумки, шарфы, шапки’);

Запрос 4

  • Созданиехранимойпроцедурыcatalog_get_departments_listPROCEDURE catalog_get_departments_list()department_id, name FROM department ORDER BY department_id;$$

Запрос 5

  • СоздаемтаблицуcategoryTABLE `category`

( `category_id` INT NOT NULL AUTO_INCREMENT,

`name` VARCHAR(100) NOT NULL,

`description` VARCHAR(1000),KEY (`category_id`),`idx_category_department_id` (`department_id`)

ENGINE=MyISAM;

Запрос 6

  • ЗаполняемтаблицуcategoryданнымиINTO `category` (`category_id`, `department_id`, `name`,

`description`) VALUES

(1, 1, ‘Верхняя одежда’, ‘Пуховики, пальто, ветровки’),

(2, 1, ‘Блузки’, ‘Блузки, рубашки, футболки, толстовки’),

(3, 1, ‘Брюки’, ‘Брюки, джинсы, шорты’),

(4, 1, ‘Платья’, ‘Платья, сарафаны’),

(5, 1, ‘Юбки’, ‘Юбка карандаш, мини, макси’),

(6, 2, ‘Зимняя обувь’, ‘Сапоги, ботфорты’),

(7, 2, ‘Осенняя обувь’, ‘Сапоги, ботильоны, ботинки, кеды на танкетке, ботфорты ‘),

(8, 2, ‘Летняя обувь’, ‘Туфли, босоножки, балетки, сандалии, сланцы’),

(9, 2, ‘Спортивная обувь’, ‘Кроссовки, кеды, кеды на танкетке’),

(10, 3, ‘Сумки’, ‘Сумки, рюкзаки, клатчи’),

(11, 3, ‘Шарфы’, ‘Теплые шарфы, легкие шарфы, хомуты’),

(12, 3, ‘Шапки’, ‘Вязаные шапки, хомуты’);

Запрос 7

  • СоздаемтаблицуproductTABLE `product` (

`product_id` INT NOT NULL AUTO_INCREMENT,

`name` VARCHAR(100) NOT NULL,

`description` VARCHAR(1000) NOT NULL,

`price` NUMERIC(10, 2) NOT NULL,

`discounted_price` NUMERIC(10, 2) NOT NULL DEFAULT 0.00,

`image` VARCHAR(150),

`image_2` VARCHAR(150),

`thumbnail` VARCHAR(150),

`display` SMALLINT NOT NULL DEFAULT 0,KEY (`product_id`)

ENGINE=MyISAM;

Запрос 8

  • Созданиетаблицыproduct_categoryTABLE `product_category` (

`product_id` INT NOT NULL,

`category_id` INT NOT NULL,KEY (`product_id`, `category_id`)

ENGINE=MyISAM;

Запрос 9

  • Создаемхранимуюпроцедуру catalog_get_department_detailsPROCEDURE catalog_get_department_details(IN inDepartmentId INT)name, descriptiondepartmentdepartment_id = inDepartmentId;$$

Запрос 10

  • Создаемхранимуюпроцедуруcatalog_get_categories_listPROCEDURE catalog_get_categories_list(IN inDepartmentId INT)category_id, namecategorydepartment_id = inDepartmentIdBY category_id;$$

Запрос 11

  • Создаемхранимуюпроцедуру catalog_get_category_detailsPROCEDURE catalog_get_category_details(IN inCategoryId INT)name, descriptioncategorycategory_id = inCategoryId;$$

Запрос 12

  • Создаемхранимуюпроцедуру catalog_count_products_in_categoryPROCEDURE catalog_count_products_in_category(IN inCategoryId INT)COUNT(*) AS categories_countproduct pJOIN product_category pcp.product_id = pc.product_idpc.category_id = inCategoryId;$$

Запрос 13

  • Создаемхранимуюпроцедуру catalog_get_products_in_categoryPROCEDURE catalog_get_products_in_category(inCategoryId INT, IN inShortProductDescriptionLength INT,inProductsPerPage INT, IN inStartItem INT)
  • Подготавливаемоператорstatement FROM

«SELECT p.product_id, p.name,(LENGTH(p.description) <= ?,.description,(LEFT(p.description, ?),

‘…’)) AS description,.price, p.discounted_price, p.thumbnailproduct pJOIN product_category pcp.product_id = pc.product_idpc.category_id = ?BY p.display DESC?, ?»;

  • Определяемпараметрызапроса@p1 = inShortProductDescriptionLength;@p2 = inShortProductDescriptionLength;@p3 = inCategoryId;@p4 = inStartItem;@p5 = inProductsPerPage;
  • Выполняемоператорstatement USING @p1, @p2, @p3, @p4, @p5;$$

Запрос 14

  • Создаемхранимуюпроцедуру catalog_count_products_on_departmentPROCEDURE catalog_count_products_on_department(IN inDepartmentId)DISTINCT COUNT(*) AS products_on_department_countproduct pJOIN product_category pcp.product_id = pc.product_idJOIN category cpc.category_id = c.category_id(p.display = 2 OR p.display = 3)c.department_id = inDepartmentId;$$

Запрос 15

  • Создаемхранимуюпроцедуру catalog_get_products_on_departmentPROCEDURE catalog_get_products_on_department(inDepartmentId INT, IN inShortProductDescriptionLength INT,inProductsPerPage INT, IN inStartItem INT)statement FROM

«SELECT DISTINCT p.product_id, p.name,(LENGTH(p.description) <= ?,.description,(LEFT(p.description, ?),

‘…’)) AS description,.price, p.discounted_price, p.thumbnailproduct pJOIN product_category pcp.product_id = pc.product_idJOIN category cpc.category_id = c.category_id(p.display = 2 OR p.display = 3)c.department_id = ?BY p.display DESC?, ?»;@p1 = inShortProductDescriptionLength;@p2 = inShortProductDescriptionLength;@p3 = inDepartmentId;@p4 = inStartItem;@p5 = inProductsPerPage;statement USING @p1, @p2, @p3, @p4, @p5;$$

Запрос 16

  • Создаемхранимуюпроцедуру catalog_count_products_on_catalogPROCEDURE catalog_count_products_on_catalog()COUNT(*) AS products_on_catalog_countproductdisplay = 1 OR display = 3;$$

Запрос 17

  • Создаемхранимуюпроцедуру catalog_get_products_on_catalogPROCEDURE catalog_get_products_on_catalog(inShortProductDescriptionLength INT,inProductsPerPage INT, IN inStartItem INT)statement FROM

«SELECT product_id, name,(LENGTH(description) <= ?,,(LEFT(description, ?),

‘…’)) AS description,, discounted_price, thumbnailproductdisplay = 1 OR display = 3BY display DESC?, ?»;@p1 = inShortProductDescriptionLength;@p2 = inShortProductDescriptionLength;@p3 = inStartItem;@p4 = inProductsPerPage;statement USING @p1, @p2, @p3, @p4;$$

Запрос 18

  • Создаемхранимуюпроцедуру catalog_get_product_detailsPROCEDURE catalog_get_product_details(IN inProductId INT)product_id, name, description,, discounted_price, image, image_2productproduct_id = inProductId;$$

Запрос 19

  • Создаемхранимуюпроцедуру catalog_get_product_locationsPROCEDURE catalog_get_product_locations(IN inProductId INT)c.category_id, c.name AS category_name, c.department_id,

(SELECT namedepartmentdepartment_id = c.department_id) AS department_name

  • Подзапрос возвращает название отдела заданной категории

FROM category cc.category_id IN

(SELECT category_idproduct_category

WHERE product_id = inProductId);

  • Этот подзапрос возвращает идентификаторы категорий,
  • к которым принадлежит товар$$

Запрос 20

  • Создаем таблицу attribute (в ней хранЯтсЯ названиЯ
  • атрибутов, например, Размер и Цвет)

CREATE TABLE `attribute` (

`attribute_id` INT NOT NULL AUTO_INCREMENT,

`name` VARCHAR(100) NOT NULL, — Например, Цвет, РазмерKEY (`attribute_id`)

ENGINE=MyISAM;

Запрос21

  • ЗаполняемданнымитаблицуattributeINTO `attribute` (`attribute_id`, `name`) VALUES

(1, ‘Размер’), (2, ‘Цвет’);

Запрос 22

  • Создаем таблицу attribute_value (в ней хранятся
  • значения вроде Белый или XXL)

CREATE TABLE `attribute_value` (

`attribute_value_id` INT NOT NULL AUTO_INCREMENT,

`attribute_id` INT NOT NULL, — Идентификаторатрибута

`value` VARCHAR(100) NOT NULL, — Например, Белый/KEY (`attribute_value_id`),`idx_attribute_value_attribute_id` (`attribute_id`)

ENGINE=MyISAM;

Запрос 23

  • Заполняемданнымитаблицуattribute_valueINTO `attribute_value` (`attribute_value_id`, `attribute_id`,

`value`)

(1, 1, ‘S’), (2, 1, ‘M’), (3, 1, ‘L’), (4, 1, ‘XL’), (5, 1, ‘XXL’),

(6, 2, ‘Черный’), (7, 2, ‘Бежевый’), (8, 2, ‘Красный’), (9, 2, ‘Коричневый’),

(10, 2, ‘Голубой’), (11, 2, ‘Синий’), (12, 2, ‘Желтый’),

(13, 2, ‘Белый’), (14, 2, ‘Сиреневый’), (15, 2, ‘Розовый’), (16, 2, ‘Зеленый’), (17, 2, ‘Серый’),

(18, 2, ‘Сиреневый’), (19, 2, ‘Разноцветный’);

Запрос24

  • Создаем таблицу product_attribute (свЯзывающую значениЯ
  • атрибутовстоварами)TABLE `product_attribute` (

`product_id` INT NOT NULL,

`attribute_value_id` INT NOT NULL,KEY (`product_id`, `attribute_value_id`)

ENGINE=MyISAM;

Запрос 25

  • Заполняемданнымитаблицу product_attributeINTO `product_attribute` (`product_id`, `attribute_value_id`)`p`.`product_id`, `av`.`attribute_value_id«product` `p`, `attribute_value` `av`;

Запрос 26

— Создаемхранимуюпроцедуру catalog_get_product_attributesPROCEDURE catalog_get_product_attributes(IN inProductId INT)a.name AS attribute_name,.attribute_value_id, av.value AS attribute_valueattribute_value avJOIN attribute aav.attribute_id = a.attribute_idav.attribute_value_id IN

(SELECT attribute_value_idproduct_attributeproduct_id = inProductId)BY a.name;$$

Запрос27

  • Создаемхранимуюпроцедуруcatalog_get_departmentsPROCEDURE catalog_get_departments()department_id, name, descriptiondepartmentBY department_id;$$

Запрос 28

  • Создаемхранимуюпроцедуру catalog_add_departmentPROCEDURE catalog_add_department(inName VARCHAR(100), IN inDescription VARCHAR(1000))INTO department (name, description)(inName, inDescription);$$

Запрос 29

  • Создаемхранимуюпроцедуру catalog_update_departmentPROCEDURE catalog_update_department(IN inDepartmentId INT,inName VARCHAR(100), IN inDescription VARCHAR(1000))departmentname = inName, description = inDescriptiondepartment_id = inDepartmentId;$$

Запрос 30

  • Создаемхранимуюпроцедуруcatalog_delete_departmentPROCEDURE catalog_delete_department(IN inDepartmentId INT)categoryRowsCount INT;count(*)categorydepartment_id = inDepartmentIdcategoryRowsCount;categoryRowsCount = 0 THENFROM department WHERE department_id = inDepartmentId;1;-1;IF;$$

Запрос 31

  • Созданиехранимойпроцедуры catalog_get_department_categoriesPROCEDURE catalog_get_department_categories(IN inDepartmentId INT)category_id, name, descriptioncategorydepartment_id = inDepartmentIdBY category_id;$$

Запрос 32

  • Создание хранимой процедуры catalog_add_category

CREATE PROCEDURE catalog_add_category(IN inDepartmentId INT,inName VARCHAR(100), IN inDescription VARCHAR(1000))INTO category (department_id, name, description)(inDepartmentId, inName, inDescription);$$

Запрос 33

  • Создание хранимой процедуры catalog_update_category

CREATE PROCEDURE catalog_update_category(IN inCategoryId INT,inName VARCHAR(100), IN inDescription VARCHAR(1000))categoryname = inName, description = inDescriptioncategory_id = inCategoryId;$$

Запрос 34

  • Создание хранимой процедуры catalog_delete_category

CREATE PROCEDURE catalog_delete_category(IN inCategoryId INT)productCategoryRowsCount INT;count(*)product pJOIN product_category pcp.product_id = pc.product_idpc.category_id = inCategoryIdproductCategoryRowsCount;productCategoryRowsCount = 0 THENFROM category WHERE category_id = inCategoryId;1;-1;IF;$$

Запрос 35

  • Создаемхранимуюпроцедуруcatalog_get_attributesPROCEDURE catalog_get_attributes()attribute_id, name FROM attribute ORDER BY attribute_id;

END$$

Запрос36

  • Создаем хранимую процедуру catalog_add_attribute

CREATE PROCEDURE catalog_add_attribute(IN inName VARCHAR(100))INTO attribute (name) VALUES (inName);$$

Запрос 37

  • Создаемхранимуюпроцедуру catalog_update_attributePROCEDURE catalog_update_attribute(inAttributeId INT, IN inName VARCHAR(100))attribute SET name = inName WHERE attribute_id = inAttributeId;$$

Запрос 38

  • Создаемхранимуюпроцедуруcatalog_delete_attributePROCEDURE catalog_delete_attribute(IN inAttributeId INT)attributeRowsCount INT;count(*)attribute_valueattribute_id = inAttributeIdattributeRowsCount;attributeRowsCount = 0 THENFROM attribute WHERE attribute_id = inAttributeId;1;-1;IF;$$

Запрос 39

  • Создаемхранимуюпроцедуру catalog_get_attribute_detailsPROCEDURE catalog_get_attribute_details(IN inAttributeId INT)attribute_id, nameattributeattribute_id = inAttributeId;$$

Запрос 40

  • Создаемхранимуюпроцедуру catalog_get_attribute_valuesPROCEDURE catalog_get_attribute_values(IN inAttributeId INT)attribute_value_id, valueattribute_valueattribute_id = inAttributeIdBY attribute_id;$$

Запрос 41

  • Создаемхранимуюпроцедуру catalog_add_attribute_valuePROCEDURE catalog_add_attribute_value(inAttributeId INT, IN inValue VARCHAR(100))INTO attribute_value (attribute_id, value)(inAttributeId, inValue);$$

Запрос 42

  • Создаемхранимуюпроцедуру catalog_update_attribute_valuePROCEDURE catalog_update_attribute_value(inAttributeValueId INT, IN inValue VARCHAR(100))attribute_valuevalue = inValueattribute_value_id = inAttributeValueId;$$

Запрос 43

  • Создаемхранимуюпроцедуру catalog_delete_attribute_valuePROCEDURE catalog_delete_attribute_value(IN inAttributeValueId INT)productAttributeRowsCount INT;count(*)product pJOIN product_attribute pap.product_id = pa.product_idpa.attribute_value_id = inAttributeValueIdproductAttributeRowsCount;productAttributeRowsCount = 0 THENFROM attribute_value WHERE attribute_value_id =;1;-1;IF;$$

Запрос 44

  • Создаетхранимуюпроцедуру catalog_get_category_productsPROCEDURE catalog_get_category_products(IN inCategoryId INT)p.product_id, p.name, p.description, p.price,.discounted_priceproduct pJOIN product_category pcp.product_id = pc.product_idpc.category_id = inCategoryIdBY p.product_id;$$

Запрос 45

  • Создаетхранимуюпроцедуру catalog_add_product_to_categoryPROCEDURE catalog_add_product_to_category(IN inCategoryId INT,inName VARCHAR(100), IN inDescription VARCHAR(1000),inPrice DECIMAL(10, 2))productLastInsertId INT;INTO product (name, description, price)(inName, inDescription, inPrice);LAST_INSERT_ID() INTO productLastInsertId;INTO product_category (product_id, category_id)(productLastInsertId, inCategoryId);$$

Запрос 46

  • Создаемхранимуюпроцедуру catalog_update_productPROCEDURE catalog_update_product(IN inProductId INT,inName VARCHAR(100), IN inDescription VARCHAR(1000),inPrice DECIMAL(10, 2), IN inDiscountedPrice DECIMAL(10, 2))productname = inName, description = inDescription, price = inPrice,_price = inDiscountedPriceproduct_id = inProductId;$$

Запрос 47

  • Создаемхранимуюпроцедуру catalog_delete_productPROCEDURE catalog_delete_product(IN inProductId INT)FROM product_attribute WHERE product_id = inProductId;FROM product_category WHERE product_id = inProductId;FROM product WHERE product_id = inProductId;$$

Запрос 48

  • Создаемхранимуюпроцедуру catalog_remove_product_from_categoryPROCEDURE catalog_remove_product_from_category(inProductId INT, IN inCategoryId INT)productCategoryRowsCount INT;count(*)product_categoryproduct_id = inProductIdproductCategoryRowsCount;productCategoryRowsCount = 1 THENcatalog_delete_product(inProductId);0;FROM product_categorycategory_id = inCategoryId AND product_id = inProductId;
  • SELECT 1;;$$

Запрос 49

  • Создаемхранимуюпроцедуру catalog_get_categoriesPROCEDURE catalog_get_categories()category_id, name, descriptioncategoryBY category_id;$$

Запрос 50

  • Создаемхранимуюпроцедуру catalog_get_product_infoPROCEDURE catalog_get_product_info(IN inProductId INT)product_id, name, description, price, discounted_price,, image_2, thumbnail, displayproductproduct_id = inProductId;$$

Запрос 51

  • Создаемхранимуюпроцедуру catalog_get_categories_for_productPROCEDURE catalog_get_categories_for_product(IN inProductId INT)c.category_id, c.department_id, c.namecategory cproduct_category pcc.category_id = pc.category_idpc.product_id = inProductIdBY category_id;$$

Запрос 52

  • Создаемхранимуюпроцедуру catalog_set_product_display_optionPROCEDURE catalog_set_product_display_option(inProductId INT, IN inDisplay SMALLINT)product SET display = inDisplay WHERE product_id = inProductId;$$

Запрос 53

  • Создаемхранимуюпроцедуру catalog_assign_product_to_categoryPROCEDURE catalog_assign_product_to_category(inProductId INT, IN inCategoryId INT)INTO product_category (product_id, category_id)(inProductId, inCategoryId);$$

Запрос54

  • Создаемхранимуюпроцедуру catalog_move_product_to_categoryPROCEDURE catalog_move_product_to_category(IN inProductId INT,inSourceCategoryId INT, IN inTargetCategoryId INT)product_categorycategory_id = inTargetCategoryIdproduct_id = inProductIdcategory_id = inSourceCategoryId;$$

Запрос 55

— Создаемхранимуюпроцедуру catalog_get_attributes_not_assigned_to_productPROCEDURE catalog_get_attributes_not_assigned_to_product(inProductId INT)a.name AS attribute_name,.attribute_value_id, av.value AS attribute_valueattribute_value avJOIN attribute aav.attribute_id = a.attribute_idav.attribute_value_id NOT IN

(SELECT attribute_value_idproduct_attributeproduct_id = inProductId)BY attribute_name, av.attribute_value_id;$$

Запрос 56

  • Создаемхранимуюпроцедуру catalog_assign_attribute_value_to_productPROCEDURE catalog_assign_attribute_value_to_product(inProductId INT, IN inAttributeValueId INT)INTO product_attribute (product_id, attribute_value_id)(inProductId, inAttributeValueId);$$

Запрос 57

  • Создаемхранимуюпроцедуру catalog_remove_product_attribute_valuePROCEDURE catalog_remove_product_attribute_value(inProductId INT, IN inAttributeValueId INT)FROM product_attributeproduct_id = inProductId AND_value_id = inAttributeValueId;$$

Запрос 58

  • Создаем хранимую процедуру catalog_set_image

CREATE PROCEDURE catalog_set_image(inProductId INT, IN inImage VARCHAR(150))product SET image = inImage WHERE product_id = inProductId;$$

Запрос 59

  • Создаемхранимуюпроцедуруcatalog_set_image_2PROCEDURE catalog_set_image_2(inProductId INT, IN inImage VARCHAR(150))product SET image_2 = inImage WHERE product_id = inProductId;$$

Запрос 60

  • Создаемхранимуюпроцедуруcatalog_set_thumbnailPROCEDURE catalog_set_thumbnail(inProductId INT, IN inThumbnail VARCHAR(150))productthumbnail = inThumbnailproduct_id = inProductId;$$