Ralph Janssen
Ralph Janssen

Reputation: 116

How to attach a relationship the right way in Laravel

I want to a connect two tables with a relation. The tables gets updated but not as expected. In one case I get the same record 2 times , in other method I'm getting only one record with no data.

With the attach method i get two times the same record and each time i'm sending the same request it creates the same records as before.

With the sync method it only adds the last record from the loop. I think sync is the way to go, because it doesn't create new records when sending the same request.

    // Network Model
    public function accounts() {
        return $this->belongsToMany('App\Account');
    }

    // Account Model
    public function networks() {
        return $this->belongsToMany('App\Models\Network')- 
        >withPivot('url');
    }


    // Updateprofile function in accounts controller
    $accounts = $request->get('accounts');

    foreach ($accounts as $key => $account) {

       $accountModel = Account::where("id", "=", $account['id'])- 
       >first();

       /* 
          Some other fields that get updated ...
       */

       $networks = 
       Network::find(Helper::getValueOrDefault(AuthConst::NETWORK, 
       $account, []));

       foreach ($account['network'] as $key => $network) {
          $accountModel->networks()->sync($network, ['url' => 
          $network['url'], 'network_id' => $network['id']]);
        }

        $accountModel->save();
     }

DB structure

Accounts Table
ID | And some metafields

Network Table
ID | Name | slug

Account_network relation Table
ID | network_id | account_id | url

The request gives an array called network with one or more objects

array(2) {
  [0]=>
  array(2) {
    ["id"]=>
    int(3)
    ["url"]=>
    string(19) "http://facebook.com"
  }
  [1]=>
  array(2) {
    ["id"]=>
    int(2)
    ["url"]=>
    string(18) "http://youtube.com"
  }
}

I expect that this wil attached to the right account with two records added to the Account_network table.

ID | network_id | account_id | url 
1 | 3 | 1| http://facebook.com
2 | 2 | 1| http://youtube.com

And i expect when sending the same request, it does nothing because the records already exists.

Upvotes: 0

Views: 264

Answers (2)

mrhn
mrhn

Reputation: 18926

Sync() will delete all the ids in the table there is not in the input of the method, if you just want to add an entry to the many to many relation. You can utilize the syncWithoutDetaching() method.

foreach ($account['network'] as $key => $network) {
    $accountModel->networks()->syncWithoutDetaching($network, ['url' => 
    $network['url'], 'network_id' => $network['id']]);
}

Upvotes: 0

Dino Numić
Dino Numić

Reputation: 1452

Attach only adds a new record to the pivot table. Sync accepts an id or an array of ids, removes all records and inserts only those present in the sync method. It accepts a second parameter as a bool which allows you to prevent this removal or you can use a syncWithoutDetaching method. So you don't need a foreach with sync as it will not work as you have intended.

Upvotes: 2

Related Questions