Запись данных в промежуточную таблицу

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Maksat1991
Сообщения: 57
Зарегистрирован: 2016.10.16, 00:15

Запись данных в промежуточную таблицу

Сообщение Maksat1991 »

Есть две модели, которые соединяются между собой как многие-ко-многим через промежуточную таблицу.
В моделях каждой их них сделал связь через via table, примерно так:

Код: Выделить всё

class Order extends ActiveRecord
{
    public function getOrderItems()
    {
        return $this->hasMany(OrderItem::className(), ['order_id' => 'id']);
    }

    public function getItems()
    {
        return $this->hasMany(Item::className(), ['id' => 'item_id'])
            ->via('orderItems');
    }
}

Теперь я могу получать для модели $order значения всех его items через $order->items;


Далее. Во вьюшке для создания/редактирования Order есть такое:

Код: Выделить всё

<?= $form->field($model, 'items')->dropDownList(ArrayHelper::map($items, 'id', 'name'), ['maxlength' => 255, 'multiple' => true, 'class'=>'form-control', 'size'=>10]) ?>
Благодаря этому в моём multiple dropdown-листе уже отмечены те items, которые с этим $order связаны, что очень классно.

Но, когда я хочу в контроллере принимаю все эти данные, то хочу потом в модели Orders в методе beforeSave пробежаться по массиву $this->items, чтобы считать и записать отсюда все данные в промежуточную таблицу. Но не могу этого сделать, потому что Yii ругается, мол, свойство $this->items - только для чтения, и в него не получается записать никакие данные, когда я делаю в контроллере $model->load(Yii::$app->request->post());

Пока что вижу только один выход - это не load-ить эти данные в модель, а напрямую в контроллере принимать их и производить запись в промежуточную таблицу. Но это слишком некрасиво. Может, все же есть способ?


P.S. Свойство items в модели Orders в валидаторах добавил как safe.
caHek2x
Сообщения: 1240
Зарегистрирован: 2016.04.12, 20:41

Re: Запись данных в промежуточную таблицу

Сообщение caHek2x »

метод setItems сделайте
Maksat1991
Сообщения: 57
Зарегистрирован: 2016.10.16, 00:15

Re: Запись данных в промежуточную таблицу

Сообщение Maksat1991 »

caHek2x писал(а): 2017.05.22, 18:37 метод setItems сделайте
Я сделаю, он будет в beforeSave вызываться. Вопрос в другом. А именно в том, что до beforeSave дело не дойдёт, т.к. в переменную items не запишутся данные. Почему - описал выше
Аватара пользователя
Alexum
Сообщения: 683
Зарегистрирован: 2016.09.26, 10:00

Re: Запись данных в промежуточную таблицу

Сообщение Alexum »

Можно добавить отдельный атрибут в модель под массив связанных items, название которого не будет перекликаться с названием связи, загружайте в него данные о существующих связях и передавайте во view. После сабмита обойдёте его и наделаете/наудаляете связей через link() и unlink().
А caHek2x предлагает вариант с определением сеттера, чтобы магический __set() увидел ваш метод и использовал его (сейчас он натыкается только на наличие геттера и выдаёт вам сообщение). И он будет не вами в beforeSave() вызываться а самостоятельно, н-р при загрузке модели данными из post.
Maksat1991 писал(а): 2017.05.22, 18:23 P.S. Свойство items в модели Orders в валидаторах добавил как safe.
Можно добавить each валидатор, который проверит существование в таблице Items записей с переданными id.
Примерно так:

Код: Выделить всё

[['items'], 'each', 'rule' => ['exist', 'skipOnError' => true, 'targetClass' => Item::className(), 'targetAttribute' => ['items' => 'id']]]
caHek2x
Сообщения: 1240
Зарегистрирован: 2016.04.12, 20:41

Re: Запись данных в промежуточную таблицу

Сообщение caHek2x »

Maksat1991 писал(а): 2017.05.23, 06:54
caHek2x писал(а): 2017.05.22, 18:37 метод setItems сделайте
Я сделаю, он будет в beforeSave вызываться. Вопрос в другом. А именно в том, что до beforeSave дело не дойдёт, т.к. в переменную items не запишутся данные. Почему - описал выше
Alexum писал(а): 2017.05.23, 09:01 А caHek2x предлагает вариант с определением сеттера, чтобы магический __set() увидел ваш метод и использовал его
совершенно верно, Maksat1991 если вы сделаете setItems, грубо говоря load будет посылать данные в этот метод ... и вы там будете уже чтото с ними делать ... создавать модели или просто в переменную писать ...
Maksat1991
Сообщения: 57
Зарегистрирован: 2016.10.16, 00:15

Re: Запись данных в промежуточную таблицу

Сообщение Maksat1991 »

Alexum писал(а): 2017.05.23, 09:01 Можно добавить отдельный атрибут в модель под массив связанных items, название которого не будет перекликаться с названием связи, загружайте в него данные о существующих связях и передавайте во view. После сабмита обойдёте его и наделаете/наудаляете связей через link() и unlink().
А caHek2x предлагает вариант с определением сеттера, чтобы магический __set() увидел ваш метод и использовал его (сейчас он натыкается только на наличие геттера и выдаёт вам сообщение). И он будет не вами в beforeSave() вызываться а самостоятельно, н-р при загрузке модели данными из post.
Maksat1991 писал(а): 2017.05.22, 18:23 P.S. Свойство items в модели Orders в валидаторах добавил как safe.
Можно добавить each валидатор, который проверит существование в таблице Items записей с переданными id.
Примерно так:

Код: Выделить всё

[['items'], 'each', 'rule' => ['exist', 'skipOnError' => true, 'targetClass' => Item::className(), 'targetAttribute' => ['items' => 'id']]]
Да, сделал как Вы предложили в первом варианте, работает.
Сейчас попробую второй, мне кажется он более правильным.
Maksat1991
Сообщения: 57
Зарегистрирован: 2016.10.16, 00:15

Re: Запись данных в промежуточную таблицу

Сообщение Maksat1991 »

caHek2x писал(а): 2017.05.23, 14:28
Maksat1991 писал(а): 2017.05.23, 06:54
caHek2x писал(а): 2017.05.22, 18:37 метод setItems сделайте
Я сделаю, он будет в beforeSave вызываться. Вопрос в другом. А именно в том, что до beforeSave дело не дойдёт, т.к. в переменную items не запишутся данные. Почему - описал выше
Alexum писал(а): 2017.05.23, 09:01 А caHek2x предлагает вариант с определением сеттера, чтобы магический __set() увидел ваш метод и использовал его
совершенно верно, Maksat1991 если вы сделаете setItems, грубо говоря load будет посылать данные в этот метод ... и вы там будете уже чтото с ними делать ... создавать модели или просто в переменную писать ...
Спасибо большое, понял Вас. Сейчас буду пробовать.
Ответить