Using forms to save many-to-many association data

Hi everyone,
I need some help with saving many to many relations associated data using forms for Cakephp 3.x.
I have the tables publications, artifacts and they have a many to many relation using table artifacts_publications. This association table has additional fields exact_reference, publication_comments and publication_type.
I’m trying to link artifacts to a publication when editing the selected publication using the publication form.

The resulting post data from the form is shown below:

[
	'ids' => [
		(int) 0 => '1',
		(int) 1 => '5'
	],
	'bibtexkey' => 'Abusch1981',
	'year' => '1970',
	'entry_type_id' => '5',
	'address' => '',
	'annote' => '',
	'book_title' => 'In Honor of Ernest R. Lacheman on His Seventy-fifth Birthday, April 29, 1981',
	'chapter' => '',
	'crossref' => '',
	'edition' => '',
	'how_published' => 'test',
	'institution' => 'ashdfkahsg',
	'journal_id' => '49',
	'month' => '',
	'note' => '',
	'number' => '',
	'organization' => '',
	'pages' => '1-9',
	'publisher' => 'Eisenbrauns: Winona Lake',
	'school' => '',
	'title' => 'Notes on a Pair of Matching Texts: A Shepherd’s Bulla and an Owner’s Receipt',
	'volume' => '1',
	'publication_history' => '',
	'series' => 'SCCNH',
	'oclc' => '',
	'designation' => 'designation new',
	'artifacts' => [
		(int) 0 => [
			'id' => '3',
			'_joinData' => [
				'exact_reference' => 'Ref 1',
				'publication_type' => 'primary',
				'publication_comments' => '42x53x19; Vocabulary 9; Qa XVI,2, unter der Abgleichung der Schicht III, 1,5 m über der Höhe des Kalksteinsockels (t.a.q. IIIc); veröffentlicht in: ATU 1, 539; bereits kommentiert von A. Falkenstein, UVB 3, 12 und ATU 1, S. 43-45.'
			]
		],
		(int) 1 => [
			'id' => '4',
			'_joinData' => [
				'exact_reference' => 'Ref 2',
				'publication_type' => 'primary',
				'publication_comments' => '26x23x23; Lú A 9-10.?.?; Fundstelle wie W 9123,d; veröffentlicht in: ATU 1, 489.'
			]
		]
	]
]

But on using patchEntity() to load the data into the entity object, the resulting value for the ‘artifacts’ field is null (‘artifacts’ => null). Can someone help me with correcting what I am doing wrong?

Code:

PublicationsController.php (part of the code):

/**
 * Merging selected publications.
 */
public function merge($id = null) {
    if ($this->request->is('post')) {
        $data = $this->request->getData();
        debug($data);
         if ((!isset($data['ids'])) or count($data['ids']) < 2) {
             $this->Flash->error(__('Atleast two publications need to be selected for merging.'));
             return $this->redirect(['action' => 'mergeSelect']);
        }
        $publication_merge = $this->Publications->get(1, [
            'contain' => ['Artifacts']
        ]);
        $publications = $this->Publications->find('all', [
            'conditions' => ['id IN' => $data['ids']],
            'contain' => ['Authors', 'Artifacts']
        ]);
        
        if (isset($id)) {
            $publication_merge = $this->Publications->patchEntity($publication_merge, $data, [
                'associated' => ['Artifacts']
            ]);
            debug($publication_merge);
            if($this->Publications->save($publication_merge)) {
                foreach (array_slice($publications->toArray(),1) as $entity) {
                    $this->Publications->delete($entity);
                }
                $this->Flash->success('Successfully merged all publications.');
            } else {
                $this->Flash->error('Could not merge.');
            }
        }
        // debug($publication);
    }

    $entryTypes = $this->Publications->EntryTypes->find('list', [
        'keyField' => 'id',
        'valueField' => 'label',
        'order' => 'label'
    ])->toArray();
    $journals = $this->Publications->Journals->find('list', [
        'keyField' => 'id',
        'valueField' => 'journal',
        'order' => 'journal'
    ])->toArray();
    $publication_type_options = [
        'primary' => 'primary',
        'electronic' => 'electronic',
        'citation' => 'citation',
        'collation' => 'collation',
        'history' => 'history',
        'other' => 'other'
    ];
    $this->set(compact('publications', 'publication_merge', 'entryTypes', 'journals', 'publication_type_options'));
    
}

merge.ctp:

<h3 class="display-4 pt-3"><?= __('Selected Publications') ?></h3>

<?= $this->Form->create($publication_merge, ['action' => 'merge', 'type' => 'post']) ?>
<table cellpadding="0" cellspacing="0" class="table-bootstrap my-3">
    <thead>
        <tr>
            <!-- <th scope="col"><?= $this->Paginator->sort('id') ?></th> -->
            <th scope="col"><?= $this->Paginator->sort('year') ?></th>
            <th scope="col"><?= $this->Paginator->sort('entry_type_id') ?></th>
            <th scope="col"><?= $this->Paginator->sort('address') ?></th>
            <th scope="col"><?= $this->Paginator->sort('annote') ?></th>
            <th scope="col"><?= $this->Paginator->sort('book_title') ?></th>
            <th scope="col"><?= $this->Paginator->sort('chapter') ?></th>
            <th scope="col"><?= $this->Paginator->sort('crossref') ?></th>
            <th scope="col"><?= $this->Paginator->sort('edition') ?></th>
            <th scope="col"><?= $this->Paginator->sort('how_published') ?></th>
            <th scope="col"><?= $this->Paginator->sort('institution') ?></th>
            <th scope="col"><?= $this->Paginator->sort('journal_id') ?></th>
            <th scope="col"><?= $this->Paginator->sort('month') ?></th>
            <th scope="col"><?= $this->Paginator->sort('note') ?></th>
            <th scope="col"><?= $this->Paginator->sort('number') ?></th>
            <th scope="col"><?= $this->Paginator->sort('organization') ?></th>
            <th scope="col"><?= $this->Paginator->sort('pages') ?></th>
            <th scope="col"><?= $this->Paginator->sort('publisher') ?></th>
            <th scope="col"><?= $this->Paginator->sort('school') ?></th>
            <th scope="col"><?= $this->Paginator->sort('title') ?></th>
            <th scope="col"><?= $this->Paginator->sort('volume') ?></th>
            <th scope="col"><?= $this->Paginator->sort('abbreviation_id') ?></th>
            <th scope="col"><?= $this->Paginator->sort('series') ?></th>
            <th scope="col"><?= $this->Paginator->sort('oclc') ?></th>
        </tr>
    </thead>
    <tbody>
        <?php foreach ($publications as $publication): ?>
        <tr>
            <!-- <td><?= $this->Number->format($publication->id) ?></td> -->
            <?= $this->Form->input('ids[]', ['type' => 'hidden', 'value' => $publication->id]) ?>
            <td><?= h($publication->year) ?></td>
            <td><?= $publication->has('entry_type') ? $this->Html->link($publication->entry_type->title, ['controller' => 'EntryTypes', 'action' => 'view', $publication->entry_type->id]) : '' ?></td>
            <td><?= h($publication->address) ?></td>
            <td><?= h($publication->annote) ?></td>
            <td><?= h($publication->book_title) ?></td>
            <td><?= h($publication->chapter) ?></td>
            <td><?= h($publication->crossref) ?></td>
            <td><?= h($publication->edition) ?></td>
            <td><?= h($publication->how_published) ?></td>
            <td><?= h($publication->institution) ?></td>
            <td><?= $publication->has('journal') ? $this->Html->link($publication->journal->journal, ['controller' => 'Journals', 'action' => 'view', $publication->journal->id]) : '' ?></td>
            <td><?= h($publication->month) ?></td>
            <td><?= h($publication->note) ?></td>
            <td><?= h($publication->number) ?></td>
            <td><?= h($publication->organization) ?></td>
            <td><?= h($publication->pages) ?></td>
            <td><?= h($publication->publisher) ?></td>
            <td><?= h($publication->school) ?></td>
            <td><?= h($publication->title) ?></td>
            <td><?= h($publication->volume) ?></td>
            <td><?= $publication->has('abbreviation') ? $this->Html->link($publication->abbreviation->abbreviation, ['controller' => 'Abbreviations', 'action' => 'view', $publication->abbreviation->id]) : '' ?></td>
            <td><?= h($publication->series) ?></td>
            <td><?= $this->Number->format($publication->oclc) ?></td>
        </tr>
        <?php endforeach; ?>
    </tbody>
</table>

<h3 class="display-4 pt-3"><?= __('Merged Publication Details') ?></h3>
<div class="col-lg boxed">
    <legend class="capital-heading"><?= __('Publication Data') ?></legend>
        <table cellpadding="10" cellspacing="10">
            <tr>
                <td>Bibtex Key:</td>
                <td><?php echo $this->Form->control('bibtexkey', ['label' => '', 'type' => 'text']); ?></td>
            </tr>
            <tr>
                <td>Year:</td>
                <td><?php echo $this->Form->control('year', ['label' => '', 'type' => 'text', 'maxLength' => 20]); ?></td>
            </tr>
            <tr>
                <td>Entry Type ID:</td>
                <td><?php echo $this->Form->control('entry_type_id', ['label' => '', 'options' => $entryTypes, 'empty' => true]);  ?></td>
            </tr>
            <tr>
                <td>Address:</td>
                <td><?php echo $this->Form->control('address', ['label' => '', 'type' => 'text', 'maxLength' => 45]);  ?></td>
            </tr>
            <tr>
                <td>Annote:</td>
                <td><?php echo $this->Form->control('annote', ['label' => '', 'type' => 'text', 'maxLength' => 45]);  ?></td>
            </tr>
            <tr>
                <td>Book Title:</td>
                <td><?php echo $this->Form->control('book_title', ['label' => '', 'type' => 'text', 'maxLength' => 255]);  ?></td>
            </tr>
            <tr>
                <td>Chapter:</td>
                <td><?php echo $this->Form->control('chapter', ['label' => '', 'type' => 'text', 'maxLength' => 100]);  ?></td>
            </tr>
            <tr>
                <td>Cross Reference:</td>
                <td><?php echo $this->Form->control('crossref', ['label' => '', 'type' => 'text', 'maxLength' => 45]);  ?></td>
            </tr>
            <tr>
                <td>Edition:</td>
                <td><?php echo $this->Form->control('edition', ['label' => '', 'type' => 'text', 'maxLength' => 45]);  ?></td>
            </tr>
            <tr>
                <td>How Published:</td>
                <td><?php echo $this->Form->control('how_published', ['label' => '', 'type' => 'text', 'maxLength' => 255]);  ?></td>
            </tr>
            <tr>
                <td>Institution:</td>
                <td><?php echo $this->Form->control('institution', ['label' => '', 'type' => 'text', 'maxLength' => 45]);  ?></td>
            </tr>
            <tr>
                <td>Journal:</td>
                <td><?php echo $this->Form->control('journal_id', ['label' => '', 'options' => $journals, 'empty' => true]);  ?></td>
            </tr>
            <tr>
                <td>Month:</td>
                <td><?php echo $this->Form->control('month', ['label' => '', 'type' => 'text', 'maxLength' => 45]);  ?></td>
            </tr>
            <tr>
                <td>Note:</td>
                <td><?php echo $this->Form->control('note', ['label' => '', 'type' => 'text', 'maxLength' => 45]);  ?></td>
            </tr>
            <tr>
                <td>Number:</td>
                <td><?php echo $this->Form->control('number', ['label' => '', 'type' => 'text', 'maxLength' => 100]);  ?></td>
            </tr>
            <tr>
                <td>Organization</td>
                <td><?php echo $this->Form->control('organization', ['label' => '', 'type' => 'text', 'maxLength' => 45]);  ?></td>
            </tr>
            <tr>
                <td>Pages:</td>
                <td><?php echo $this->Form->control('pages', ['label' => '', 'type' => 'text', 'maxLength' => 45]);  ?></td>
            </tr>
            <tr>
                <td>Publisher:</td>
                <td><?php echo $this->Form->control('publisher', ['label' => '', 'type' => 'text', 'maxLength' => 100]);  ?></td>
            </tr>
            <tr>
                <td>School:</td>
                <td><?php echo $this->Form->control('school', ['label' => '', 'type' => 'text', 'maxLength' => 80]);  ?></td>
            </tr>
            <tr>
                <td>Title:</td>
                <td><?php echo $this->Form->control('title', ['label' => '', 'type' => 'text', 'maxLength' => 255]);  ?></td>
            </tr>
            <tr>
                <td>Volume:</td>
                <td><?php echo $this->Form->control('volume', ['label' => '', 'type' => 'text', 'maxLength' => 50]);  ?></td>
            </tr>
            <tr>
                <td>Publication History:</td>
                <td><?php echo $this->Form->control('publication_history', ['label' => '', 'type' => 'text']);  ?></td>
            </tr>
            <tr>
                <td>Series:</td>
                <td><?php echo $this->Form->control('series', ['label' => '', 'type' => 'text', 'maxLength' => 100]);  ?></td>
            </tr>
            <tr>
                <td>OCLC:</td>
                <td><?php echo $this->Form->control('oclc', ['label' => '', 'type' => 'number']);  ?></td>
            </tr>
            <tr>
                <td>Designation:</td>
                <td><?php echo $this->Form->control('designation', ['label' => '', 'type' => 'text']); ?></td>
            </tr>
        </table>

        <legend class="capital-heading"><?= __('Linked Artifacts Data') ?></legend>

        <table cellpadding="10" cellspacing="10">
        <thead>
        <tr>
            <th scope="col">Artifact Information</th>
            <th scope="col">Artifact ID</th>
            <th scope="col">Publication ID</th>
            <th scope="col">Exact Reference</th>
            <th scope="col">Publication Type</th>
            <th scope="col">Publication Comments</th>
        </tr>
        </thead>
        <tbody>
            <?php foreach ($publication_merge->artifacts as $key => $artifactsPublication): ?>
                <?= $this->Form->input("artifacts.{$key}._id", ['type' => 'hidden', 'value' => $artifactsPublication->id]) ?>  
                <!-- <?= debug($artifactsPublication) ?> -->
                <tr>  
                   <td></td>
                    <td><?= $this->Html->link($artifactsPublication->_joinData->artifact_id, ['controller' => 'Artifacts', 'action' => 'view', $artifactsPublication->_joinData->artifact_id]) ?></td>
                    <td><?= $this->Html->link($artifactsPublication->_joinData->publication_id, ['controller' => 'Publications', 'action' => 'view', $artifactsPublication->_joinData->publication_id]) ?></td>
                    <td><?= $this->Form->input("artifacts.{$key}._joinData.exact_reference", ['label' => '', 'type' => 'text']); ?></td>
                    <td><?= $this->Form->input("artifacts.{$key}._joinData.publication_type", ['label' => '', 'type' => 'select', 'options' => $publication_type_options]); ?></td>
                    <td><?= $this->Form->input("artifacts.{$key}._joinData.publication_comments", ['label' => '', 'type' => 'textarea']); ?></td>
                </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
    
<?= $this->Form->submit('Submit', ['class' => 'btn btn-primary']) ?>
<?= $this->Form->end() ?>

</div>

Please post your code so that we can help you.

I’ve added part of the code which is needed here. Please let me know if something else is required.