Как справиться с симметричным отношением к одной и той же таблице в Laravel? - PullRequest
1 голос
/ 18 апреля 2019

У меня есть таблица продуктов в моем проекте 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, она создает отношение, которое работает в обоих направлениях.

Я определяю метод в моей модели продукта для получения идентификаторов связанных продуктов:

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

Этот метод использует функцию в модели Products следующим образом:

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

У меня возникли некоторые проблемы при выполнении этого «пути ларавеллы». Очевидно, что когда я получаю связанные продукты для определенного идентификатора продукта $, мне нужно получить все записи в 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 для запроса второго идентификатора из сводной таблицы, я мог бы каким-то образом присоединиться к функции в контроллере? Может быть, что-то вроде этого:

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

Тогда как правильно сформулировать оператор контроллера, чтобы он смотрел здесь отношения как в связанных (), так и связанных () функциях:

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

Мне интересно, может быть, есть лучший способ сделать это? Может кто-нибудь показать мне, как рекомендуется справляться с этим в Laravel?

1 Ответ

0 голосов
/ 08 мая 2019

С небольшой помощью друга мне удалось решить эту проблему. Мне не хватало обратной зависимости в контроллере продукта.

if (method_exists ($ data, 'related')) { $ association = ($ request-> has ('association'))? $ request-> get ('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);
        });
    }
...