Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ketrindorofeeva/togolden
Сайт компаний
https://github.com/ketrindorofeeva/togolden
bootstrap4 css html javascript mysql php yii2
Last synced: about 18 hours ago
JSON representation
Сайт компаний
- Host: GitHub
- URL: https://github.com/ketrindorofeeva/togolden
- Owner: KetrinDorofeeva
- License: bsd-3-clause
- Created: 2023-02-25T12:32:50.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2023-05-05T08:14:46.000Z (over 1 year ago)
- Last Synced: 2024-09-23T22:02:28.771Z (4 days ago)
- Topics: bootstrap4, css, html, javascript, mysql, php, yii2
- Language: PHP
- Homepage:
- Size: 5.88 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# togolden
Технологии разработки
Языки программирования
Фреймворки
База данных
##
Оглавление
- База данных
- Yii2-framework
- Установка Yii2-фреймворка
- Настройка ЧПУ
- Реализация программного продукта
- Компании
- Регистрация
- Авторизация
- Страница компании
- Добавить компанию
- Редактировать компанию
- Удалить компанию
- Мои компании
- Личный кабинет пользователя
- Редактировать информацию о пользователе_________________________________________________________________________________________________________________________________________________________________
##База данных
![ER-диаграмма базы данных](https://github.com/ketrindorofeeva/togolden/raw/main/for-readme/database-design.png)
![Таблицы и поля базы данных](https://github.com/ketrindorofeeva/togolden/raw/main/for-readme/database-tables-and-fields.png)
:bookmark_tabs: Оглавление##
Yii2-framework
Для начала нужно [установить и настроить OpenServer](https://timeweb.com/ru/community/articles/ustanovka-i-nastroyka-openserver)
**OpenServer** — готовая платформа для автоматизации работы мини-хостинга.###
Установка Yii2-фреймворка
1. **Установка при помощи Composer**
**Composer** - это пакетный менеджер уровня приложений для языка программирования PHP, который предоставляет средства по управлению зависимостями в PHP-приложении.
Для того, чтобы установить Yii2-фреймворк, нужно открыть консоль в OpenServer:
И ввести соответствующую команду:
```php
cd domains
composer create-project yiisoft/yii2-app-basic basic
//composer create-project yiisoft/yii2-app-версия придуманное_название_проекта
```
Эта команда устанавливает последнюю стабильную версию Yii в директорию ```basic```. Если хотите, можете выбрать другое имя директории.2. Установка из архива
Установка Yii из архива состоит из трёх шагов:
- Скачайте архив с [yiiframework.com](https://www.yiiframework.com/download);
- Создать папку в ```domains```;
- Загрузить в папку архив;
- Распаковать архив;
- Зайти в папку ```/config/web.php``` добавьте секретный ключ в значение cookieValidationKey (при установке через Composer это происходит автоматически):
```php
// !!! Напишите секретный ключ в поле (если оно пустое) - это требуется для проверки файлов cookie
'cookieValidationKey' => 'Введите_здесь_секретный_ключ_(произвольный_набор_символов)',
```
:bookmark_tabs: Оглавление###
Настройка ЧПУ
**ЧПУ** – красивые адреса, ставшие стандартом в веб-разработке.
Фреймворк Yii2 из коробки не имеет настроенных ЧПУ, но исправить это крайне легко. По умолчанию сразу после установки фреймворка для доступа к главной странице необходимо обратиться к папке ```web```, в которой и лежит публичная часть Yii2 приложения. Для доступа к главной странице нужно набрать адрес «http://*название_проекта*/web/».
От папки ```web``` можно легко избавиться с помощью файлов ```.htaccess```.
```.htaccess``` в корне приложения:
```php
RewriteEngine on
RewriteRule ^(.+)?$ /web/$1
```
```.htaccess``` в папке ```web```:
```php
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``` необходимый код:
```php
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
],
],
```
В элемент ```request``` массива ```components``` нужно добавить строчку ```'baseUrl' => ' '```:
```php
'components' => [
'request' => [
'cookieValidationKey' => 'произвольный_код',
'baseUrl' => '',
],
...
],
```
Для связи проекта с базой данных в файле ```/config/db.php``` прописываются ```dbname```, ```username``` и ```password```:
```php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=название_базы_данных',
'username' => 'логин_от_PhpMyAdmin',
'password' => 'пароль_от_PhpMyAdmin',
'charset' => 'utf8',
];
```
:bookmark_tabs: Оглавление##
Реализация программного продукта
###Компании
В зависимости от того, авторизован ли пользователь, на странице компаний отображаются определенные элементы.
Страница компаний, как гостя, так и авторизованного пользователя, включает в себя:
1) По 6 карточек компаний на каждой странице.
Каждая карточка имеет информацию: название компании, адрес, телефон и генеральный директор.
2) Пагинация.Контроллер ```SiteController``` действие ```Index```:
```php
use app\models\Companies;
use yii\data\Pagination;//Компании
public function actionIndex()
{
$query = Companies::find();
$pages = new Pagination(['totalCount' => $query->count(), 'pageSize' => 6]);
$model = $query->offset($pages->offset)->limit($pages->limit)->orderBy(['id' => SORT_DESC])->all();return $this->render('index', compact('model', 'pages'));
}
```Модуль ```Companies```:
```php
namespace app\models;use Yii;
class Companies extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'companies';
}public function rules()
{
return [
['name', 'required', 'message' => 'Введите название вашей компании!'],
['inn', 'required', 'message' => 'Введите ИНН вашей компании!'],
[['inn'], 'integer'],
['inn', 'string', 'min' => 10, 'max' => 10],
['general_information', 'required', 'message' => 'Введите общую информацию вашей компании!'],
['general_manager', 'required', 'message' => 'Введите генерального директора вашей компании!'],
['address', 'required', 'message' => 'Введите адрес вашей компании!'],
['phone', 'required', 'message' => 'Введите телефон вашей компании!'],
[['name', 'general_manager', 'phone'], 'string', 'max' => 255],
];
}public function attributeLabels()
{
return [
'name' => 'Название',
'inn' => 'ИНН',
'general_information' => 'Общая информация',
'general_manager' => 'Генеральный директор',
'address' => 'Адрес',
'phone' => 'Телефон',
];
}//Связь комментария с компанией
public function getComments()
{
return $this->hasMany(Comments::class, ['id_company' => 'id']);
}
}
```Представление ```index```:
```php
title = 'Компании';
?>
id'>";
echo "" . $company->name . "
";
echo "Адрес: " . $company->address . "
";
echo "Телефон: " . $company->phone . "
";
echo "Генеральный директор: " . $company->general_manager;
echo "";if (!Yii::$app->user->isGuest && \Yii::$app->user->identity->id == $company->id_user) {
echo "" .";
"" . Html::a(Html::img('@web/img/pencil-fill.svg'), ['update', 'id' => $company->id]) . "" .Html::a(Html::img('@web/img/trash-fill.svg'), ['delete', 'id' => $company->id], [
'data' => [
'confirm' => 'Вы уверены, что хотите удалить эту компанию?',
'method' => 'post',
]
]) .
"
}
?>
user->isGuest) {
echo Html::a('Новая компания', ['create'], ['class' => 'btn btn-success']);
}
?>
= LinkPager::widget([
'pagination' => $pages,
]);
?>
```Десктопная версия (гость):
Мобильная версия (гость):
https://user-images.githubusercontent.com/93386515/221585366-692c3b2c-8b94-4671-a42f-ec39e3a0e31f.mp4
Авторизованный пользователь на странице компаний имеет возможность: добавлять компании, а также редактировать и удалять созданные им компании. Доступны страницы "Мои компании" и раздел личной страницы пользователя, включающий в себя аватар и логин пользователя, при нажатии на которые всплывает выпадающий список со страницей "Профиль" и кнопкой "Выйти".
Десктопная версия (пользователь):Мобильная версия (пользователь):
https://user-images.githubusercontent.com/93386515/226163379-9ab07e45-4efe-4115-858f-8cecf81cd6d0.mp4
:bookmark_tabs: Оглавление###
Регистрация
Поля и их заполнение:
Поля
Обязательность заполнения
Правила заполнения
Фамилия
Да
Имя
Да
Отчество
Нет
Пол
Да
Две радиокнопки ("Мужчина" и "Женщина").
Дата рождения
Да
1) Пользователь должен быть старше 18 лет;
2) Нельзя выбрать дату больше текущей.
Формат даты рождения: гггг-мм-дд
Пример: 2023-05-22
Телефон
Нет
Формат телефона должен быть: +7 (XXX) XXX-XX-XX
Пример: +7 (981) 942-53-40
Да
Значение Email должно быть правильным email адресом.
Пример: [email protected]
Местоположение
Да
При вводе местоположения всплывают текстовые подсказки.
Краткое описание
Нет
Логин
Да
Логин должен быть уникальным (не должен совпадать с логиным из базы данных).
Пароль
Да
Пароль от 8 до 12 символов должен содержать хотя бы одну большую букву, одну маленькую букву и одну цифру.
Пример: Goodpassword7
Повторите пароль
Да
Введенные данные должны совпадать с данными из поля "Пароль".
Для того, чтобы пользователь смог зарегистрироваться, для начала нужно создать модель.
**Модуль (Module)** – предоставляет данные, позволяет работать с конкретной таблицей из базы данных и реагирует на команды контроллера, изменяя своё состояние.
Для занесения данных зарегистрированного пользователя в базу данных, требуется получить таблицу с именем ``user``. Для этого используется статическая функция ``tableName``, которая возвращает имя таблиц. Функция ``attributeLabels`` возвращает ассоциативный массив, в котором передаются имена для отображения в представлении.
Для более наглядного понимания безопасного заполнения полей данных информацией, стоит поподробнее описать функцию ``rules``. Она проверяет является ли выбранное поле строкой, числом и т.д. Также в ``rules`` при желании можно написать собственные валидаторы, которые можно будет использовать для своих каких-либо проверок.
Валидатор
Описание
Для каких полей
required
Поля обязательны для заполнения
surname, name, gender, date_birth, email, address, username, password, confirm_password
safe
Атрибут безопасен для добавления в базу данных
middle_name, phone, description
unique
Проверка на уникальность
username
match
Проверка совпадения значения с заданным условием
password
pattern
Регулярное выражение, с которым должно совпадать входящее значение
password
compare
Проверка на совпадение
confirm_password
compareAttribute
Сравнение введенного значения со значением из таблицы
confirm_password
message
Сообщение/предупреждение
password, confirm_password
Модуль ```RegistrationForm```:
```php
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 [
'avatar' => 'Аватар',
'surname' => 'Фамилия',
'name' => 'Имя',
'middle_name' => 'Отчество',
'gender' => 'Пол',
'date_birth' => 'Дата рождения',
'phone' => 'Телефон',
'email' => 'Email',
'address' => 'Местоположение',
'description' => 'Краткое описание',
'username' => 'Логин',
'password' => 'Пароль',
'confirm_password' => 'Повторите пароль',
];
}public $confirm_password;
public function rules() {
return [
[['surname', 'name', 'gender', 'date_birth', 'email', 'address', 'username', 'password', 'confirm_password'], 'required'],
[['middle_name', 'phone', 'description'], 'safe'],
['email', 'email'],
['username', '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->avatar = "avatars/null_user.png";
$this->registration_date = date("Y-m-d");
$this->password = md5($this->password);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\web\Controller`` есть метод ``goHome()``. Данный метод позволяет успешно зарегистрированному пользователю попасть сразу на главную страницу, а именно на страницу представления ```index.php``` в папке ```/views/site``` авторизированного пользователя.
Передача введенных и автоматически прописанных данных, а именно ``username, password, confirm_password`` происходит при помощи метода ``render``, куда первым параметром поступает строка – название представления и информация, передаваемая представлению.
В модели ``RegistrationForm`` прописана функция ``registration``, в которой проверяется валидность введенных данных при помощи метода ``$this->validate()``. Для безопасного хранения и использования хэшированных паролей в базе данных используется ``md5``. Если данных успешно прошли проверку на валидность, определяется ``id`` зарегистрированного пользователя, используя выражение ``Yii::$app->user->login(User::findIdentity($this->id))``. Оно возвращает экземпляр класса идентификатора, представляющего текущего пользователя, вошедшего в систему.
Контроллер ```SiteController``` действие ```Registration```:
```php
use app\models\RegistrationForm;//Регистрация
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-тег ````. Для создания в форме элемента с меткой и любой применимой валидацией с помощью JavaScript, вызывается ``ActiveForm::field()``, который возвращает экземпляр ``yii\bootstrap4\ActiveField``. Дополнительные HTML-элементы можно добавить к форме, используя обычный HTML или методы из класса помощника Html, как это было сделано с помощью ``Html::submitButton()``.
Также присутствует виджет ```DatePicker```. ```DatePicker``` – это поле отображения и ввода даты, оно выглядит так же, как выпадающий календарь. Документация по [DatePicker](https://demos.krajee.com/widget-details/datepicker).
Помимо этого, дополнительно настроена связь поля ввода местоположения с API Яндекс.Карт. Данную настройку следует описать поподробнее.
Создаем файл представления ```registration.php``` в папке ```/views/site```, в который добавляется код:
```js```
Затем создается файл ```script.js``` в папке ```/web/js```, в который добавляется код:
```js
ymaps.ready(init);function init() {
let suggestView = new ymaps.SuggestView('registrationform-address');
}
```В котором ```'registrationform-address'``` является ```id``` поля ввода местоположения.
Представление ```registration```:```php
title = 'Регистрация';
$this->params['breadcrumbs'][] = $this->title;
?>
= Html::encode($this->title) ?>
'myform',
'method' => 'post',
]);echo $form->field($model, 'surname', ['template' => '{label} *{input}{error}'])->textInput();
echo $form->field($model, 'name', ['template' => '{label} *{input}{error}'])->textInput();
echo $form->field($model, 'middle_name', ['template' => '{label}{input}{error}'])->textInput();
echo $form->field($model, 'gender', ['template' => '{label} *{input}{error}'])->radioList([1 => 'Мужчина', 2 => 'Женщина']);echo $form->field($model, 'date_birth', ['template' => '{label} *{input}{error}'])->widget(DatePicker::classname(), [
'options' => [
'placeholder' => 'гггг-мм-дд'
],
'pluginOptions' => [
'format' => 'yyyy-mm-dd',
'endDate' => '-18y'
]
]);echo $form->field($model, 'phone')->widget(\yii\widgets\MaskedInput::className(), ['mask' => '+7 (999) 999-99-99'])->textInput();
echo $form->field($model, 'email', ['template' => '{label} *{input}{error}'])->textInput();
echo $form->field($model, 'address', ['template' => '{label} *{input}{error}'])->textInput();
echo $form->field($model, 'description')->textarea();
echo $form->field($model, 'username', ['template' => '{label} *{input}{error}'])->textInput();
echo $form->field($model, 'password', ['template' => '{label} *{input}{error}'])->passwordInput();
echo $form->field($model, 'confirm_password', ['template' => '{label} *{input}{error}'])->passwordInput();
echo "
";
echo Html::submitButton("Зарегистрироваться", ['class' => 'btn btn-success']);
ActiveForm::end();
?>```
https://user-images.githubusercontent.com/93386515/226170009-55e2e7ec-a91e-49b6-b874-6c26420726f8.mp4
:bookmark_tabs: Оглавление###
Авторизация
Поля и их заполнение:
Поля
Обязательность заполнения
Правила заполнения
Логин
Да
Введенные данные должны совпадать с данными из таблицы.
Пароль
Да
Введенные данные должны совпадать с данными из таблицы.
Запомнить меня
Нет
Для того, чтобы доступ к системе имели только авторизированные пользователи, используются фильтры контроля доступа (ACF).
**ACF** – это фильтры, которые могут присоединяться к контроллеру или модулю как поведение.Контроллер ```SiteController``` в папке ```/controllers```:
```php
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'my', 'create', 'update', 'delete'],
'rules' => [
[
'actions' => ['logout', 'my', 'create', 'update', 'delete'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post', 'get'],
],
],
];
}
```Код выше показывает ACF фильтр, связанный с контроллером ```SiteController``` через поведение. Параметр ```only``` указывает, что фильтр ACF нужно применять только к действиям ```logout, my, create, update, delete```. Параметр ```rules``` задает правила доступа, которые означают следующее: разрешить аутентифицированным пользователям доступ к действиям ```logout, my, create, update, delete```.
При попытке доступа к действиям ```logout, my, create, update, delete``` неавторизированного пользователя перенаправляет на форму авторизации, за которую отвечает метод действия ```actionLogin``` контроллера ```SiteController```. Это действие проверяет, не является ли пользователь гостем. Если условие возвращает ```false```, это значит, что пользователь авторизован и он попадает на главную страницу. Если возвращается ```true``` – создается экземпляр модели ```LoginForm```, в нее загружаются данные и вызывается метод ```login()```, который авторизует пользователя. Если данные загружены и метод ```login()``` вернул ```true```, то пользователь переносится туда, откуда он пришел. В противном случае, передается модель в вид ```login```.Контроллер ```SiteController``` действие ```Login```:
```php
use app\models\LoginForm;//Авторизация
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', compact('model'));
}
```Контроллер ```SiteController``` действие ```Logout``` (выход пользователя из личного кабинета):
```php
//Выход из личного кабинета пользователя
public function actionLogout()
{
Yii::$app->user->logout();return $this->goHome();
}```
Метод ```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```.
Модуль ```User```:
```php
namespace app\models;
use yii\db\ActiveRecord;class User extends ActiveRecord implements \yii\web\IdentityInterface
{
public static function findIdentity($id)
{
return static::findOne($id);
}public static function findIdentityByAccessToken($token, $type = null)
{}
public static function findByUsername($username)
{
return static::findOne(['username' => $username]);
}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);
}
}
```Представление ```login```:
```php
title = 'Войти';
$this->params['breadcrumbs'][] = $this->title;
?>
= Html::encode($this->title) ?>
'login-form',
'fieldConfig' => [
'template' => '{label}{input}{error}',
],
]);echo $form->field($model, 'username')->textInput();
echo $form->field($model, 'password')->passwordInput();
echo $form->field($model, 'rememberMe')->checkbox();
echo "
";
echo Html::submitButton("Войти", ['class' => 'btn btn-success']);
?>
```https://user-images.githubusercontent.com/93386515/226170310-a9e01475-3455-4522-96e3-5461bd3da179.mp4
:bookmark_tabs: Оглавление###
Страница компании
В зависимости от того, авторизован ли пользователь, на странице компании отображаются определенные элементы.
Страница компании, как гостя, так и авторизованного пользователя, включает в себя расширенную информацию. Каждая компания имеет информацию: название компании, ИНН, общая информация, генеральный директор, адрес и телефон.Авторизованный пользователь имеет возможность:
1) К каждому полю каждой компании оставить комментарии;
2) Оставить комментарий к компании целиком;
3) Видеть комментарии других пользователей.Каждый комментарий включает в себя: время добавление, логин пользователя и текст комментария.
Реализована интерактивность добавления комментария (поле ввода по умолчанию скрыто, открывается по желанию пользователя, закрывается после сохранения). При добавлении нового комментария на экране появляется оповещение, в котором сказано, что комментарий успешно добавлен.Контроллер ```SiteController``` действие ```View```:
```php
use app\models\Companies;
use app\models\Comments;
//Страница компании
public function actionView($id)
{
$model = Companies::findOne(['id' => $id]);
$model_c = Comments::find($id)->where(['=', 'id_company', $id])->orderBy(['time_comment' => SORT_DESC])->all();//Добавить комментарий
$model_cr = new Comments();if ($model_cr->load(Yii::$app->request->post())) {
$model_cr->id_company = $id;
$model_cr->id_user = Yii::$app->user->identity->id;
$model_cr->time_comment = date('Y-m-d H:i:s');Yii::$app->session->setFlash('success', "Комментарий успешно добавлен");
if ($model_cr->save(false)) {
return $this->redirect(['view', 'id' => $id]);
}
}return $this->render('view', compact('model', 'model_c', 'model_cr'));
}
```Модуль ```Companies``` указан в подразделе Компании.
Модуль ```Comments```:
```php
namespace app\models;use Yii;
class Comments extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'comments';
}public function rules()
{
return [
[['id_company', 'id_user', 'time_comment'], 'required'],
[['name_comment', 'inn_comment', 'general_information_comment', 'general_manager_comment', 'address_comment', 'phone_comment', 'general_comment'], 'string'],
[['time_comment'], 'safe'],
[['id_company'], 'exist', 'skipOnError' => true, 'targetClass' => Companies::class, 'targetAttribute' => ['id_company' => 'id']],
[['id_user'], 'exist', 'skipOnError' => true, 'targetClass' => User::class, 'targetAttribute' => ['id_user' => 'id']],
];
}public function attributeLabels()
{
return [
'name_comment' => '',
'inn_comment' => '',
'general_information_comment' => '',
'general_manager_comment' => '',
'address_comment' => '',
'phone_comment' => '',
'general_comment' => '',
];
}//Связь комментария с компанией
public function getCompany()
{
return $this->hasOne(Companies::class, ['id' => 'id_company']);
}//Связь комментария с пользователем
public function getUser()
{
return $this->hasOne(User::class, ['id' => 'id_user']);
}
}
```Представление ```view```:
```php
title = $model->name;
if (!Yii::$app->user->isGuest) {
$this->params['breadcrumbs'][] = ['label' => 'Мои компании', 'url' => ['my']];
}
$this->params['breadcrumbs'][] = $this->title;
?>.alert-success.alert.alert-dismissible {
margin-left: 0px;
}
=
DetailView::widget([
'model' => $model,
'attributes' => [
'name',
],
]);
?>
user->isGuest) { ?>
Прокомментировать
user->isGuest) { ?>
name_comment !== NULL) {
echo "" . $comment->time_comment . "" .
"" . $comment->user->username . ":" . "" .
"" . $comment->name_comment . "
";
}
}
?>
=
DetailView::widget([
'model' => $model,
'attributes' => [
'inn',
],
]);
?>
user->isGuest) { ?>
Прокомментировать
user->isGuest) { ?>
inn_comment !== NULL) {
echo "" . $comment->time_comment . "" .
"" . $comment->user->username . ":" . "" .
"" . $comment->inn_comment . "
";
}
}
?>
'add_in_n_comment',
'method' => 'post',
]);echo $form->field($model_cr, 'inn_comment')->textInput();
echo Html::submitButton('Добавить комментарий', ['class' => 'btn btn-success']);
ActiveForm::end(); ?>
=
DetailView::widget([
'model' => $model,
'attributes' => [
'general_information',
],
]);
?>
user->isGuest) { ?>
Прокомментировать
user->isGuest) { ?>
general_information_comment !== NULL) {
echo "" . $comment->time_comment . "" .
"" . $comment->user->username . ":" . "" .
"" . $comment->general_information_comment . "
";
}
}
?>
'add_gen_inf_comment',
'method' => 'post',
]);echo $form->field($model_cr, 'general_information_comment')->textInput();
echo Html::submitButton('Добавить комментарий', ['class' => 'btn btn-success']);
ActiveForm::end(); ?>
=
DetailView::widget([
'model' => $model,
'attributes' => [
'general_manager',
],
]);
?>
user->isGuest) { ?>
Прокомментировать
user->isGuest) { ?>
general_manager_comment !== NULL) {
echo "" . $comment->time_comment . "" .
"" . $comment->user->username . ":" . "" .
"" . $comment->general_manager_comment . "
";
}
}
?>
'add_gen_man_comment',
'method' => 'post',
]);echo $form->field($model_cr, 'general_manager_comment')->textInput();
echo Html::submitButton('Добавить комментарий', ['class' => 'btn btn-success']);
ActiveForm::end(); ?>
=
DetailView::widget([
'model' => $model,
'attributes' => [
'address',
],
]);
?>
user->isGuest) { ?>
Прокомментировать
user->isGuest) { ?>
address_comment !== NULL) {
echo "" . $comment->time_comment . "" .
"" . $comment->user->username . ":" . "" .
"" . $comment->address_comment . "
";
}
}
?>
'add_addr_comment',
'method' => 'post',
]);echo $form->field($model_cr, 'address_comment')->textInput();
echo Html::submitButton('Добавить комментарий', ['class' => 'btn btn-success']);
ActiveForm::end(); ?>
=
DetailView::widget([
'model' => $model,
'attributes' => [
'phone',
],
]);
?>
user->isGuest) { ?>
Прокомментировать
user->isGuest) { ?>
phone_comment !== NULL) {
echo "" . $comment->time_comment . "" .
"" . $comment->user->username . ":" . "" .
"" . $comment->phone_comment . "
";
}
}
?>
'add_ph_comment',
'method' => 'post',
]);echo $form->field($model_cr, 'phone_comment')->textInput();
echo Html::submitButton('Добавить комментарий', ['class' => 'btn btn-success']);
ActiveForm::end(); ?>
user->isGuest) { ?>
Общие комментарии
Прокомментировать компанию
general_comment !== NULL) {
echo "";";
echo "
" . $comment->time_comment . "" .
"" . $comment->user->username . ":" . "" .
"" . $comment->general_comment . "";
echo "
}
} ?>
'add_gen_comment',
'method' => 'post',
]);echo $form->field($model_cr, 'general_comment')->textarea(['rows' => 6]);
echo Html::submitButton('Добавить комментарий', ['class' => 'btn btn-success']);
ActiveForm::end(); ?>
```Создаем файл ```script.js``` в папке ```/web/js```:
```js
//При клике появляется поле для ввода комментария и кнопка
//Название
function viewNameCom() {
document.getElementById("add_name_comment").style.display = "block";
};//ИНН
function viewAddInnCom() {
document.getElementById("add_inn_comment").style.display = "block";
}//Общая информация
function viewGenInfCom() {
document.getElementById("add_general_information_comment").style.display = "block";
};//Генеральный директор
function viewGenManCom() {
document.getElementById("add_general_manager_comment").style.display = "block";
};//Адрес
function viewAddressCom() {
document.getElementById("add_address_comment").style.display = "block";
};//Телефон
function viewPhoneCom() {
document.getElementById("add_phone_comment").style.display = "block";
};//Общие комментарии
function viewGenCom() {
document.getElementById("add_general_comment").style.display = "block";
};
```Десктопная версия (гость):
Десктопная версия (пользователь):
https://user-images.githubusercontent.com/93386515/226183660-c364845d-ebd6-4b30-b0fd-525c817afbb7.mp4
:bookmark_tabs: Оглавление###
Добавить компанию
Модуль ```Companies``` указан в подразделе Компании.Поля для заполнения:
1) Название;
2) ИНН;
3) Общая информация;
4) Генеральный директор;
5) Адрес;
6) Телефон.При добавлении новой компании на экране появляется оповещение, в котором сказано, что компания успешно добавлена.
Контроллер ```SiteController``` действие ```Create```:
```php
use app\models\Companies;//Добавить новую компанию
public function actionCreate()
{
$model = new Companies();if ($this->request->isPost) {
if ($model->load($this->request->post())) {
$model->id_user = Yii::$app->user->identity->id;Yii::$app->session->setFlash('success', "Новая компания успешно добавлена");
if ($model->save()) {
return $this->redirect(['index', 'id' => $model->id]);
}
}
} else {
$model->loadDefaultValues();
}return $this->render('create', compact('model'));
}
```Представление ```create```:
```php
title = 'Новая компания';
$this->params['breadcrumbs'][] = ['label' => 'Мои компании', 'url' => ['my']];
$this->params['breadcrumbs'][] = $this->title;
?>
= Html::encode($this->title) ?>
= $this->render('_form', ['model' => $model]) ?>
```Представление ```_form```:
```php
field($model, 'name')->textInput();
echo $form->field($model, 'inn')->textInput();
echo $form->field($model, 'general_information')->textarea(['rows' => 6]);
echo $form->field($model, 'general_manager')->textInput();
echo $form->field($model, 'address')->textarea(['rows' => 6]);
echo $form->field($model, 'phone')->textInput();
?>
= Html::submitButton('Сохранить', ['class' => 'btn btn-success']) ?>
```
Десктопная версия:
Мобильная версия:
https://user-images.githubusercontent.com/93386515/221591283-70506e7c-596f-4c3c-8f08-fb38a7208f8d.mp4
:bookmark_tabs: Оглавление###
Редактировать компанию
Модуль ```Companies``` указан в подразделе Компании.Поля для редактирования:
1) Название;
2) ИНН;
3) Общая информация;
4) Генеральный директор;
5) Адрес;
6) Телефон.При редактировании компании на экране появляется оповещение, в котором сказано, что компания успешно обновлена.
Контроллер ```SiteController``` действие ```Update```:
```php
use app\models\Companies;//Редактировать компанию
public function actionUpdate($id)
{
$model = Companies::findOne($id);if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) {
Yii::$app->session->setFlash('success', "Компания успешно обновлена");return $this->redirect(['view', 'id' => $model->id]);
}return $this->render('update', compact('model'));
}
```Представление ```update```:
```php
title = 'Редактировать компанию ' . $model->name;
$this->params['breadcrumbs'][] = ['label' => 'Мои компании', 'url' => ['my']];
$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]];
$this->params['breadcrumbs'][] = 'Редактировать компанию ' . $model->name;
?>
= Html::encode($this->title) ?>
= $this->render('_form', ['model' => $model]) ?>
```Представление ```_form```:
```php
field($model, 'name')->textInput();
echo $form->field($model, 'inn')->textInput();
echo $form->field($model, 'general_information')->textarea(['rows' => 6]);
echo $form->field($model, 'general_manager')->textInput();
echo $form->field($model, 'address')->textarea(['rows' => 6]);
echo $form->field($model, 'phone')->textInput();
?>
= Html::submitButton('Сохранить', ['class' => 'btn btn-success']) ?>
```Десктопная версия:
Мобильная версия:
https://user-images.githubusercontent.com/93386515/222395436-ad1d4ceb-d96b-456e-893c-eaaf9b65eb57.mp4
:bookmark_tabs: Оглавление###
Удалить компанию
При удалении компании на экране появляется оповещение, в котором сказано, что компания успешно удалена.Контроллер ```SiteController``` действие ```Delete```:
```php
use app\models\Companies;//Удалить компанию
public function actionDelete($id)
{
$model = Companies::findOne($id);Companies::findOne($id)->delete();
Yii::$app->session->setFlash('success', "Компания успешно удалена");return $this->redirect(['/site/index']);
return $this->render(compact('model'));
}
```Модуль ```Companies``` указан в подразделе Компании.
Изображение корзины, при нажатии на которую удаляется компания (и относящиеся к ней комментарии), находится в представлении ```index```, которое указано в подразделе Компании.Десктопная версия:
Мобильная версия:
https://user-images.githubusercontent.com/93386515/222397061-e0570ffa-2dc1-4afe-b134-88c7e5f61136.mp4
:bookmark_tabs: Оглавление###
Мои компании
В данном разделе находятся компании, которые принадлежат конкретному пользователю. Пользователь может добавлять, редактировать и удалять компании, а также, кликнув по названию, перейти на страницу компании с комментариями.
Поля каждой компании:
1) Название;
2) ИНН;
3) Общая информация;
4) Генеральный директор;
5) Адрес;
6) Телефон.Контроллер ```SiteController``` действие ```My```:
```php
use app\models\CompaniesSearch;
//Мои компании
public function actionMy()
{
$searchModel = new CompaniesSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);return $this->render('my', compact('searchModel', 'dataProvider'));
}
```Модуль ```CompaniesSearch```:
```php
namespace app\models;use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\Companies;class CompaniesSearch extends Companies
{
public function rules()
{
return [
[['id', 'id_user', 'inn'], 'integer'],
[['name', 'general_information', 'general_manager', 'address', 'phone'], 'safe'],
];
}public function scenarios()
{
return Model::scenarios();
}public function search($params)
{
$query = Companies::find()->where(['id_user' => \Yii::$app->user->identity->id]);$dataProvider = new ActiveDataProvider([
'query' => $query,
]);$this->load($params);
if (!$this->validate()) {
return $dataProvider;
}$query->andFilterWhere([
'id' => $this->id,
'id_user' => $this->id_user,
'inn' => $this->inn,
]);$query->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'general_information', $this->general_information])
->andFilterWhere(['like', 'general_manager', $this->general_manager])
->andFilterWhere(['like', 'address', $this->address])
->andFilterWhere(['like', 'phone', $this->phone])
->orderBy(['id' => SORT_DESC]);return $dataProvider;
}
}
```Представление ```my```:
```php
title = 'Главная';
$this->params['breadcrumbs'][] = 'Мои компании';
?>
Мои компании
'btn btn-success']);
?>
= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
[
'attribute' => 'name',
'format' => 'raw',
'value' => function($data) {
return '' . $data->name . '';
}
],
'inn',
'general_information',
'general_manager',
'address',
'phone',['class' => 'yii\grid\ActionColumn'],
],
]); ?>
```Десктопная версия (компаний нет):
Десктопная версия (компания есть):
Десктопная версия (несколько компаний), а также поиск:
https://user-images.githubusercontent.com/93386515/226196700-0bcf9305-0eaf-4ae7-864d-032065cedcda.mp4
:bookmark_tabs: Оглавление###
Личный кабинет пользователя
В данном разделе выводится информация о пользователе, а именно:
1) Аватарка;
2) Фамилия;
3) Имя
4) Отчество;
5) Пол;
6) Дата рождения;
7) Телефон;
8) Email;
9) Местоположение;
10) Краткое описание;
11) Дата регистрации.Контроллер ```PersonalController``` действие ```Page```:
```php
//Личный кабинет пользователя
public function actionPage() {
return $this->render('page');
}
```Для того, чтобы доступ к системе имели только авторизированные пользователи, используются фильтры контроля доступа (ACF).
**ACF** – это фильтры, которые могут присоединяться к контроллеру или модулю как поведение.Контроллер ```PersonalController``` в папке ```/controllers```:
```php
use yii\filters\AccessControl;
use yii\filters\VerbFilter;public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['personal', 'update'],
'rules' => [
[
'actions' => ['personal', 'update'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post', 'get'],
],
],
];
}
```Модуль ```Personal```:
```php
namespace app\models;class Personal extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'user';
}public function rules()
{
return [
[['surname', 'name', 'gender', 'date_birth', 'email', 'address'], 'required'],
['avatar', 'file', 'extensions' => 'png, jpg'],
[['middle_name', 'phone', 'description'], 'safe'],
['email', 'email'],
];
}public function attributeLabels()
{
return [
'avatar' => 'Аватар',
'surname' => 'Фамилия',
'name' => 'Имя',
'middle_name' => 'Отчество',
'gender' => 'Пол',
'date_birth' => 'Дата рождения',
'phone' => 'Телефон',
'email' => 'Email',
'address' => 'Местоположение',
'description' => 'Краткое описание'
];
}public function getComments()
{
return $this->hasMany(Comments::class, ['id_user' => 'id']);
}public function getCompanies()
{
return $this->hasMany(Companies::class, ['id_user' => 'id']);
}
}
```Представление ```page```:
```php
title = 'Профиль';
$this->params['breadcrumbs'][] = 'Профиль';
?>
Фамилия:= Yii::$app->user->identity->surname ?>
Имя:= Yii::$app->user->identity->name ?>
user->identity->middle_name != NULL) { ?>
Отчество:= Yii::$app->user->identity->middle_name ?>
Пол:
user->identity->gender == 1) {
echo "Мужчина";
} else {
echo "Женщина";
} ?>
Дата рождения:= date("d.m.Y", strtotime(Yii::$app->user->identity->date_birth)) ?>
Дата регистрации:= date("d.m.Y", strtotime(Yii::$app->user->identity->registration_date)) ?>
user->identity->phone != NULL) { ?>
Телефон:= Yii::$app->user->identity->phone ?>
Email:= Yii::$app->user->identity->email ?>
Местоположение:
= Yii::$app->user->identity->address ?>
user->identity->description != NULL) { ?>
Краткое описание:
= Yii::$app->user->identity->description ?>
Yii::$app->user->id], ['class' => 'btn btn-success']);
?>
```Десктопная версия:
Мобильная версия:
https://user-images.githubusercontent.com/93386515/226198784-29148437-9e6d-421b-9431-2ad5b32f1c74.mp4
:bookmark_tabs: Оглавление###
Редактировать информацию о пользователе
Контроллер ```PersonalController``` действие ```Update```:
```php
use Yii;
use app\models\Personal;//Редактировать информацию о пользователе
public function actionUpdate($id)
{
$model = Personal::findOne($id);
$model->avatar_now = $model->avatar;if ($model->load(\Yii::$app->request->post()) && $model->uppage()) {
}
return $this->render('update', compact('model'));
}
```В модуль ```Personal```, указанный в подразделе Личный кабинет пользователя, добавляем код для добавления/редактирования и удаления заменяемой аватарки пользователя, а именно виджет ```UploadedFile```. Документация по [UploadedFile](https://unetway.com/tutorial/yii-uploading-files).
Модуль ```Personal```:
```php
use Yii;
use yii\web\UploadedFile;
use yii\helpers\Url;public $avatar_now;
public function uppage() {
if ($this->validate()) {
if ($this->avatar = UploadedFile::getInstance($this, 'avatar')) {
$file_name = time() . '_user.' . $this->avatar->extension;if ($this->avatar->saveAs('avatars/' . $file_name)) {
if (file_exists($this->avatar_now)) {
unlink($this->avatar_now);
}
$this->avatar = 'avatars/' . $file_name;
}
} else {
$this->avatar = $this->avatar_now;
}
}if ($this->save(false)) {
Yii::$app->response->redirect(Url::to(['personal/page', 'id' => Yii::$app->user->id]));
}
}
```В представлении указан немаловажный виджет ```DatePicker```. ```DatePicker``` представлен в подразделе Регистрация.
Представление ```update```:
```php
title = 'Редактировать профиль';
$this->params['breadcrumbs'][] = ['label' => 'Профиль', 'url' => ['page', 'id' => $model->id]];
$this->params['breadcrumbs'][] = 'Редактировать профиль';
?>
'mypersonal',
'method' => 'post',
'fieldConfig' => [
'template' => '{label} {input}{error}',
],
]); ?>
field($model, 'avatar')->fileInput();
echo $form->field($model, 'surname', ['template' => '{label} *{input}{error}'])->textInput();
echo $form->field($model, 'name', ['template' => '{label} *{input}{error}'])->textInput();
echo $form->field($model, 'middle_name')->textInput();
echo $form->field($model, 'gender', ['template' => '{label} *{input}{error}'])->radioList([1 => 'Мужчина', 2 => 'Женщина']);
echo $form->field($model, 'date_birth', ['template' => '{label} *{input}{error}'])->widget(DatePicker::classname(), [
'options' => [
'placeholder' => 'гггг-мм-дд'
],
'pluginOptions' => [
'format' => 'yyyy-mm-dd',
'endDate' => '-18y',
'todayHighlight' => true
]
]);echo $form->field($model, 'phone')->widget(\yii\widgets\MaskedInput::className(), ['mask' => '+7 (999) 999-99-99'])->textInput();
echo $form->field($model, 'email', ['template' => '{label} *{input}{error}'])->textInput();
echo $form->field($model, 'address', ['template' => '{label} *{input}{error}'])->textInput();
echo $form->field($model, 'description')->textarea();
echo "
";
echo Html::submitButton("Сохранить", ['class' => 'btn btn-success']);
ActiveForm::end(); ?>
```Десктопная версия:
https://user-images.githubusercontent.com/93386515/226316492-60ca08f9-6263-445b-9918-40c656c3700e.mp4
:bookmark_tabs: Оглавление
'add_nam_comment',
'method' => 'post',
]);
echo $form->field($model_cr, 'name_comment')->textInput();
echo Html::submitButton('Добавить комментарий', ['class' => 'btn btn-success']);
ActiveForm::end(); ?>