voskobovich / yii2-many-to-many-behavior

This behavior soon will be DEPRECATED. See the link:

Home Page:https://github.com/voskobovich/yii2-linker-behavior

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Сохранение доп информации в свяжующую таблицу

koroleveduard opened this issue · 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 контрола в форме.
Что-то типа:

  1. Категории
  2. Главная категорий
    Как ты юзеру объяснишь, что главная участвует для хлебных крошек и для прочей логики, а "Категории" это реальный список категорий с которыми связан продукт. Можно подсказку написать. Но тогда может случится исключительная ситуация.
    Юзер выбрал:
    Категории = Б, В, Г, Д
    Главная категория = A
    Как видишь, главной категории нет в реальном списке категории.
    Тогда может SEO пострадать из-за не правильных ссылок и прочего.
    В общем, просто будь внимателен - твое решение является узким местом со сложной логикой для пользователя.

А, ну тогда хорошо)