Duplicate data into another table

Hello bakers :slight_smile:

I’m having a problem saving duplicate data. I’ve two (2) tables: users [id,fullname,email] and duplicates [id,fullname,email].
What I want to do is to duplicate input data from users add form into the duplicates table. Normally, we can use: duplicates.0.fullname & duplicates.0.email field in Users/add.php but I don’t want to have a duplicate input field. How can I save the users [fullname,email] into a duplicates table from the controller?
I tried the following codes to get the value from user.fullname & user.email but how can i save it?

public function add()
{
	$user = $this->Users->newEmptyEntity();
	if ($this->request->is('post')) {
	$duplicate_fullname = $this->request->getData('fullname'); //getvalue from user.fullname
	$duplicate_email = $this->request->getData('email'); //tet value from user.email
		$user = $this->Users->patchEntity($user, $this->request->getData());
		if ($this->Users->save($user)) {
			$this->Flash->success(__('The user has been saved.'));

			return $this->redirect(['action' => 'index']);
		}
		$this->Flash->error(__('The user could not be saved. Please, try again.'));
	}
	$this->set(compact('user'));
}

Thank you

After its saved correctly

you’ll need to load your duplicate model and add the record there. If you need source code on how to just ask; but conceptually that’s where it goes. Obviously you’ll need an actual duplicate model (unless its exactly the same as your users table, you may be able to sub-class its object - but I don’t know how to do that in Cake!).

If the Duplicates table is associated with the User table (even distantly) you can get to it along the association chain:

$DuplicateTable = $this->Users->NextAssociaton->Duplicates;

Or the controllers should allow this:

$DuplicatesTable = $this->getTableLocator()->get('Duplicates');

You can make any class support the ‘locator’ syntax by using the LocatorAwareTrait (Cake 4x).

Once you have a DuplicatesTable instance, patch your data and save it.

$patchData = ['name' => $duplicate_fullname, 'email' => $duplicate_email];

$duplicate = $DuplicatesTable->newEntity($patchData);

if (!$duplicate->hasErrors() && DuplicatesTable->save($duplicate) {
   //all is well
}
else {
  //problems can be found enumerated at $duplicate->getErrors();
}
1 Like

Thank you. I really appreciate your reply and solution. Problem solved :slight_smile:

The following codes is the solution:

public function add()
{
	$user = $this->Users->newEmptyEntity();
	if ($this->request->is('post')) {
		$user = $this->Users->patchEntity($user, $this->request->getData());
			$duplicate_fullname = $this->request->getData('fullname');
			$duplicate_email = $this->request->getData('email');

			$duplicatesTable = TableRegistry::getTableLocator()->get('Duplicates');
			$duplicateData = ['fullname' => $duplicate_fullname, 'email' => $duplicate_email];

			$duplicate = $duplicatesTable->newEntity($duplicateData);
		
		if ($this->Users->save($user) && $duplicatesTable->save($duplicate)) {
			$this->Flash->success(__('The user has been saved.'));
			return $this->redirect(['action' => 'index']);
		}
		$this->Flash->error(__('The user could not be saved. Please, try again.'));
	}
	$this->set(compact('user'));
}

I also found that if in table duplicates have user_id, then you need to execute the save after $this->Users->save so that you can get the user id using $user->id.

Hope this might be helpful for others :slight_smile:

That is how I would have done it, but I sense there is a proper Cake solution, from what DreamingMind posted, where the tables are associated and the Duplicate is created along the lines of an Object Oriented approach. Meaning, if you added a new Users record anywhere, not just in add() it’ll still create the Duplicate record without explicit code there.

Yes the data can be saved in one step. Modifying @Foggies code:


//this assumes Users->hasOne('Duplicates') 

public function add()
{
  $user = $this->Users->newEmptyEntity();
  if ($this->request->is('post')) {

     $patchData = $this->request->getData());
     $patchData['duplicate'] = [
        'fullname' => $this->request->getData('fullname');
        'email' => $this->request->getData('email')
     ];
     $user = $this->Users->patchEntity($user, $patchData);

     if ($this->Users->save($user)) {
        $this->Flash->success(__('The user has been saved.'));
        return $this->redirect(['action' => 'index']);
     }

     $this->Flash->error(__('The user could not be saved. Please, try again.'));
  }
  $this->set(compact('user'));
}

Cake will create User and use the new id to link Duplicate. By default this save will be done in a transaction, so no worries there.

The key to making this work lies in proper naming of the node where the associated data is attached; in this case ‘duplicate’.

//in the array
$patchData['duplicate']
//later in the entity
$user->duplicate
//hasOne makes the node name singular by default. 
//hasMany would make it plural

As a general rule, if you want to save associated data but aren’t sure how to assemble the patch array (and the subsequent entity), do a query of the association and debug the results->toArray(). This is the structure you should recreate for your save.

$result = $this->Users->find()
   ->where('User.id' => $id)
   ->contain('Duplicates')
   ->toArray();

debug($result)->toArray();