Немного теории и структураРасширение подразумевает использование глобальных uid по всему проекту, что позволяет создавать аккуратные и "чистые" модели данных. При этом данный подход может накладывать некоторые ограничения и они обязательно всплывут в процессе разработки. К этому надо быть готовым или постараться спроектировать сайт с оглядкой на использование расширения.
Модель - это строка со всеми данными в таблице БД.
Расширение лежит на гитхабе.
- Uids - основная таблица, которая хранит идентификаторы сущностей, относящихся к контентной части проекта.
- Post - таблица (родительская) с записями (используем минимальный набор полей).
- Catalog - таблица для формирования дерева элементов (категории, тэги...), которые можно привязать к родительской таблице.
- Seo - таблица (дочерняя) с информацией сео.
- Binds - таблица для связи родительских таблиц с таблицей catalog.
Обязательным условием является наличие поля uid в "контентных" таблицах, модели которых будем связывать через промежуточную таблицу или между собой, через поле uid_content.
Поле uid должно иметь внешний ключ на поле id таблицы uids (delete CASCADE), потому что при удалении любой контентной модели будет удаляться запись из таблицы uids, а внешние ключи удалят саму модель, все связанные модели и связи из таблицы binds. Структура БД будет выглядеть приблизительно так:
Таблицы post и news являются
родительскими, catalog, comment и seo -
дочерними. Т.к. к родительским моделям можно привязать только одну модель (в народе hasOne) из seo и из comment, привязывать их будем через поле
uid_content в дочерних таблицах. В таблице catalog хранятся модели тэгов, категорий и т.д., поэтому к родительским моделям можно привязать несколько моделей из catalog (в народе hasMany). При этом один тэг можно привязать к нескольким моделям post и их же к моделям news. Привязку hasMany осуществляем в таблице binds.
В таблице binds внешние ключи указывают из двух полей (uid - модель
(post,news), к которой привязываем и uid_bind - модель
(catalog), которую привязываем) на поле id таблицы uids. Сделано это для того, чтобы разорвать связи удаляемой (родительской) модели с моделями из catalog.
Принцип создания и удаления моделейПри создании контентной модели выполняется запись в таблицу uids, в которую пишем id юзера (
created_by), время создания (created_at), название таблицы создаваемой модели (бонусом идут статусы состояния). После создания записи в uids, свеженький id присваиваем создаваемой модели (пишем в поле uid).
При удалении модели необходимо получить uid (равен uids.id) и выполнить удаление записи из таблицы uids.
В случае удаления модели из каталога, достаточно будет удалить только запись из таблицы uids и все связи удаляться автоматически. При удалении родительской модели, также необходимо позаботиться об удалении дочерних моделей (hasOne). Дочерние модели (hasMany)
удалять нельзя, потому что они могут использоваться в других родительских моделях.
Для надежности все обязательные таблицы в миграциях расширения названы с префиксом bind_ и возможностью добавить свой префикс.
Скрины для наглядностиУправление каталогом
Добавление данных модели
Настройка файла конфигурацииВ секцию components необходимо добавить следующий код для генерации seo meta-tags
'components' => [
...
'view' => [
'as seo' => [
'class' => \fedornabilkin\binds\behaviors\SeoBehavior::class,
],
],
],
В секцию modules подключить модули для управления каталогом (расширение использует treemanager от kartik)
'modules' => [
...
'binds' => [
'class' => 'fedornabilkin\binds\Module',
],
'treemanager' => [
'class' => 'kartik\tree\Module',
'dataStructure' => [
'keyAttribute' => 'id',
],
],
],
Класс моделиКласс контентной модели должен быть унаследован от
fedornabilkin\binds\models\base\BindModel и может выглядеть следующим образом
<?php
namespace frontend\models;
use fedornabilkin\binds\behaviors\BindBehavior;
use fedornabilkin\binds\behaviors\SeoBehavior;
use fedornabilkin\binds\models\base\BindModel;
/**
* This is the model class for table "post".
*
* @property int $id
* @property int $uid
* @property string $title
* @property string $post
*/
class Post extends BindModel
{
public function behaviors()
{
return array_merge_recursive(parent::behaviors(), [
'SeoBehavior' => [
'class' => SeoBehavior::class,
],
'BindsBehavior' => [
'class' => BindBehavior::class,
'tree' => [
// никнэймы корневых узлов дерева каталога
'nicknames' => [
'visible' => [
'multiple' => false, // единичный или множественный выбор
],
'categories' => [
'multiple' => false,
],
'tags' => [
'multiple' => true,
'asDropdown' => false, // развернутое состояние
],
],
],
],
]);
}
/**
* @inheritdoc
*/
public static function tableName()
{
return 'post';
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[['post'], 'string'],
[['title'], 'string', 'max' => 150],
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'title' => 'Title',
'post' => 'Post',
];
}
// модели hasOne
public function getChildModels()
{
return array_merge(parent::getChildModels(), [
'comment' => Comment::class,
]);
}
}
Если к родительской модели привязаны дочерние как hasOne, то их классы необходимо указать в массиве, который возвратит метод getChildsModels()
Массив должен включать в себя элементы массива из одноименного метода родительского класса. При удалении родительской модели, расширение проверит наличие связи с дочерними моделями (указанными в getChildsModels()) и удалит дочерние модели.
Форма заполнения данными модели имеет такой вид (подключены Status, Seo и Binds виджеты)
<?php
use fedornabilkin\binds\models\Catalog;
use fedornabilkin\binds\models\Uid;
use yii\helpers\Html;
use kartik\tree\TreeViewInput;
use yii\widgets\ActiveForm;
/* @var $this yii\web\View */
/* @var $model frontend\models\Post */
$this->title = 'Update Post';
$this->params['breadcrumbs'][] = ['label' => 'Posts', 'url' => ['index']];
$this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->id]];
$this->params['breadcrumbs'][] = 'Update';
?>
<div class="post-update">
<h1><?= Html::encode($this->title) ?></h1>
<?php $form = ActiveForm::begin(); ?>
<div class="row">
<div class="col-xs-12 col-sm-8">
<?= \fedornabilkin\binds\widgets\status\StatusWidget::widget(['model' => $model])?>
<?= $form->field($model, 'title')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'post')->textarea(['rows' => 6]) ?>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?= \fedornabilkin\binds\widgets\seo\SeoWidget::widget(['model' => $model])?>
</div>
<div class="col-xs-12 col-sm-4">
<?= \fedornabilkin\binds\widgets\binds\BindsWidget::widget(['model' => $model])?>
</div>
</div>
<?php ActiveForm::end(); ?>
</div>
Основные реляции объявлены в BindModel, поэтому получение данных связанных моделей может выглядеть следующим образом:
$model = Post::findOne(123); // получаем модель с id 123
$model->uids->created_at; // время создания
$model->uids->created_by; // id пользователя
// массив тэгов (моделей из таблицы catalog),
// привязанных к модели Post
$tags = $model->getCatalogByNickname('tags')->all();
foreach ($tags as $index => $tag) {
echo $tag->name . ' '; // название тэга
}
$posts = Post::findFiltered()->all(); // получит все модели со статусом 1 (Опубликован)
Замечание модератора:
Эта тема была закрыта автоматически ввиду отсутствия активности в ней на протяжении 100+ дней.
Если Вы считаете ее актуальной и хотите оставить сообщение, то воспользуйтесь кнопкой
или обратитесь к любому из модераторов.
|
Сообщение отредактировал fedornabilkin - 13.3.2018, 0:14