Магазин на Yii2, часть 27. Админка: приводим в порядок сгенерированный код

02.09.2019

Теги: CRUDWeb-разработкаYii2ИнтернетМагазинКаталогТоваровПанельУправленияПрактикаФреймворк

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

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

Работа с брендами

<?php
namespace app\modules\admin\models;

use Yii;
use yii\db\ActiveRecord;

/**
 * Это модель для таблицы БД `category`
 *
 * @property int $id Уникальный идентификатор
 * @property string $name Наименование бренда
 * @property string $content Описание бренда
 * @property string $keywords Мета-тег keywords
 * @property string $description Мета-тег description
 * @property string $image Имя файла изображения
 */
class Brand extends ActiveRecord {

    /**
     * Возвращает имя таблицы базы данных
     */
    public static function tableName() {
        return 'brand';
    }

    /**
     * Правила валидации полей формы при создании и редактировании бренда
     */
    public function rules() {
        return [
            [['name'], 'required'],
            [['name', 'content', 'keywords', 'description', 'image'], 'string', 'max' => 255],
        ];
    }

    /**
     * Возвращает имена полей формы для создания и редактирования бренда
     */
    public function attributeLabels() {
        return [
            'id' => 'ID',
            'name' => 'Наименование',
            'content' => 'Описание',
            'keywords' => 'Мета-тег keywords',
            'description' => 'Мета-тег description',
            'image' => 'Изображение',
        ];
    }
}
<?php
namespace app\modules\admin\controllers;

use Yii;
use app\modules\admin\models\Brand;
use yii\data\ActiveDataProvider;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

/**
 * Класс BrandController реализует CRUD для брендов
 */
class BrandController extends AdminController {

    public function behaviors() {
        return [
            'verbs' => [
                'class' => VerbFilter::class,
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Список всех брендов с постраничной навигацией
     */
    public function actionIndex() {
        $dataProvider = new ActiveDataProvider([
            'query' => Brand::find(),
        ]);
        return $this->render('index', [
            'dataProvider' => $dataProvider,
        ]);
    }

    /**
     * Просмотр данных существующего бренда
     */
    public function actionView($id) {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Создание нового бренда
     */
    public function actionCreate() {
        $model = new Brand();
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }
        return $this->render('create', [
            'model' => $model,
        ]);
    }

    /**
     * Обновление существующего бренда
     */
    public function actionUpdate($id) {
        $model = $this->findModel($id);
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }
        return $this->render('update', [
            'model' => $model,
        ]);
    }

    /**
     * Удаление существующего бренда
     */
    public function actionDelete($id) {
        $this->findModel($id)->delete();
        return $this->redirect(['index']);
    }

    /**
     * Поиск бренда по идентификатору
     */
    protected function findModel($id) {
        if (($model = Brand::findOne($id)) !== null) {
            return $model;
        }
        throw new NotFoundHttpException('The requested page does not exist.');
    }
}
<?php
/*
 * Страница списка всех брендов, файл modules/admin/views/brand/index.php
 */
use yii\helpers\Html;
use yii\grid\GridView;

/* @var $this yii\web\View */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = 'Бренды';
?>

<h1><?= Html::encode($this->title); ?></h1>
<p>
    <?= Html::a('Добавить бренд', ['create'], ['class' => 'btn btn-success']); ?>
</p>

<?=
GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        'name',
        [
            'attribute' => 'keywords',
            'value' => function($data) {
                return empty($data->keywords) ? 'Не задано' : $data->keywords;
            }
        ],
        [
            'attribute' => 'description',
            'value' => function($data) {
                return empty($data->description) ? 'Не задано' : $data->description;
            }
        ],
        ['class' => 'yii\grid\ActionColumn'],
    ],
]);
?>
<?php
/*
 * Страница добавления нового бренда, файл modules/admin/views/brand/create.php
 */
use yii\helpers\Html;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Brand */

$this->title = 'Новый бренд';
?>

<h1><?= Html::encode($this->title); ?></h1>
<?=
$this->render(
    '_form',
    ['model' => $model]
);
?>
<?php
/*
 * Страница редактирования существующего бренда, файл modules/admin/views/brand/update.php
 */
use yii\helpers\Html;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Brand */

$this->title = 'Редактирование бренда: ' . $model->name;
?>

<h1><?= Html::encode($this->title); ?></h1>
<?=
$this->render(
    '_form', [
    'model' => $model,
]);
?>
<?php
/*
 * Страница просмотра данных бренда, файл modules/admin/views/brand/view.php
 */
use yii\helpers\Html;
use yii\widgets\DetailView;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Brand */

$this->title = 'Просмотр бренда: ' . $model->name;
?>

<h1><?= Html::encode($this->title); ?></h1>
<p>
    <?= Html::a('Изменить', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']); ?>
    <?=
    Html::a(
        'Удалить',
        ['delete', 'id' => $model->id],
        [
            'class' => 'btn btn-danger',
            'data' => [
                'confirm' => 'Вы уверены, что хотите удалить бренд?',
                'method' => 'post',
            ],
        ]
    );
    ?>
</p>

<?=
DetailView::widget([
    'model' => $model,
    'attributes' => [
        'name',
        'content',
        'keywords',
        'description',
        'image',
    ],
]);
?>
<?php
/*
 * Форма для добавления и редактирования бренда, файл modules/admin/views/brand/_form.php
 */
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Brand */
/* @var $form yii\widgets\ActiveForm */
?>

<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
    <?= $form->field($model, 'content')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <?= $form->field($model, 'keywords')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <?= $form->field($model, 'description')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <?= $form->field($model, 'image')->textInput(['maxlength' => true]) ?>
    <div class="form-group">
        <?= Html::submitButton('Сохранить', ['class' => 'btn btn-success']) ?>
    </div>
<?php ActiveForm::end(); ?>

Работа с категориями

<?php
namespace app\modules\admin\models;

use Yii;
use yii\db\ActiveRecord;

/**
 * Это модель для таблицы БД `category`
 *
 * @property int $id Уникальный идентификатор
 * @property int $parent_id Родительская категория
 * @property string $name Наименование категории
 * @property string $content Описание категории
 * @property string $keywords Мета-тег keywords
 * @property string $description Мета-тег description
 * @property string $image Имя файла изображения
 */
class Category extends ActiveRecord {

    /**
     * Возвращает имя таблицы базы данных
     */
    public static function tableName() {
        return 'category';
    }

    /**
     * Возвращает данные о родительской категории
     */
    public function getParent() {
        return $this->hasOne(Category::class, ['id' => 'parent_id']);
    }

    /**
     * Возвращает наименование родительской категории
     */
    public function getParentName() {
        $parent = $this->parent;
        return $parent ? $parent->name : '';
    }

    /**
     * Правила валидации полей формы при создании и редактировании категории
     */
    public function rules() {
        return [
            [['parent_id'], 'integer'],
            [['name'], 'required'],
            [['name', 'content', 'keywords', 'description', 'image'], 'string', 'max' => 255],
        ];
    }

    /**
     * Возвращает имена полей формы для создания и редактирования категории
     */
    public function attributeLabels() {
        return [
            'id' => 'ID',
            'parent_id' => 'Родитель',
            'name' => 'Наименование',
            'content' => 'Описание',
            'keywords' => 'Мета-тег keywords',
            'description' => 'Мета-тег description',
            'image' => 'Изображение'
        ];
    }
}
<?php
namespace app\modules\admin\controllers;

use Yii;
use app\modules\admin\models\Category;
use yii\data\ActiveDataProvider;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

/**
 * Класс CategoryController реализует CRUD для категорий
 */
class CategoryController extends AdminController {

    public function behaviors() {
        return [
            'verbs' => [
                'class' => VerbFilter::class,
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Список всех категорий с постраничной навигацией
     */
    public function actionIndex() {
        $dataProvider = new ActiveDataProvider([
            'query' => Category::find(),
        ]);
        return $this->render('index', [
            'dataProvider' => $dataProvider,
        ]);
    }

    /**
     * Просмотр данных существующей категории
     */
    public function actionView($id) {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Создание новой категории
     */
    public function actionCreate() {
        $model = new Category();
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }
        return $this->render('create', [
            'model' => $model,
        ]);
    }

    /**
     * Обновление существующей категории
     */
    public function actionUpdate($id) {
        $model = $this->findModel($id);
        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }
        return $this->render('update', [
            'model' => $model,
        ]);
    }

    /**
     * Удаление существующей категории
     */
    public function actionDelete($id) {
        $this->findModel($id)->delete();
        return $this->redirect(['index']);
    }

    /**
     * Поиск категории по идентификатору
     */
    protected function findModel($id) {
        if (($model = Category::findOne($id)) !== null) {
            return $model;
        }
        throw new NotFoundHttpException('The requested page does not exist.');
    }
}
<?php
/*
 * Страница списка всех категорий, файл modules/admin/views/category/index.php
 */
use yii\helpers\Html;
use yii\grid\GridView;

/* @var $this yii\web\View */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = 'Категории каталога';
?>

<h1><?= Html::encode($this->title); ?></h1>
<p>
    <?= Html::a('Добавить категорию', ['create'], ['class' => 'btn btn-success']); ?>
</p>
<?=
GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        'name',
        [
            'attribute' => 'parent_id',
            'value' => function($data) {
                return $data->getParentName();
            }
        ],
        [
            'attribute' => 'keywords',
            'value' => function($data) {
                return empty($data->keywords) ? 'Не задано' : $data->keywords;
            }
        ],
        [
            'attribute' => 'description',
            'value' => function($data) {
                return empty($data->description) ? 'Не задано' : $data->description;
            }
        ],
        ['class' => 'yii\grid\ActionColumn'],
    ],
]);
?>
<?php
/*
 * Страница добавления новой категории, файл modules/admin/views/category/create.php
 */
use yii\helpers\Html;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Category */

$this->title = 'Новая категория';
?>

<h1><?= Html::encode($this->title); ?></h1>
<?=
$this->render(
    '_form',
    ['model' => $model]
);
?>
<?php
/*
 * Страница редактирования категории, файл modules/admin/views/category/update.php
 */
use yii\helpers\Html;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Category */

$this->title = 'Редактирование категории: ' . $model->name;
?>

<h1><?= Html::encode($this->title); ?></h1>
<?=
$this->render(
     '_form', [
    'model' => $model,
]);
?>
<?php
/*
 * Страница просмотра категории, файл modules/admin/views/category/view.php
 */
use yii\helpers\Html;
use yii\widgets\DetailView;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Category */

$this->title = 'Просмотр категории: ' . $model->name;
?>

<h1><?= Html::encode($this->title); ?></h1>
<p>
    <?= Html::a('Изменить', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']); ?>
    <?=
    Html::a(
        'Удалить',
        ['delete', 'id' => $model->id],
        [
            'class' => 'btn btn-danger',
            'data' => [
                'confirm' => 'Вы уверены, что хотите удалить категорию?',
                'method' => 'post',
            ],
        ]
    );
    ?>
</p>

<?=
DetailView::widget([
    'model' => $model,
    'attributes' => [
        'name',
        [
            'attribute' => 'parent_id',
            'value' =>  $model->getParentName()
        ],
        'content',
        'keywords',
        'description',
        'image',
    ],
]);
?>
<?php
/*
 * Форма для добавления и редактирования категории, файл modules/admin/views/category/_form.php
 */
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Category */
/* @var $form yii\widgets\ActiveForm */
?>

<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'parent_id')->textInput() ?>
    <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
    <?= $form->field($model, 'content')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <?= $form->field($model, 'keywords')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <?= $form->field($model, 'description')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <?= $form->field($model, 'image')->textInput(['maxlength' => true]) ?>
    <div class="form-group">
        <?= Html::submitButton('Сохранить', ['class' => 'btn btn-success']) ?>
    </div>
<?php ActiveForm::end(); ?>

Работа с товарами

<?php
namespace app\modules\admin\models;

use Yii;
use yii\db\ActiveRecord;

/**
 * Это модель для таблицы БД `product`
 *
 * @property int $id Уникальный идентификатор
 * @property int $category_id Родительская категория
 * @property int $brand_id Идентификатор бренда
 * @property string $name Наименование товара
 * @property string $content Описание товара
 * @property string $price Цена товара
 * @property string $keywords Мета-тег keywords
 * @property string $description Мета-тег description
 * @property string $image Имя файла изображения
 * @property int $hit Лидер продаж?
 * @property int $new Новый товар?
 * @property int $sale Распродажа?
 */
class Product extends ActiveRecord {

    /**
     * Возвращает имя таблицы базы данных
     */
    public static function tableName() {
        return 'product';
    }

    /**
     * Возвращает данные о родительской категории
     */
    public function getCategory() {
        return $this->hasOne(Category::class, ['id' => 'category_id']);
    }

    /**
     * Возвращает наименование родительской категории
     */
    public function getCategoryName() {
        $parent = $this->category;
        return $parent ? $parent->name : '';
    }

    /**
     * Возвращает данные о бренде товара
     */
    public function getBrand() {
        return $this->hasOne(Brand::class, ['id' => 'brand_id']);
    }

    /**
     * Возвращает наименование бренда товара
     */
    public function getBrandName() {
        $brand = $this->brand;
        return $brand ? $brand->name : '';
    }

    /**
     * Правила валидации полей формы при создании и редактировании товара
     */
    public function rules() {
        return [
            [['category_id', 'brand_id', 'name'], 'required'],
            [['category_id', 'brand_id', 'hit', 'new', 'sale'], 'integer'],
            [['content'], 'string'],
            [['price'], 'number'],
            [['name', 'keywords', 'description', 'image'], 'string', 'max' => 255],
        ];
    }

    /**
     * Возвращает имена полей формы для создания и редактирования товара
     */
    public function attributeLabels() {
        return [
            'id' => 'ID',
            'category_id' => 'Категория',
            'brand_id' => 'Бренд',
            'name' => 'Наименование',
            'content' => 'Описание',
            'price' => 'Цена',
            'keywords' => 'Мета-тег keywords',
            'description' => 'Мета-тег description',
            'image' => 'Изображение',
            'hit' => 'Лидер продаж',
            'new' => 'Новинка',
            'sale' => 'Распродажа',
        ];
    }
}
<?php
namespace app\modules\admin\controllers;

use Yii;
use app\modules\admin\models\Product;
use yii\data\ActiveDataProvider;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

/**
 * Класс ProductController реализует CRUD для товаров
 */
class ProductController extends AdminController {

    public function behaviors() {
        return [
            'verbs' => [
                'class' => VerbFilter::class,
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Список всех товаров с постраничной навигацией
     */
    public function actionIndex() {
        $dataProvider = new ActiveDataProvider([
            'query' => Product::find(),
        ]);
        return $this->render('index', [
            'dataProvider' => $dataProvider,
        ]);
    }

    /**
     * Просмотр данных существующего товара
     */
    public function actionView($id) {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Создание нового товара
     */
    public function actionCreate() {
        $model = new Product();

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }
        return $this->render('create', [
            'model' => $model,
        ]);
    }

    /**
     * Обновление существующего товара
     */
    public function actionUpdate($id) {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
            return $this->redirect(['view', 'id' => $model->id]);
        }

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

    /**
     * Удаление существующего товара
     */
    public function actionDelete($id) {
        $this->findModel($id)->delete();
        return $this->redirect(['index']);
    }

    /**
     * Поиск товара по идентификатору
     */
    protected function findModel($id) {
        if (($model = Product::findOne($id)) !== null) {
            return $model;
        }
        throw new NotFoundHttpException('The requested page does not exist.');
    }
}
<?php
/*
 * Страница списка всех товаров, файл modules/admin/views/product/index.php
 */
use yii\helpers\Html;
use yii\grid\GridView;

/* @var $this yii\web\View */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = 'Товары каталога';
?>

<h1><?= Html::encode($this->title); ?></h1>
<p>
    <?= Html::a('Добавить товар', ['create'], ['class' => 'btn btn-success']); ?>
</p>

<?=
GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        'name',
        [
            'attribute' => 'category_id',
            'value' => function($data){
                return $data->getCategoryName();
            }
        ],
        [
            'attribute' => 'brand_id',
            'value' => function($data){
                return $data->getBrandName();
            }
        ],
        'price',
        [
            'attribute' => 'hit',
            'value' => function($data) {
                return $data->hit ? 'Да' : 'Нет';
            }
        ],
        [
            'attribute' => 'new',
            'value' => function($data) {
                return $data->new ? 'Да' : 'Нет';
            }
        ],
        [
            'attribute' => 'sale',
            'value' => function($data) {
                return $data->sale ? 'Да' : 'Нет';
            }
        ],
        ['class' => 'yii\grid\ActionColumn'],
    ],
]);
?>
<?php
/*
 * Страница добавления нового товара, файл modules/admin/views/product/create.php
 */
use yii\helpers\Html;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Product */

$this->title = 'Новый товар';
?>

<h1><?= Html::encode($this->title); ?></h1>
<?=
$this->render(
    '_form',
    ['model' => $model]
);
?>
<?php
/*
 * Страница редактирования товара, файл modules/admin/views/product/update.php
 */
use yii\helpers\Html;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Product */

$this->title = 'Редактирование товара: ' . $model->name;
?>

<h1><?= Html::encode($this->title); ?></h1>
<?=
$this->render(
    '_form',
    ['model' => $model]
);
?>
<?php
/*
 * Страница просмотра товара, файл modules/admin/views/product/view.php
 */
use yii\helpers\Html;
use yii\widgets\DetailView;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Product */

$this->title = 'Просмотр товара: ' . $model->name;
?>

<h1><?= Html::encode($this->title); ?></h1>
<p>
    <?= Html::a('Изменить', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']); ?>
    <?=
    Html::a(
        'Удалить',
        ['delete', 'id' => $model->id],
        [
            'class' => 'btn btn-danger',
            'data' => [
                'confirm' => 'Вы уверены, что хотите удалить товар?',
                'method' => 'post',
            ],
        ]
    );
    ?>
</p>

<?=
DetailView::widget([
    'model' => $model,
    'attributes' => [
        'name',
        [
            'attribute' => 'category_id',
            'value' => $model->getCategoryName()
        ],
        [
            'attribute' => 'brand_id',
            'value' => $model->getBrandName()
        ],
        'price',
        'content:html',
        'keywords',
        'description',
        'image',
        [
            'attribute' => 'hit',
            'value' =>  $model->hit ? 'Да' : 'Нет'
        ],
        [
            'attribute' => 'new',
            'value' =>  $model->new ? 'Да' : 'Нет'
        ],
        [
            'attribute' => 'sale',
            'value' =>  $model->sale ? 'Да' : 'Нет'
        ],
    ],
]);
?>
<?php
/*
 * Форма для добавления и редактирования товара, файл modules/admin/views/product/_form.php
 */
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model app\modules\admin\models\Product */
/* @var $form yii\widgets\ActiveForm */
?>

<?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'name')->textInput(['maxlength' => true]); ?>
    <?= $form->field($model, 'category_id')->textInput(); ?>
    <?= $form->field($model, 'brand_id')->textInput(); ?>
    <?= $form->field($model, 'price')->textInput(['maxlength' => true]); ?>
    <?= $form->field($model, 'image')->textInput(['maxlength' => true]); ?>
    <?= $form->field($model, 'content')->textarea(['rows' => 6]); ?>
    <?= $form->field($model, 'keywords')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <?= $form->field($model, 'description')->textarea(['rows' => 2, 'maxlength' => true]); ?>
    <?= $form->field($model, 'hit')->textInput(); ?>
    <?= $form->field($model, 'new')->textInput(); ?>
    <?= $form->field($model, 'sale')->textInput(); ?>
    <div class="form-group">
        <?= Html::submitButton('Сохранить', ['class' => 'btn btn-success']) ?>
    </div>
<?php ActiveForm::end(); ?>

Поиск: Web-разработка • Yii2 • Интернет магазин • Каталог товаров • Панель управления • Фреймворк • Gii • CRUD

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.