Pull to refresh

Создание сайта из готовых компонентов на примере сайта заказа еды в офис

Reading time 14 min
Views 8.5K
В окрестностях нашего офиса нет приличного общепита, поэтому обеды нам привозят на заказ из одного кафэ. Заказ осуществляется за день (на понедельник заказ делается с пятницы), по телефону, с перечислением всех блюд и их количества (в случае если заказ не изменился относительно вчерашнего достаточно просто сказать это). Как компания, занимающаяся разработкой ПО, преимущественно веб, мы до недавнего времени жили по принципу «Сапожник без сапог», и весь учет заказов велся ответсвенным за заказ еды человеком на листочке, в случае изменения заказа нужно было писать письмо этому ответственному человеку, а он уже пересчитывал общий заказ.

Выкроив немного свободного времени в перерыве между проектами реализовал (именно реализовал, а не написал — почему именно так, расскажу немного ниже) систему для заказа еды. За основу, как нетрудно догадаться исходя из тематики блога, была взята CMS Drupal, которая является моим основным инструментом уже около полутора лет.

Цели данного топика:
  • Показать новичкам на довольно простом примере, как создается сайт невысокой сложности на CMS Drupal
  • Кратко расказать про несколько основных модулей — как правило они применяются в 90% проектов на друпале
  • Показать как можно собрать сайт на друпале из готовых компонентов, не написав при этом ни одной строчки кода (на самом деле будет пара строк кода, но немного не в том виде, как он обычно пишется =))


Итак, что должно быть реализовано в проекте:
  • Меню — список блюд, разделенных на категории, с возможностью описания блюд
  • Индивидуальные заказы — пользователь может сделать и заказ, просмотреть его содержимое и изменить
  • Сводный заказ — список всех заказаных пользователями блюд с указанием их количества
  • Возможность делиться впечатлениями о блюдах — тут просто возможность комментирования и рейтингования



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

Итак, приступам. Первое что нам понадобится, это собственно сам Drupal. На момент написания статьи последняя стабильная версия — 6.10. Установка друпала не должна вызвать никаких затруднений — все, ИМХО, предельно просто и понятно — инсталятор дает достаточно подсказок и пояснений. После установки у нас имеется девственно-чистая система.


Т.к. во время разработки нам очень много приется ходить по разным разделам сайта, то начнем мы с установки модуля Administration menu. Этот модуль создает меню вверху страницы для быстрой навигации по сайту для администрирования. Для установки модуля скачиваем его (на момент написания статьи последняя стабильная версия 6.x-1.3), распаковываем и помещаем в sites/all/modules (папку modules нужно будет создать самому, почему именно сюда — можете почитать в документации друпала). После этого идем в Administer -> Site building -> Modules и включаем модуль. Сразу после установки модуля должны увидеть вверху то самое администраторское меню, с выпадающими пунктами. Вобще, для того чтобы оно появилось, необходимо дать пользователям на это разрешение в разделе Administer -> User management -> Permissions, но т.к. мы сейчас работаем под пользователем с UID 1, то нам можно все и всегда (поэтому тестировать им ни в коем случае нельзя).


Теперь нам нужно создать новый тип контента, который будет представлять собой описание блюда. Для этого идем в Administer -> Content management -> Content types -> Add content type и настраиваем все необходимое нам. Я назвал тип контента Meal (врутреннее имя meal), переименовал Body в Description (ибо у нас тут будет описание), убрал галку с Promoted to front page, ибо мы не собираемся выводить информацию о блюдах на главную и покрутил немного настройки каментов.


Фундамент положен, и теперь нужно на его основе строить сайт. Одного описания и названия для блюда мало. Во первых нам необходимо разделять блюда по категориям (Салаты, Супы, Горячее и т.д.), затем нам нужна цена блюда и, добавим еще возможность прикрепления избражений блюда. Если первое мы может сделать при помощи модуля Taxonomy, который входит в базовую поставку друпала, то для остального нам нужно будет установить дополнительные модули. Для добавления полей разных типов в контент тайпы у друпала есть модуль Content Construction Kit (CCK). В его поставку включены как базовый модуль для добавления дополнительных полей, так и небольшой набор частоиспользуемых типов полей. Скачиваем, распаковываем и помещаем этот модуль в sites/all/modules (это набор действий одинаков для все всех новых модулей, поэтому больше описывать его я не буду, при установке нового стороннего модуля оно подразумевается автоматически). Для добавления цены нам понадобится поле типа Money, которое входит в состав модуля Money CCK field. Этот модуль зависит от нескольких модулей (узнать это можно зайдя в раздел управления модулями) — это Currency API, который является частью модуля Currency Exchange, Format Number API и Formatted Number CCK. Для добавления изображений к ноде (нода — это название еденицы контента в друале) вобще-то можно воспользоватся стандартным модулем прикрепления файлов, но нам хочется чтобы все было красиво, а посему воспользуемся настраиваемым полем для загрузки изображений. Для реализации этого нам понадобятся модули ImageField и ImageCache, а так же их зависимости — FileField и ImageAPI.

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

Итак, после того как все модули скачаны и помещены куда нужно идем в секцию управления модулями (Administer -> Site building -> Modules) и отмечаем галочками нужные нам модули. А нужны нам следующие — ImageField, Money CCK field, ImageCache, ImageCache UI, ImageAPI GD2 и Taxonomy (должен быть установлен по умолчанию, но если нет, то установим). Все требуемые им модули будут установлены автоматически (в установщике модуля Money CCK field верси 1.0 есть небольшая ошибка, и он выдает сообщение о то что его зависимости не установлены, хотя они устанавливаются автоматически, поэтому этот модуль придется еще раз отметить галкой и запустить установку).

Теперь создадим профиль для загружаемых изображений блюд. Для этого нам и нужен был модуль ImageCache. Идем в Administer -> Site configuration -> By module (сюда, потому что ImageCache UI почему-то не выносит ссылку на свои настройки в общий список), ищем модуль ImageCache UI и идем в единственный его возможный вариант настройки — ImageCache. Создаем новый набор настроек (Add new preset). Назовом его meal_img и добавим действие Scale (масштабирование). В поле Width укажем 120 (пикселей), а из поля Height удалим значение. Тогда изображения у нас будут масштабироваться с соблюдением пропорций и уменьшаться относительно ширины.

Теперь создадим категории, по которым у нас будут делится блюда. Для этого идем в Administer -> Content management -> Taxonomy -> Add vocabulary и заполняем поля:
Vocabulary nameКатегория
Content typesMeal
Required
После чего идем в раздел add terms нашего словаря и создаем несколько категорий (терминов).


Теперь можно переходить к добавлению необходимых нам полей к созданному ранее типу контента Meal. Для этог идем в Administer -> Content management -> Content types -> Edit Meal -> Manage fields и создаем нужные поля. А нужны нам следующие поля:
  1. Label: Cost, Field Name: field_cost, Type: Money, Form element: Amount and currency, после создания выбираем удобный нам вид отображения и валюту (почему-то всегда считал что Российский рубль это RUR, а тут почему-то RUB) и делаем поле обязательным для заполнения (Required)
  2. Label: Pictures, Field Name: field_pictures, Type: File, Form element: Image, обязательным это поле делать не обязательно, а максимальное количесто (Number of values) можно установить, например, в 3, ну и покрутить немного настройки, чтобы пользователям было проще добавлять новые блюда в меню.



Теперь нам нужно настроить отображение нод. Для этого идем в Administer -> Content management -> Content types -> Edit Meal -> Display fields -> Basic. Тут для поля Pictures нужно выставить:
Teaser<Hidden>
Full nodemeal_img image linked to image (для этого мы и создавали пресет)
Для поля Cost можно выставить поле Label в значение Inline, чтобы подпись к полю была в одну строку со значением.


Ну а теперь пришло время наконец-то создать несколько экзепляров блюд для дальнейшего тестирования. Для этого идем в Create content -> Meal и заполняем поля. Повторяем это действие несколько раз. Добавим по парочке блюд в каждую категорию.


Далее, добавим блюдам собственно возможность заказа и систему рейтингования (просто так =)). В этом нам помогут модули Flag и модуль Fivestar, для которого потребуется установить так же Voting API. Качаем эти модули, идем в панель управления модулями и включаем Flag и Fivestar. После установки, необходимо настроить модули. Для этого сначала идем в Administer -> Site configuration -> Fivestar и выбираем стиль, который вам нравится больше всего (я выбрал Basic с желтым набором цветов, наведя курсор на звездочки можно сразу увидеть как они будут выглядеть). Теперь нужно активировать систему рейтингов для контента, реализующего блюда. Для этого идем в Administer -> Content types -> Edit Meal и в разделе Fivestar ratings ставим галку Enable Fivestar rating, и выставим значение поля Teaser display в Clickable widget below teaser (пригодится нам позже). Остальные настройки можете крутить на свой вкус.


Теперь ненадолго отвлечемся от контента и сделаем несколько настроек для пользователей. Наш ресурс для заказа еды будет являться внутренним, но расположен он будет в глобальной сети, поэтому нам нужно как-то его защитить. Для этого мы во-первых отключим возможность регистрации новых пользователей (при устройстве на работу наш сисадмин заводит учетные записи в используемых нами системах — почта, форум, бейзкэмп, теперь еще и в системе заказа еды). Сделать это можно пройдя в Administer -> User management -> User settings и выставив переключатель Public registrations в положение Only site administrators can create new user accounts. Теперь идем в Administer -> User management -> Roles и добавляем новую роль (я назвал ее HabraUser). Теперь настроим права доступа. Для этого идем в Administer -> User management -> Permissions, убираем все права у групп anonymous user и authenticated user, а группе HabraUser даем следующий набор прав:
comment module: access comments, post comments, post comments without approval
fivestar module: rate content
node module: access content
user module: access user profiles


Теперь, наконец-то, добавим возможность заказывать блюда. Для этого нужно создать и настроить новый флаг. Для этого идем в Administer -> Site building -> Flags -> Add и создаем флаг с именем meal_order и типом Nodes. Задаем разные надписи (мой варинат можете посмотреть на скриншоте к этому абзацу), разрешаем только пользователям из группы HabraUser пользоваться этим типом флага, и применяем этот флаг только к нодам типа Meal. Показывать флаг будем как в тизере, так и на странице. Link type оставим в значении JavaScript toggle — тогда флаг будет переключаться используя AJAX.


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

Для реализации всевозможных списков в друпале есть очень гибкий модуль Views, им мы и воспользуемся. Скачиваем, идем в панель управления модулями и включаем Views (ядро) и Views UI (админский интерфейс для управления вьюхами). Теперь создадим вьюхи для отображения блюд из разных категорий, для этого идем в Administer -> Site building -> Views -> Add и создаем меню с именем meal_menu, и типом Node. После чего попадаем на страницу управления вьюхой. Изначално у нас нет отображений, и мы можем настроить параметры общие для всех отображений. Я сделал следующие настройки:
  • Basic settings
    • Row style: Node -> Display only teaser, Display links (отображать ноды полностью, показывать только тизер и линки — в линках у нас будет флаг заказа)
    • Items to display: 0 (все блюда на одной станице)
    • Access: Role -> HabraUser

  • Sort criteria
    • Node: Post date: Ascending (тут можете выбрать что вам больше нравится)

  • Filters
    • Node: Published: Yes
    • Node: Type: Is one of -> Meal


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


Теперь создадим конкретные страницы для каждой категории блюд, унаследовав все страницы от базовой. Для этого в левой колонке настройки вьюх выбираемв выпадающем списке тип отображения Page (обычна выбрана по умолчанию) и жмем кнопку Add display и сразу же видим как у нас добавилось новое отображение во вьюху. Т.к.это конкретное отображение — у него несколько изменился набор параметров — добавились параметры меню, и исчезли общие настройки вьюх. Теперь нам нужно переопределить некоторые параметры базовой вьюхи. Первое что нам нужно — добавить фильтр на тармин из словаря категорий таксономии. Для этого добавляем новый фильтр Taxonomy: Term и в нем:
  • VocabularyКатегория (он у нас, собственно, только один)
  • Selection typeDropdown
  • OperatorIs one of
  • Select terms from vocabulary КатегорияГорячее (нужно выбрать только один термин)


Теперь очень важное действие — необходимо нажать кнопку Override, для того чтобы этот фильтр применился только к этому экзепляру отображения. В противном случае он применится к базовому отображению. Теперь жмем Update, что сохранит наш новый фильтр. Далее, дадим отображению имя и заголовок по названию термина. Т.е. поменяем в Basic settings параметры Name и Title (тут так же необходимо будет нажать Override для переопределения параметра, относительно базового отображения) на Горячее. Теперь, для того чтобы можно было попасть на страницу, реализующую данный тип отображения необходимо установить для нее путь. Делается это в разделе Page settings, например meal_menu/hot. Сохраняем вьюху (доэтого все действия заносились во временное хранилице, и легко могут быть отменены).


Теперь повторяем те же самые действия, но для всех остальных терминов таксономии. В итоге должно получиться 3 (у меня 3 термина в словаре, сколько категорий блюд будет в мню, столько и терминов) реализации отображения. У меня они имеют следующие названия/заголовки и пути:
  • Горячееmeal_menu/hot
  • Салатыmeal_menu/salad
  • Супыmeal_menu/soup

Посмотреть что получилось можно перейдя по ссылкам вида View «Салаты», расположенным вверху.


Теперь, когда у нас есть составные части меню, в виде списков блюд по категориям, самое время занятся самим меню. Для этого воспользуемся модулем Panels. На момент написания статьи стабильной версии модуля для шестой версии друпала нет. Есть 2 версии модуля, находящихся в версии альфа — 6.x-3.0-alpha2 и 6.x-2.0-alpha3, т.е. достаточно ранние. И хотя рекомендованной отмечена версия 2.0, мы все же воспользуемся версией 3.0, хотя бы потому что она более новая. А по опыту использования могу сказать что по моим субъективным ощущениям стабильность этих двух верий находится примерно на одном уровне, причем достаточно высоком. Версия 6.x-3.0-alpha2 так же имеет в замисимостях модуль Chaos tool suite. Качаем и идем в панель управления модулями. Там активизируем следующие модули — Chaos tools, Delegator, Panels и Views panes.

Теперь создадим саму страницу с меню. Для этого идем в Administer -> Site building -> Pages -> Add page. Задаем имя и путь для страницы (в моем случае и то и другое meal_menu). Далее добавляем правило доступа на страницу (как вы помните мы создаем сайт для внутреннего использовани, но с доступом через Интернет, поэтому дадим доступ только созданной нами группе). Т.к. меню — это основная функциональная страница сайта, то добавим ссылку на нее в главное меню. Для этого выберем в Type Normal menu entry, зададим заголовок (у меня это Meal Menu) и выберем в Menu Primary links. Далее выберем одиночный обработчик для нашей страницы (Create a single handler for this page) и установим его в Panel (если честно, никогда не пользовался множественными обработчиками). Теперь настроим обработчик. Зададим для него такой же уровень доступа как и для страницы. Из шаблонов нам больше подходит Three column 33/34/33 (по одной категории в колонку, хотя на живом сайте у меня в эти же 3 колонки помещено больше категорий). Далее зададим заголовок для страницы (например Meal Menu) и выберем стиль для панели (советую Rounded corners, ибо этот стиль по умолчанию дает достаточно большое и удобное расстояние между колонками). Ну и наконец добавим в колонки созданные нами ранее отображения вьюхи — meal_menu: Горячее, meal_menu: Салаты, meal_menu: Супы. Если хочется поменять порядок следования вьюх в колонке или поменять колонку для некоторых вьюх — достаточно просто перетащить их — Drag&Drop работает стабильно. Наконец жмем Finish и… не замечаем абсолютно никаких изменений =)


Все дело в том что модуль Panels пользуется своей системой для определения возможности доступа пользователя, поэтому пользователь с UID 1 не имеет привелегий. Как мы помним, доступ к меню был дан только пользователям из группы HabraUser, поэтому просто добавим себя в эту группу. Для этого идем в редактирование своего профиля (My account -> Edit) и в разделе Account information ставим галку HabraUser в поле Roles и сохраняем профиль. Теперь в главном меню появился пункт меню, который и приведет нас на страницу с меню. Теперь мы можем сделать заказ, и перейти к следующей части =)


После того как заказ сделан, нам интересно посмотреть свой заказ у себя в профиле. Для этого опять же воспользуемся возможностями модуля Views. Идем в Administer -> Views -> Add и создаем вьюху с именем user_meal_order c типом Node. У базового отображения (я бы сравнил его с абстрактным базовым классом в ООП) делаем следующие настройки:
  • Basic settings
    • Style: HTML List -> Unordered list
    • Items to display: 0 (все)

  • Relationships
    • Flags: Node flag -> Include only flagged content, Flag: Заказ еды, By: Current user

  • Fields
    • Node: Title -> Label: <пустое значение>, Link this field to its node

  • Sort criteria
    • Flags: Flagged time -> Ascending

  • Filters
    • Node: Published -> Yes


Теперь добавим новое отображение типа Block и добавим следующие настройки:
  • Basic settings
    • Title: Мой заказ (не забудте нажать Override пред сохранением параметра, чтобы переопределить его, а не менять у базового отображения)


Сохраняем вьюху и идем в панель управления блоками Administer -> Blocks -> List. Там в списке находим наш блок, user_meal_order: Block, и добавляем его в регион Left sidebar. Для удобства перетаскиваем блок в самый низ списка блоков региона. Сохраняем настройки блоков. Мы видим что блок появился в левой панели. Но я считаю что не очень красиво, чтобы этот блок болтался на всех страницах. Сделаем так, чтобы блок был виден только в профиле у владельца. Для этого жмем configure рядом с нашим блоком и попадаем на страницу редактирования настроек блока. Тут нас интересует раздел Page specific visibility settings. Устанавливаем параметр Show block on specific pages в значение Show if the following PHP code returns TRUE (PHP-mode, experts only) и пишем в поле ввода следующее (да, это первый кусочек кода =)):

<?php
global $user;
return (arg(0) == 'user' && arg(1) == $user->uid);
?>


Спасибо пользователю brmn за подсказку в оптимизации этого кусочка кода.

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


Последнее что нам осталось реализовать — сводный заказ, т.е. список всех заказаных блюд с указанием их количества. Для этого опять же воспользуемся модулем Views. Для этой страницы нам понадобится дополнительный модуль, поэтому идем в панель управления модулями и включаем PHP filter (идет в стандартной поставке). Теперь идем в Administer -> Views -> Add и создаем вьюху с именем meal_order c типом Node. Изменяем у базового отображения параметры следующим образом:
  • Basic settings
    • Style: HTML List -> Unordered list
    • Row style (настройки, иконка в виде шестеренки, нужно будет сделать после того, как будет пройден пункт Fields): ометить оба поля и в качестве разделителя вписать " — "
    • Items to display: 0
    • Distinct: Distinct (в противном случае у нас будет столько строк с одним блюдом, сколько раз оно заказано)
    • Access: Role -> HabraUser

  • Relationships
    • Flags: Node flag: Include only flagged content, Flag: Заказ еды, By: Any user
    • Flags: Node flag counter: Include only flagged content, Flag: Заказ еды

  • Fields
    • Node: Title: Label: <пустое значение>, Link this field to its node
    • Flags: Flag counter: Label: <пустое значение>

  • Sort criteria
    • Node: Post date -> Ascending

  • Filters
    • Node: Published -> Yes


Затем добавляем новое отображение типа Page и переопределяем в нем в разделе Basic settings следующие параметры:
  • Title: Сводный заказ
  • Header: Display even if view has no result, Input format: PHP code и в поле ввода забиваем следующее (да, второй кусочек кода =))
    <h3>Дата:
    <?php
    echo ((date('w') > 0 && date('w') < 5) ? date('d.m.Y', strtotime('+1 day')) : date('d.m.Y', strtotime('next Monday')));
    ?>
    </h3>
    

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

Теперь в разделе Page settings зададим путь (meal_order) и создадим ссылку в главном меню (Normal menu entry). Сохраняем, и видим в главное меню добавилась ссылка на страницу с общим заказом, куда можно сходить и убедиться в работоспособности выборки. Теперь можно выкладывать систему в Интернет и создавать аккаунты своим коллегам (Administer -> User management -> Users -> Add user)


Дополнительно, сдантартная тема друпала предоставляет CSS для удобного вывода страниц на печать.


Вот вобщем-то и все, что я собирался рассказать в этой статье. Все что задумывалось в проекте — достигнуто. Достигнуты ли цели топика — решать читателям. Жду отзывов и вопросов.

PS: На создание живой версии сайта для мой компании ушло порядка 2.5 часов. В это время входило вбивание порядка сотни наименований блюд (правда без изображений).

UPD:
Заинтересовавшимся темой разработки на друпале могу порекомендовать замечательную книгу, по которой в свое время учился сам — в ней все достаточно понятно и подробно описано (правда во втором издании нашел ошибку в коде =)). Книга называется Pro Drupal Development (издатльство Apress, ISBN 9781430209898). Книг таких в природе существует 2 — первое и второе издание. Первое описывает Drupal 5, второе издание — Drupal 6. Найти их в сети достаточно просто. Книги советую читать в оригинале, т.е. на англ. Ибо о существовании второго издания на русском ничего не знаю, а первое недавно купили в офис (спустя пол года как перешли на Д6) — какое-то оно тонкое, такое чуство что там что-то сократили.
Tags:
Hubs:
+88
Comments 117
Comments Comments 117

Articles