Yii2 activerecord 自定义属性

jim*_*mmy 5 php activerecord yii2

我正在尝试在扩展的模型类中使用自定义属性db\activerecord

我试过声明public $categories = [],然后直接通过$model->categories = [1,2,3]或在我的模型类中使用 setter 方法为其public function setCategories($ids) {...赋值,然后再次通过$model->categories = [1,2,3].

我也试过用$model->setAttribute('categories', [1,2,3]).

在所有情况下$model->categories都不填充。

我的最终目标是为模型分配类别,然后使用afterSave()和更新数据库关系/表beforeSave()

这可以完成还是我应该从 扩展我的模型类db\model?如果我这样做了,我会失去什么功能?

编辑 我可能误报了我的问题。

我有一个表单,用户可以在其中为特定模型(即“产品”)选择类别。所有类别都是预先存在的,并且产品通过具有一对多关系的连接表 product_category('product_id', 'category_id') 分配给类别(一个产品有多个类别)。

现在在处理视图的控制器中,我收到了一个类别 ID 列表,我想将它们分配给一个属性,以便我可以处理它们,即删除或添加(通过link())特定产品的 product_category 表中的条目。

Bli*_*izz 2

在我看来,您似乎正在手动尝试建立表之间的关系?为什么不使用内置功能并让其为您处理呢?

对于这个(多对多),您需要一个链接 activerecord 或表来指示哪些模型链接到哪些类别(我在这里假设您有一个ActiveRecord被称为ModelCategory并且有 amodel_id和 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');
}
Run Code Online (Sandbox Code Playgroud)

(您也可以使用viaTable()替代via()和避免额外的方法,这是您的选择。)

这意味着您可以像这样访问它们:

$product->categories  
Run Code Online (Sandbox Code Playgroud)

(始终使用关系的神奇功能,实际上是 __get() 函数执行数据库查询)。

对于分配关系,没有自动方法。Yii 为此提供了一些辅助功能:

$category = new Category();
// Assign attributes
$category->save();

$product = new Product();
// Assign attributes
$product->save();

$product->link('categories', $category);
Run Code Online (Sandbox Code Playgroud)

查看 -link函数以获取更多详细信息。显然还有其他方法,但这取决于您的需求。

根据您的额外信息:

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);
   }
}
Run Code Online (Sandbox Code Playgroud)

未经测试,但这应该能让您了解如何解决这个问题。