2

I have a model X that has a many-to-many relationship with the Word model. In the controller of the X model, I have a custom form widget which submits a wordId via ajax, and save that relationship:

public function onAddWord()
{
    $wordId = post($this->getFieldName());

    if (is_numeric($wordId)) {
        $this->model->words()->syncWithoutDetaching([$wordId]);
    } else {
        // if the word that user selected, was not in the list, wordId does not contain any ID,
        // but it's the actual new word the needs to be added to the words table
        $newWord     = WordModel::create(
            [
                'word'    => $wordId,
                'lang_id' => 2,
            ]
        );
        $this->model->words()->attach($newWord->id);
    }

    // refresh the relation manager list
    return $this->controller->relationRefresh('related_words');
}

This works perfectly when I am updating model X. But when I am in the create page of model X, saving the above relations fails, because model X does not exist yet. I tried to use differed binding, but it didn't work:

public function onAddWord()
{
    $sessionKey = $this->controller->formGetSessionKey();

    $wordId = post($this->getFieldName());

    if (is_numeric($wordId)) {
        $this->model->words()->syncWithoutDetaching([$wordId]);
    } else {
        // if the word that user selected, was not in the list, wordId does not contain any ID,
        // but it's the actual new word the needs to be added to the words table
        $newWord     = WordModel::create(
            [
                'word'    => $wordId,
                'lang_id' => 2,
            ], $sessionKey
        );
        $this->model->words()->attach($newWord->id, $sessionKey);
    }

    // refresh the relation manager list
    return $this->controller->relationRefresh('related_words');
}

How can I make this work?

B Faley
  • 17,120
  • 43
  • 133
  • 223
  • hmmm may be `attach method` is not supporting `$sessionKey`, may be try using `add method` , docs : https://octobercms.com/docs/api/october/rain/database/relations/belongstomany. please can you try it and let us know – Hardik Satasiya Apr 29 '20 at 07:49
  • @HardikSatasiya I think `add` is for one-to-many relationships. The words relationship in my example is many-to-many. – B Faley Apr 29 '20 at 07:57
  • i guess i posted correct docs https://octobercms.com/docs/database/relations#many-to-many -> its `belongsToMany` relation in each modal and API https://octobercms.com/docs/api/october/rain/database/relations/belongstomany is also correct. you can check code there is no `attach` method which can have `sessionKey` there is only `add` method who can do same with `sessionKey` and `object`. kindly check those details – Hardik Satasiya Apr 29 '20 at 08:40
  • This occurs because the new post does not exist yet and can't be attached to the pivot table. My suggestion is to have a hidden (from display) column in the table that can take the id of the new `$newWord`. Then use the `afterSave()` method available to models to attach the relation. Would this work? – Pettis Brandon Apr 29 '20 at 17:15
  • `new post does not exist ` <- that is why we are using `deferred binding` isn't it @PettisBrandon ? – Hardik Satasiya Apr 30 '20 at 06:35
  • 1
    Yeah but Meysam said "*I tried to use differed binding, but it didn't work*" I was just thinking of a different approached than `deferred binding`. @HardikSatasiya – Pettis Brandon May 01 '20 at 17:10
  • 1
    @Meysam Hardik is correct with the `add method` . If you look at the docs there is a topic on [this page](https://octobercms.com/docs/database/relations#inserting-method) that talks about adding with pivot data to `many-to-many` relationship. "*The second argument of the `add` method can also specify the session key used by deferred binding...*" `$user->roles()->add($role, $sessionKey, $pivotData);` – Pettis Brandon May 01 '20 at 17:30
  • 1
    @PettisBrandon @HardikSatasiya You are right. Add with `$sessionKey` works. The only problem is that I cannot use the sync method anymore, so I have to find the word and then add it only if it does not exist, to simulate the functionality of sync. – B Faley May 01 '20 at 18:10

0 Answers0