Skip to content

KetrinDorofeeva/website-cafe-restaurant-pleasure

Repository files navigation

Сайт кафе-ресторана Pleasure (дипломный проект)

Технологии разработки Языки программирования Фреймворки База данных
HTML PHP Yii2 MySQL
CSS JavaScript Bootstrap4

Оглавление


Техническое задание

На сайте реализовано семь разделов: «Главная страница», «Акции», «Меню», «Забронировать столик», «Отзывы», «Контакты» и «Корзина»; и формы регистрации и авторизации пользователей.
Для администраторов доступна админ-панель, включающая в себя семь разделов: «Категории меню», «Подкатегории меню (напитки)», «Товары», «Заказчики и их заказы», «Забронированные столики», «Акции» и «Отзывы». Роли и возможности

📑 Оглавление

Блок-схема

Блок-схема

📑 Оглавление

База данных

ER-диаграмма базы данных Таблицы и поля базы данных

📑 Оглавление

Yii2-framework

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

Установка Yii2-фреймворка

  1. Установка при помощи Composer
    Composer - это пакетный менеджер уровня приложений для языка программирования PHP, который предоставляет средства по управлению зависимостями в PHP-приложении.
    Для того, чтобы установить Yii2-фреймворк, нужно открыть консоль в OpenServer:

Консоль в OpenServer

И ввести соответствующую команду:

cd domains
composer create-project yiisoft/yii2-app-basic basic
  
//composer create-project yiisoft/yii2-app-версия придуманное_название_проекта

Эта команда устанавливает последнюю стабильную версию Yii в директорию basic. Если хотите, можете выбрать другое имя директории.

  1. Установка из архива
    Установка Yii из архива состоит из трёх шагов:
    • Скачайте архив с yiiframework.com;
    • Создать папку в domains;
    • Загрузить в папку архив;
    • Распаковать архив;
    • Зайти в папку /config/web.php добавьте секретный ключ в значение cookieValidationKey (при установке через Composer это происходит автоматически):
// !!! Напишите секретный ключ в поле (если оно пустое) - это требуется для проверки файлов cookie
'cookieValidationKey' => 'Введите_здесь_секретный_ключ_(произвольный_набор_символов)',

📑 Оглавление

Настройка ЧПУ

ЧПУ – красивые адреса, ставшие стандартом в веб-разработке.
Фреймворк Yii2 из коробки не имеет настроенных ЧПУ, но исправить это крайне легко. По умолчанию сразу после установки фреймворка для доступа к главной странице необходимо обратиться к папке web, в которой и лежит публичная часть Yii2 приложения. Для доступа к главной странице нужно набрать адрес «http://название_проекта/web/».
От папки web можно легко избавиться с помощью файлов .htaccess.
.htaccess в корне приложения:

RewriteEngine on
RewriteRule ^(.+)?$ /web/$1

.htaccess в папке web:

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php

Таким образом, папки web больше нет в адресной строке. Однако это еще не все. Для того, чтобы получить доступ к странице с формой, которая находится в действии actionIndex контроллера SiteController, нужно набрать следующий адрес: «http://название_проекта/?r=site/index». Вместо такого адреса хотелось бы иметь возможность обратиться к данной странице по такому адресу: «http://название_проекта/site/index».
Для решения поставленной задачи необходимо обратиться к файлу /config/web.php и прописать в массив components компонента urlManager необходимый код:

'urlManager' => [
  'enablePrettyUrl' => true,
  'showScriptName' => false,
  'rules' => [
      
  ],
],

В элемент request массива components нужно добавить строчку 'baseUrl' => ' ':

'components' => [
  'request' => [
    'cookieValidationKey' => 'произвольный_код',
    'baseUrl' => '',
  ],
  ...
],

Для связи проекта с базой данных в файле /config/db.php прописываются dbname, username и password:

return [
  'class' => 'yii\db\Connection',
  'dsn' => 'mysql:host=localhost;dbname=название_базы_данных',
  'username' => 'логин_от_PhpMyAdmin',
  'password' => 'пароль_от_PhpMyAdmin',
  'charset' => 'utf8',
];

📑 Оглавление

Реализация программного продукта

Главная страница

Главная страница кафе-ресторана состоит из трех составляющих:

  1. Лендинг: пользователь видит его сразу при входе на сайт.
    Лендинг (целевая страница) – веб-страница, которая используется для усиления эффективности рекламы, увеличения аудитории. Целевая страница обычно содержит информацию о товаре или услуге. Призывает выполнить целевое действие: оставить контакты, подписаться на рассылку, оформить заявку.

Главная страница

  1. «О нас»: краткое описание кафе-ресторана «Pleasure».

О нас

  1. «Интерьер»: показ интерьера при помощи слайдера.
    Слайдер – это специальный элемент веб-дизайна, представляющий собой блок определенной ширины. Их функция заключается в добавлении картинок в текст и более выгодный показ данных сайта. Описание того, какие атрибуты содержит в себе разработанный слайдер, представлено в таблице:
Атрибуты Описание
data-nav = "thumbs" По стандарту слайдер переключается по флажкам, которые находятся под изображением. Чтобы эти флажки заменить на изображения из слайдера, нужно прописать дополнительный атрибут со значением data-nav = "thumbs"
data-loop = "true" По стандарту слайдеры доходят до последнего изображения и останавливаются. Есть специальный атрибут, который запускает просмотр заново — data-loop = "true"
data-keyboard = "true" Позволяет листать слайды кнопками на клавиатуре

Интерьер

Мобильная версия главной страницы:

mobile-version-of-the-main-page.mp4

📑 Оглавление

Контакты и форма обратной связи

В начале раздела «Контакты» указаны адрес, телефон, e-mail и режим работы кафе-ресторана, а также была добавлена Google карта.
Стоит разобрать добавление Google карты на сайт поподробнее:

  1. Открыть сайт Google Maps;
  2. Ввести компанию на картах, нажать на «Поделиться»;
  3. Нажать «Встраивание карт» и выбрать размер из предложенных или выбрать «Другой размер» и указать свои параметры;
  4. Скопировать получившийся HTML-код и вставить его в код своего сайта в то место, где будет размещена карта.

Контакты

📑 Оглавление

Поля и их заполнение

Поля Обязательность заполнения Правила заполнения
Ваше имя Да
Ваш E-mail Да Формат: ***@yandex.ru
Пример: multiveb@yandex.ru
Тема письма Да
Сообщение Да
Проверочные символы Да Пример: zugioo

📑 Оглавление

Верстка формы обратной связи

Отправка сообщения на почту происходит через Simple Mail Transfer Protocol (SMTP) с помощью yandex. В файле настроек /config/web.php и добавляется настройка отправки почты в элемент массива components:

'components' => [
  'mailer' => [
    'class' => 'yii\swiftmailer\Mailer',
    'useFileTransport' => false,
    'transport' => [
      'class' => 'Swift_SmtpTransport',
      'host' => 'smtp.yandex.ru',
      'username' => 'ваша_почта@yandex.ru',
      'password' => 'ваш_пароль',
      'port' => '465',
      'encryption' => 'ssl',
    ],
  ],
  ...
],

Код для отправки введенных данных на почту, прописанный в вашей модели:

public function contact($email)
{
  if ($this->validate()) {
    Yii::$app->mailer->compose()
      ->setTo('***@yandex.ru') //Кому отправить
      ->setFrom(['***@yandex.ru' => $this->name]) //От кого
      ->setSubject($this->subject) //Тема сообщения
      ->setHtmlBody($this->body. '<br><br>' . $this->email) //Текст сообщения и отправивший
      ->send(); //Отправка сообщения

      return true;
  }

  return false;
}

Код для отправки введенных данных на почту, прописанный в вашем контроллере:

public function actionContact() //actionContact() - название контроллера
{
  $model = new ContactForm(); //ContactForm() - название модели
  if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
    if (true) {
      Yii::$app->session->setFlash('success', "Благодарим Вас за обращение к нам. Мы ответим вам как можно скорее.");
        
      return $this->refresh();
    } else {
      Yii::$app->session->setFlash('error', 'Внимание! Ваше письмо по каким-то причинам не отправлено! 
        Вы можите связаться с нами по телефону 8 (981) 942-53-40 или написать нам на почту cafe_restaurant_pleasure@email.com');
    }
  } 

  return $this->render('contact', ['model' => $model]); //contact - название вьюшки
}

После того, как клиент ввел корректные данные и нажал на кнопку «ОТПРАВИТЬ», всплывает Flash-сообщение «Благодарим Вас за обращение к нам. Мы ответим вам как можно скорее.». Все данные, которые ввел пользователь, отправляются на почту администратора.

Форма обратной связи с корректно заполненными полями: Корректо заполненная форма обратной связи

Оповещение об успешной отправке письма: Успешная отправка формы обратной связи

Мобильная версия страницы "Контакты":

mobile-version-of-the-feedback-form.mp4

Отправленное письмо:

Отправленное письмо

📑 Оглавление

Регистрация

Поля и их заполнение

Поля Обязательность заполнения Правила заполнения
Логин Да Логин должен быть уникальным (не должен совпадать с логиным из базы данных).
Пароль Да Пароль от 8 до 12 символов должен содержать хотя бы одну большую букву, одну маленькую букву и одну цифру.
Пример: Goodpassword7
Повторите пароль Да Введенные данные должны совпадать с данными из поля "Пароль".

📑 Оглавление

Верстка формы регистрации

Для того, чтобы пользователь смог зарегистрироваться, для начала нужно создать модель.
Модуль (Module) – предоставляет данные, позволяет работать с конкретной таблицей из базы данных и реагирует на команды контроллера, изменяя своё состояние.
Для занесения данных зарегистрированного пользователя в базу данных, требуется получить таблицу с именем user. Для этого используется статическая функция tableName, которая возвращает имя таблиц. Функция attributeLabels возвращает ассоциативный массив, в котором передаются имена для отображения в представлении.
Для более наглядного понимания безопасного заполнения полей данных информацией, стоит поподробнее описать функцию rules. Она проверяет является ли выбранное поле строкой, числом и т.д. Также в rules при желании можно написать собственные валидаторы, которые можно будет использовать для своих каких-либо проверок.

Валидатор Описание Для каких полей
required Поля обязательны для заполнения login, password, confirm_password
unique Проверка на уникальность login
match Проверка совпадения значения с заданным условием password
pattern Регулярное выражение, с которым должно совпадать входящее значение password
compare Проверка на совпадение confirm_password
compareAttribute Сравнение введенного значения со значением из таблицы confirm_password
message Сообщение/предупреждение login, password, confirm_password
namespace app\models;

use Yii;
use yii\base\Model;
use yii\db\ActiveRecord;
use app\models\User;

class RegistrationForm extends ActiveRecord {
  public static function tableName() {
    return 'user';
  }

  public function attributeLabels() {
    return [
      'login' => 'Логин',
      'password' => 'Пароль',
      'confirm_password' => 'Повторите пароль',
    ];
  }

  public $confirm_password;

  public function rules() {
    return [
      [['login', 'password', 'confirm_password'], 'required'],
      ['login', 'unique'],
      ['password', 'match', 'pattern' => '/^\S*(?=\S{8,12})(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[\d])\S*$/', 
        'message' => 'Пароль от 8 до 12 символов должен содержать хотя бы одну большую букву, одну маленькую букву и одну цифру'],
      ['confirm_password', 'compare', 'compareAttribute' => 'password', 'message' => 'Пароли не совпадают'],
    ];
  }

  public function registration() {
    if ($this->validate()) {
      $this->password = md5($this->password);
      $this->role = 2;

      if ($this->save(false)) {
        if (Yii::$app->user->login(User::findIdentity($this->id), 3600 * 24 * 30)) {
          return true;
        }
      }
    }

    return false;
  }
}

Далее в контроллере SiteController было реализовано действие actionRegistration.
Контроллер (Controller) – при запуске выполняет соответствующее действие, что обычно подразумевает создание соответствующих моделей и отображение необходимых представлений.
Действие (Action) – это метод класса контроллера, имя которого начинается на action.
В переменной $model при помощи new реализована связь с моделью RegistrationForm. Вызов $model->load() ищет подмассив, который имеет имя, которое должно быть у формы модели, а уже из этого правильно именованного подмассива извлекает атрибуты. Для того, чтобы получить параметры запроса, нужно использовать методы Yii::$app->request->post() компонента request. Вызов $model->registration() расписан в модели RegistrationForm. Для перенаправления на домашнюю страницу в контроллере наследнике \yii\base\Controller есть метод goHome(). Данный метод позволяет успешно зарегистрированному пользователю попасть сразу на главную страницу, а именно на страницу представления index.php в папке /views/site авторизированного пользователя.
Передача введенных и автоматически прописанных данных, а именно login, password, confirm_password, role происходит при помощи метода render, куда первым параметром поступает строка – название представления и информация, передаваемая представлению.
В модели RegistrationForm прописана функция registration, в которой проверяется валидность введенных данных при помощи метода $this->validate(). Для безопасного хранения и использования хэшированных паролей в базе данных используется md5. Если данных успешно прошли проверку на валидность, определяется id зарегистрированного пользователя, используя выражение Yii::$app->user->login(User::findIdentity($this->id)). Оно возвращает экземпляр класса идентификатора, представляющего текущего пользователя, вошедшего в систему.

//Регистрация пользователя
public function actionRegistration() {
  $model = new RegistrationForm();

  if ($model->load(Yii::$app->request->post()) && $model->registration()) { 
    return $this->goHome();
  } 

  return $this->render('registration', compact(['model']));
}

Наконец, представление.
Представление (View) – отвечает за отображение данных модели пользователю, зашедшему на страницу сайта, реагируя на изменения модели.
Представление содержит в себе ту информацию, которая передается ей в контроллере. Здесь осуществляется вёрстка данной страницы, и в места, где это нужно, вставляется информация из контроллера.
Для создания интерактивной HTML-формы используется виджет ActiveForm. Его следует описать поподробнее.
В контроллере передается экземпляр этой модели ($model) в представление для виджета ActiveForm, который генерирует форму. В вышеприведённом коде ActiveForm::begin() не только создаёт экземпляр формы, но также и знаменует её начало. Весь контент, расположенный между ActiveForm::begin() и ActiveForm::end(), будет завёрнут в HTML-тег <form>. Для создания в форме элемента с меткой и любой применимой валидацией с помощью JavaScript, вызывается ActiveForm::field(), который возвращает экземпляр yii\widgets\ActiveField. Дополнительные HTML-элементы можно добавить к форме, используя обычный HTML или методы из класса помощника Html, как это было сделано с помощью Html::submitButton().

<?php
  use yii\helpers\Html;
  use yii\bootstrap\ActiveForm;

  $this->title = 'Регистрация';
  $this->params['breadcrumbs'][] = $this->title;
?>
   
<div class = "site-registration">
  <div class = "admin-panel_name"><?= Html::encode($this->title) ?></div><br>

  <?php 
    $form = ActiveForm::begin([
      'id' => 'myform',
      'method' => 'post',
      'fieldConfig' => [
          'template' => '{label}{input}{error}',
      ],
    ]);

      echo $form->field($model, 'login')->textInput();
      echo $form->field($model, 'password')->passwordInput();
      echo $form->field($model, 'confirm_password')->passwordInput();
      echo "<br>";
      echo Html::submitButton("Зарегистрироваться", ['class' => 'btn btn-primary']);
    ActiveForm::end(); 
  ?>
</div>

Регистрация

Мобильная версия страницы "Регистрация":

mobile-version-of-the-registration-form.mp4

📑 Оглавление

Авторизация

Поля и их заполнение

Поля Обязательность заполнения Правила заполнения
Логин Да Введенные данные должны совпадать с данными из таблицы.
Пароль Да Введенные данные должны совпадать с данными из таблицы.
Запомнить меня Нет

📑 Оглавление

Верстка формы авторизации

Для того, чтобы доступ к системе имели только авторизированные пользователи, используются фильтры контроля доступа (ACF).
ACF – это фильтры, которые могут присоединяться к контроллеру или модулю как поведение.

public function behaviors()
{
  return [
    'access' => [
      'class' => AccessControl::className(),
      'only' => ['logout'],
      'rules' => [
        [
          'actions' => ['logout'],
          'allow' => true,
          'roles' => ['@'],
        ],
      ],
    ],
        
    'verbs' => [
      'class' => VerbFilter::className(),
      'actions' => [
        'logout' => ['post', 'get'],
      ],
    ],
  ];
}

Код выше показывает ACF фильтр, связанный с контроллером SiteController через поведение. Параметр only указывает, что фильтр ACF нужно применять только к действию logout (выйти из системы). Параметр rules задает правила доступа, которые означают следующее: разрешить аутентифицированным пользователям доступ к действию logout.
При попытке доступа к действию logout неавторизированного пользователя перенаправляет на форму авторизации, за которую отвечает метод действия actionLogin контроллера SiteController. Это действие проверяет, не является ли пользователь гостем. Если условие возвращает false, это значит, что пользователь авторизован и он попадает на главную страницу. Если возвращается true – создается экземпляр модели LoginForm, в нее загружаются данные и вызывается метод login(), который авторизует пользователя. Если данные загружены и метод login() вернул true, то пользователь переносится туда, откуда он пришел. В противном случае передается модель в вид login.

//Авторизация
public function actionLogin()
{
  if (!Yii::$app->user->isGuest) {
    return $this->goHome();
  }

  $model = new LoginForm();
  if ($model->load(Yii::$app->request->post()) && $model->login()) {
    return $this->goBack();
  }

  $model->password = '';
  return $this->render('login', [
    'model' => $model,
  ]);
}

Метод login() проверяет данные на соответствие правилам, описанных в модели. Здесь вызывается метод validatePassword(), который при отсутствии ошибок создает объект User, вызывая метод getUser(). Метод проверяет, не авторизован ли пользователь. Если не авторизован – вызывается статический метод findByUsername() с переданным ему введенным именем пользователя класса User.
Модель User реализует интерфейс yii\web\IdentityInterface. В данной моделе должно быть объявлено семь методов:

Методы Описание
findIdentity() Данный метод находит экземпляр identity class, используя ID пользователя.
findIdentityByAccessToken() Данный метод находит экземпляр identity class, используя токен доступа. Метод используется, когда требуется аутентифицировать пользователя только по секретному токену.
findByUsername() Данный метод находит пользователя по его логину.
getId() Данный метод возвращает ID пользователя, представленного данным экземпляром identity.
getAuthKey() Данный метод возвращает ключ, используемый для основанной на cookie аутентификации. Ключ сохраняется в аутентификационной cookie и позже сравнивается с версией, находящейся на сервере, чтобы удостоверится, что аутентификационная cookie верная.
validateAuthKey() Данный метод реализует логику проверки ключа для основанной на cookie аутентификации.
validatePassword() Данный метод сравнивает хранящийся в базе данных пароль с тем, что ввел пользователь.

А так же объявляется метод tableName(), который укажет, что модель User будет взаимодействовать с таблицей user.

namespace app\models;
use yii\db\ActiveRecord;

class User extends ActiveRecord implements \yii\web\IdentityInterface
{
  public static function tableName() {
    return 'user';
  }

  public static function findIdentity($id)
  {
    return static::findOne($id);
  }

  public static function findIdentityByAccessToken($token, $type = null)
  {

  }

  public static function findByUsername($login)
  {
    return static::findOne(['login' => $login]);
  }

  public function getId()
  {
    return $this->id;
  }

  public function getAuthKey()
  {
    return $this->auth_key;
  }

  public function validateAuthKey($authKey)
  {
    return $this->auth_key === $authKey;
  }

  public function validatePassword($password)
  {
    return $this->password === md5($password);
  }
}

Авторизация

Мобильная версия страницы "Авторизация":

mobile-version-of-the-authorization-form.mp4

📑 Оглавление

Размещение сайта на хостинге

Хостинг – это комплекс услуг, которые позволяют разместить сайт или другие данные в сети Интернет. Обычно под фразой "хостинг для сайта" подразумевают место и мощности на сервере (специальном компьютере с круглосуточным подключением к сети). Таблица сравнений популярных хостинг-компаний за май 2022 года (Данные были взяты с сайтов https://ru.hostings.info и https://hostinghub.ru):

Хостинг Оценка Количество клиентов Стоимость от, р. Поддержка Тестовый период, дн.
timeweb 9.5/10 210000 179 PHP, Python, HTTP/2, Memcached 10
спринт ХОСТ 9.5/10 358669 133 PHP, Python, Node.js, HTTP/2, Memcached, Perl, Sphinx 30
Beget 9.3/10 165000 169 PHP, Python, HTTP/2, Memcached, Redis, Perl, Sphinx 30
FORNEX 9.0/10 110000 75 PHP, Python, Node.js, Memcached, Ruby 7
REG.RU 9.0/10 2200000 152 PHP, Python, HTTP/2, Perl 14

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

  1. Выбор хостинга;
  2. Выбор и регистрация домена;
  3. Загрузка сайта на хостинг:
    3.1. Добавление архива, который содержит в себе все файлы сайта;
    3.2. Импорт SQL-файла в PhpMyAdmin.

📑 Оглавление

Ссылка на разработанный программный продукт (на данный момент сайт расположен на хостинге "спринт ХОСТ"): f0635336.xsph.ru