Сохранение доп информации в свяжующую таблицу
koroleveduard opened this issue · 8 comments
У меня в таблице cat_2_product есть поле main которое обозначает главная эта категория или нет.
Во вьюхе у меня есть список чекбоксом со всеми категориями, отмеченные те из них, к которым относится продукт.
И я хочу список отмеченных категорий, в котором среди них выбираешь одну главную.
Общий список я получаю вот так:
<?= $form->field($model, 'category_ids')
->checkBoxList(
ArrayHelper::map(Category::find()->all(), 'id_category', 'name')
//,['multiple' => 'true']
);
?>
главную категорию вывожу так:
<?= $form->field($model, 'main')
->dropDownList(
ArrayHelper::map($model->main, 'id_category', 'name')
);
?>
При клике на чекбоксы я javascript'ом удаляю из второго списка все элементы, и добавляю туда все отмеченные в первом.
В модели поле main получается так:
public function getMain()
{
return $this->hasMany(Category::className(), ['id_category' => 'id_category'])
->viaTable('{{%cat_2_product}}', ['id_product' => 'id_product'],function($query){
$query->andWhere([
'main' => '1',
]);
return $query;
});
}
Подскажите плиз как сохранить 1 в поле main одной из строк связующей табл
Моя команда решала подобную задачу совсем не давно.
После долгих размышлений мы пришли к выводу, что лучше всего опираться на порядок передаваемых категорий - первая переданная с клиента категория является главной.
Исходя из этого конфигурация поведения имеет следующий вид:
'manyToManyBehavior' => [
'class' => ManyToManyBehavior::className(),
'relations' => [
'category_ids' => [
'categories',
'fields' => [
'string' => [
'get' => function ($value) {
return implode(',', array_map('intval', $value));
},
'set' => function ($value) {
if (empty($value)) {
return [];
}
return array_map('intval', explode(',', $value));
},
]
],
'viaTableValues' => [
'is_main' => function ($model, $relationName, $attributeName, $relatedPK) {
return $model->category_ids[0] == $relatedPK;
},
],
],
'link_block_post_ids' => 'linkedPosts',
],
],
Код взят из реального проекта.
Он настроен на чтение и передачу клиенту строки с id категорий, а не массив элементов. Но ты можешь это изменить переписав или убрав get & set в конфигурации поведения.
Но дальше, потребовался нормальный control для управления всем этим делом.
Так как категории хранятся в виде дерева используя behaviors @paulzi и мой виджет для управления деревом tree manager то нами был создан еще один виджет для привязки категорий к посту с возможностью управлять сортировкой категорий и выбором главной (первая из спика).
В данный момент виджет тестируется и я не успел еще выложить его, но если он тебе понадобиться - я оформлю репо в течении пары дней.
Почему мы выбрали это решение?
Потому что только этот вариант позволяет работать в обе стороны:
- вычислить главную категорию на сервере из списка переданных с клиента
- вычислить главную категорию на клиенте переданных с сервера
Все остальные варианты с созданием доп. полей и попытки их заполнять с сервера начали порождать кучу костылей и мы от них оказались в пользу вышеописанного способа.
Как движется решение задачи?
Это заставило тебя сделать два отдельных контрола для главной категории и для остальных. Такой подход конечно работает, но он много вопросов порождает у пользователей, а потом и проблем)
Я не контроллеры имел ввиду, а контролы (form control -англ - элемент управления).
С таким подходом тебе пришлось сделать 2 контрола в форме.
Что-то типа:
- Категории
- Главная категорий
Как ты юзеру объяснишь, что главная участвует для хлебных крошек и для прочей логики, а "Категории" это реальный список категорий с которыми связан продукт. Можно подсказку написать. Но тогда может случится исключительная ситуация.
Юзер выбрал:
Категории = Б, В, Г, Д
Главная категория = A
Как видишь, главной категории нет в реальном списке категории.
Тогда может SEO пострадать из-за не правильных ссылок и прочего.
В общем, просто будь внимателен - твое решение является узким местом со сложной логикой для пользователя.
А, ну тогда хорошо)