0

I have a many-to-many relationship between Invoices and Items. An Item can appear multiple times in the same Invoice, but with different amounts (e.g. when the same service is used several times during one month).

I was hoping I could create this association by including the following in the 'items' element of the invoice when saving (see https://book.cakephp.org/3/en/orm/saving-data.html#saving-belongstomany-associations):

Array
(
    [0] => Array
        (
            [id] => 1
            [_joinData] => Array
                (
                    [amount] => 5338.29
                )

        )

    [1] => Array
        (
            [id] => 1
            [_joinData] => Array
                (
                    [amount] => 5988.53
                )

        )

    [2] => Array
        (
            [id] => 1
            [_joinData] => Array
                (
                    [amount] => 6023.40
                )

        )
)

In the example above, the result I'm hoping for is that three rows are created in the join table invoices_items. The invoice is saved correctly, but only one row is created in the join table.

One both associations I tried setting saveStrategy to append (I wasn't sure what this does), but this didn't help:

  $this->belongsToMany('Invoices', [
    'saveStrategy' => 'append'
  ]);

Is it possible to achieve this behaviour out of the box, or do I need to create something more custom, like a new model to specifically keep track of these relationships? Please let me know if more code would help to clarify what I'm trying to achieve.

Thanks!

Simon
  • 123
  • 3
  • 9
  • 1
    I think the marshaller is still not capable of handling this: **https://stackoverflow.com/questions/56154557/saving-belongstomany-association-with-same-keys-but-different-joindata**. – ndm Jun 18 '20 at 22:35
  • Thanks @ndm – had not spotted this very similar question – Simon Jun 19 '20 at 02:05

1 Answers1

0

The answer seems to be that no, this type of mass assignment isn't possible. The solution I arrived at is to loop through each item I want to associate with the freshly saved invoice and call link() for each. I don't know what the performance hit is for this but for my purposes it works as this operation in my case happens relatively rarely.

        // Build an array with an element per item
        ...
        $itemsJoinData[] = [
          'item' => $item,
          '_joinData' => [
            'amount' => $amount
          ]
        ];
        ...

Once the invoice is successfully saved I attach the items with their respective amount.

        // Join up the invoice with the items
        foreach($itemsJoinData as $itemToJoin)  {
          $itemToJoin['item']->_joinData =  new Entity(['amount' => $itemToJoin['_joinData']['amount']], ['markNew' => true]); 
          $this->Invoices->Items->link( $invoice, [$itemToJoin['item']] );
        }
Simon
  • 123
  • 3
  • 9