如何在laravel中处理与同一张桌子的对称关系?

时间:2019-04-18 20:07:01

标签: php laravel-5 voyager

我的Laravel项目中有一个产品表,产品。我还有另一个表, product_assocs

CREATE TABLE `product_assocs` (
  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `product_id_primary` bigint(20) UNSIGNED DEFAULT NULL,
  `product_id_assoc` bigint(20) UNSIGNED DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

这使我可以相互关联相关产品。我希望这些关系是对称的。也就是说,如果您在product_assocs表中创建一条记录,则它会创建一个双向运行的关系。

我正在产品模型中定义一个方法来获取关联产品的ID:

$associationsForProduct = $product->associated()->get();

此方法利用Products模型中的函数,如下所示:

public function associated() {
      return $this->belongsToMany(Product::class, 'product_assocs', 'product_id_primary', 'product_id_assoc');

我在做这种“幼虫方式”时遇到了一些麻烦。显然,当我获得与特定产品$ id的关联产品时,我必须在product_assocs中的id1=$id OR id2=$id处获取所有记录。我可以想象一个老式的PHP循环可以完成此任务:

// assume $assocs is an array of records fetched where product_id_primary=$id or product_id_assoc=$id
// assume $id is the current product for which we are fetching records
$clean = array();
foreach($assocs as $asc) {
  if ($asc["product_id_primary"] != $id && !in_array($asc["product_id_primary"], $clean)) {
    $clean[] = $asc["product_id_primary"];
  }
  if ($asc["product_id_assoc"] != $id && !in_array($asc["product_id_assoc"], $clean)) {
    $clean[] = $asc["product_id_assoc"];
  }

}

我是不是了解一下,如果我在Product模型中创建了一个倒数功能,以便从数据透视表中查询第二个ID,我可以以某种方式将其加入控制器中吗?也许是这样的:

public function related() {
      return $this->belongsToMany(Product::class, 'product_assocs', 'product_id_assoc', 'product_id_primary');

然后,如何正确地构造控制器语句,以便它在此处在related()和related()函数中查找关系:

$associationsForProduct = $product->[--associated()--OPERAND --related()]->get();

我想知道是否有更好的方法可以实现这一目标。 有人可以告诉我如何在Laravel中处理该问题吗?

1 个答案:

答案 0 :(得分:0)

在朋友的帮助下,我设法解决了这个问题。我在产品控制器中缺少逆关系。

if(method_exists($ data,'associated')){             $ association =($ request-> has('association'))? $ request-> get('association'):[];             $ data-> associated()-> sync($ association);

        // create the inverse relationships
        $associated = Product::whereIn('id', $association)->get()->each(function($product) use ($data) {
            // doing a remove first to prevent duplicate entries
            $product->associated()->detach($data->id);
            $product->associated()->attach($data->id);
        });
    }