I'm trying to use a custom attribute in a model class that extends db\activerecord
.
I've tried declaring public $categories = []
and then either assigning values to it directly via $model->categories = [1,2,3]
or using a setter method in my model class public function setCategories($ids) {...
and then again assigning via $model->categories = [1,2,3]
.
I've also tried updating the attribute with $model->setAttribute('categories', [1,2,3])
.
In all cases $model->categories
is not populated.
My end goal is to assign categories to a model and then update the db relation/tables using afterSave()
and beforeSave()
Can this be done or should I extend my model class from db\model
? If I do, what functionality will I lose?
Edit I might have misstated my problem.
I've got a form where a user can select categories for a specific model (ie "Product"). All categories are pre-existing and products are assigned to categories via a junction table product_category('product_id', 'category_id') with a one-to-many relationship (one product has many categories).
Now in the controller that's handling the view, I'm receiving a list of category id's and I want to assign them to an attribute so that I can process them i.e. delete or add (via link()
) entries in the product_category table for the specific product.
class ClassName extends \yii\db\ActiveRecord
{
public $addition; //what attribute you want
/* your code */
public function fields()
{
$fields = parent::fields();
$fields[] = 'addition'; //the value must be the same as the new attribute
/* your code */
$this->addition = 'done'
return $fields
}
}
It looks to me like you are manually trying to do relations between tables? Why not use the built in functionality and have it taken care of for you?
For this (many-to-many) you need a link activerecord or table that indicates which models link to which categories (I'm assuming here that you have an ActiveRecord
that is called ModelCategory
and has a model_id
and a category_id
:
public function getProductCategories()
{
return $this->hasMany(ProductCategory::className(), ['product_id' => 'id']);
}
public function getCategories()
{
return $this->hasMany(Category::className(), ['id' => 'category_id'])
->via('productCategories');
}
(You can also use viaTable()
instead of via()
and avoid an extra method, that is your choice.)
This means that you can access them like so:
$product->categories
(always use the magic functionality for relations, it's the __get() function that actually does the database query).
For assigning relations there is no automatic method. Yii has some assisting functions for this though:
$category = new Category();
// Assign attributes
$category->save();
$product = new Product();
// Assign attributes
$product->save();
$product->link('categories', $category);
Check out the link
-function for more details.
Obviously there are other ways as well, but it depends on your needs.
As per your extra information:
public function actionAssignCategories($product, $categories)
{
$product = Product::findOne($product);
$existingCategories = \yii\base\ArrayHelper::getColumn($product->categories, 'category_id');
$removeCategories = array_diff($existingCategories, $categories);
$addCategories = array_diff($categories, $existingCategories);
foreach ($addCategories as $category) {
$category = Category::findOne($category);
$product->link('categories', $category);
}
foreach ($removeCategories as $category) {
$category = Category::findOne($category);
$product->unlink('categories', $category);
}
}
Untested, but that should give you an idea on how to tackle this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With