Сложно все. Непонятно...
По итогу имеем слудующее:
Модель Item
Код: Выделить всё
private $_categories;
...
/**
* @return \yii\db\ActiveQuery
*/
public function getCategories()
{
return $this->hasMany(Category::className(), ['id' => 'category_id'])
->viaTable('item_category', ['item_id' => 'id']);
}
public function setCategories($categories)
{
if (!empty($categories)) {
if (!is_array($categories)) {
$categories = array($categories);
}
foreach ($categories as $category) {
if ($category instanceof Category) {
$this->_categories[] = $category;
} else {
$this->_categories[] = Category::findOne(['id' => $category]);
}
}
}
}
public function afterSave($insert, $changedAttributes)
{
ItemCategory::deleteAll(['item_id' => $this->id]);
if (is_array($this->_categories)) {
foreach ($this->_categories as $category) {
$this->link('categories', $category);
}
}
return parent::afterSave($insert, $changedAttributes);
}
Т.е. во время загрузки модели через метод
все данные загружаются в модель, при этом категории грузятся в приватный член. Это удобно, что можно передать POST-данные скопом, а не парсить их в контроллере. После успешного сохранения, когда появляется id модели, мы в afterSave связываем модель Category с Item через метод link().
Все работает, но вот осадок какой-то присутствует. Есть подозрение, что я что-то делаю не так как планировали разработчики ядра.
Почему-то в setCategories передаются то объекты Category, то массив с id из формы. Где и как правильно транзакцию начинать, чтобы в случае ошибки в afterSave можно было откатить все обратно? Как правильно проводить валидацию массива _categories?