Сохраняет не все связи из формы в таблицу
zhe17065564 opened this issue · 1 comments
Здравствуйте. Столкнулся с такой проблемой, что поведение many-to-many при создании записи, в моем случае публикации, сохраняется связь только с последнего поля формы , а их 4 различных типа в форме. В связующую таблицу сохраняет только id публикации и id последнего типа соавторов, остальные пустые(то есть null). Поведение вообще поддерживает сохранение нескольких связей в одну таблицу, чтобы глобально хранить "набором" связи или все же надо переписывать логику? Пробовал разносить по разным таблицам - тогда работает и сохраняет все связи, но к-во запросов к БД возрастает, чего хотелось бы избежать. Может подскажете хотя бы вектор куда двигаться - изменять логику поведения или же в контроллере дополнительно обрабатывать все входящие данные и тогда передавать в save() ? Вот собственно код формы - там всё подгружает всё работает:
` <?= $form->field($model, 'staff_ids')->widget(Select2::classname(), [
'model' => $model,
'attribute' => 'staff_ids',
'data'=>Staff::listAll(),
'options' => [
'placeholder' => '-Выберите автора-',
'multiple' => true,
],
'pluginOptions' => [
'tags' => true,
],
])->label('Авторы сотрудники')
?>
<?= $form->field($model, 'student_ids')->widget(Select2::classname(), [
'model' => $model,
'attribute' => 'student_ids',
'data'=>Student::listAll(),
'options' => [
'placeholder' => '-Выберите соавтора-',
'multiple' => true,
],
'pluginOptions' => [
'tags' => true,
],
])->label('Соавторы студенты')
?>
<?= $form->field($model, 'oi_ids')->widget(Select2::classname(), [
'model' => $model,
'attribute' => 'oi_ids',
'data'=>Oi::listAll(),
'options' => [
'placeholder' => '-Выберите соавтора-',
'multiple' => true,
],
'pluginOptions' => [
'tags' => true,
],
])->label('Соавторы других ВУЗов')
?>
<?= $form->field($model, 'fi_ids')->widget(Select2::classname(), [
'model' => $model,
'attribute' => 'fi_ids',
'data'=>Fi::listAll(),
'options' => [
'placeholder' => '-Выберите соавтора-',
'multiple' => true,
],
'pluginOptions' => [
'tags' => true,
],
])->label('Соавторы зарубежных ВУЗов')
?>
<?= $form->field($model,'user_id')->hiddenInput(['value' => Yii::$app->user->id]);?>`
А вот код модели:
`class Publications extends \yii\db\ActiveRecord
{
/**
* @inheritdoc
*/
public static function tableName()
{
return '{{%ssu_publications}}';
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[['job_title', 'types', 'indexing', 'status', 'country', 'output_data', 'published_sumdu', 'student_publication', 'user_id'], 'required'],
[['job_title', 'types', 'indexing', 'status', 'country', 'output_data', 'published_sumdu', 'student_publication'], 'string'],
[['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['user_id' => 'id']],
[['staff_ids', 'student_ids', 'oi_ids', 'fi_ids'], 'each', 'rule' => ['integer']],
];
}
/**
* @inheritdoc
*/
public function behaviors()
{
return [
[
'class' => \voskobovich\behaviors\ManyToManyBehavior::className(),
'relations' => [
'staff_ids' =>'staff',
'student_ids' => 'student',
'oi_ids' =>'oi',
'fi_ids' =>'fi',
],
],
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => Yii::t('app', 'ID'),
'job_title' => Yii::t('app', 'Название работы'),
'types' => Yii::t('app', 'Тип'),
'indexing' => Yii::t('app', 'Индексация в БД Scope'),
'status' => Yii::t('app', 'Статус'),
'country' => Yii::t('app', 'Страна'),
'output_data' => Yii::t('app', 'Исходные данные'),
'published_sumdu' => Yii::t('app', 'Публикация вуза'),
'student_publication' => Yii::t('app', 'Публикация студента'),
'user_id' => Yii::t('app', 'Пользователь ID'),
];
}
/**
* @return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
public function getStaff()
{
return $this->hasMany(Staff::className(), ['id' => 'staff_id'])
->viaTable('{{%ssu_composite}}', ['publication_id' => 'id']);
}
public function getStudent()
{
return $this->hasMany(Student::className(), ['id' => 'student_id'])
->viaTable('{{%ssu_composite}}', ['publication_id' => 'id']);
}
public function getOi()
{
return $this->hasMany(Oi::className(), ['id' => 'oi_id'])
->viaTable('{{%ssu_composite}}', ['publication_id' => 'id']);
}
public function getFi()
{
return $this->hasMany(Fi::className(), ['id' => 'fi_id'])
->viaTable('{{%ssu_composite}}', ['publication_id' => 'id']);
}
/**
* @inheritdoc
* @return PublicationsQuery the active query used by this AR class.
*/
public static function find()
{
return new PublicationsQuery(get_called_class());
}
}`
@zhe17065564 с такой логикой как у вас работать не будет. Если посмотрите в код, то увидите, что перед записью связей из связующей таблицы все удаляется и записывается заново.
Я не могу знать тонкости вашей архитектуры БД, но лучше для организации каждой связи делать отдельную таблицу - это правильно. Почитайте еще подробно про организацию связей много-ко-многим, и вы поймете о чем я говорю.
То есть плохо хранить все в одной таблице ssu_composite
, а нужно сделать 4 отдельные. На количество запросов к БД это никак не должно повлиять.
Но если вы не захотите переделывать, тогда вам подойдет мое новое поведение Yii2 Linker Behavior в котором вы можете использовать ManyToManySmartUpdater
. Он не удаляет связи, а ищет разницу и вносит ее в таблицу. Это требует больше запросов к БД, но за-то не перезаписывает все связи.
Прошу прощения за поздний ответ. Не получал писем от гитхаба:(