Problem saving associated data. CakePHP 3

Hi everybody.

I´ve a problem saving associated data. Im saving “Users” and the associated data “Groups”. The problem is when I´m saving a id of a group that not exists or the id of the group is zero, cakephp creates a new registry in the table of “Groups”. I only want to save the association if the group exists. There is any way to do this?

// Templates/Users/create_user.ctp

<?= $this->Form->create($user) ?>
  <?= $this->Form->control('name'); ?>
  <?= $this->Form->control('date'); ?>
  <?= $this->Form->control('groups.0.id', ['options'=>$groups, 'type' => 'select', 'empty' => __('No group')]); ?>
  <?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>



// Controllers/UsersController.php

public function createUser() {

	$user = $this->Users->newEntity();
    $groups = $this->Groups->find('list');                         

    if ($this->request->is('post')) {
    	$this->Users->patchEntity($user, $this->request->getData(), ['associated' => ['Groups'] ]);

        if ($this->Users->save($user)) {
            $this->Flash->success(__('Data saved successfully'));
            return $this->redirect(['action' => 'createUser']);
        } else {
            $this->Flash->error('Error');
        }
    }
	
	$this->set(compact('users','groups'));
}


// Model/Table/UsersTable.php

class UsersTable extends Table {

    public function initialize(array $config) {
        parent::initialize($config);

        $this->setTable('users');
        $this->setPrimaryKey('id');
        $this->addBehavior('Timestamp');

        $this->belongsToMany('Groups', [
        	'joinTable' => 'groups_users',
            'foreignKey' => 'user_id',
            'dependent' => false
        ]);
    }
}

Request data in controller:

[ 
    name => "...",
    date => "...",
    groups => [
        0 => [
            id => 0    
        ]
    ]
]

Database previous save the new user:

Users
id | name | date
1 | “…” | “…”

Groups
id | name

GroupsUsers
id | group_id | user_id

Database after save the new user:

Users
id | name | date
1 | “…” | “…”
2 | “…” | “…”

Groups
id | name
2 |

GroupsUsers
id | group_id | user_id
1 | 0 | 1

Thanks you.

I think You can check your ctp file interpreted in the well format then get that id in controller.

By the way check in the web developers tools so that then get that id to controller then save that database.

1 Like

You should not create the input fields “manually”. Use the mechanisms CakePHP provides instead:

https://book.cakephp.org/3.0/en/views/helpers/form.html#creating-inputs-for-associated-data

You can check the content of the object in the controller action before/after saving using $this->log($user) (will write to error-log). This might help you to find data-driven errors (such as wrongly named fields)

Hope this helps

1 Like

I´ve edited the code. Now it´s written in CakePHP`s syntaxis. But my problem it´s the same. I´ve check the data received and they are the expected. I think the problem is the CakePHP´s behavior, and I want that CakePHP only save the data in “GroupsUsers” and not in “Groups”.

I´ve change the code to a CakePHP´s syntaxis. I want CakePHP only save de relational data (table “GroupsUsers”), but if the group.0.id input is 0 or an id that not exists in “Groups” table CakePHP creates a new Group and a new GroupUser.

If you only want the relation to be saved in GroupsUsers, why do you specify belongsToMany-Groups instead of belongsToMany-GroupsUsers (or whatever type your relationship is) ?

Is it possible that you want to implement HABTM between Users and Groups here?

Regarding your original question:
You can e.g. check if your users-object contains a group with a valid ID (so it seems to exist) before saving and if not, do

unset($user->groups)

to prevent the group from being created.

It´s true, I should use the relation to the GroupsUsers directly, this way new groups can´t be created. The problem of to save not existing ids or 0 can be solved with unset or other code as you say, but I would like to know if CakePHP can check automaticly if the relation is valid before save.

thanks you!

Ok, got it.

Unfortunately, the only other way that comes to my mind would be to create validation rules in the specific tables to achieve this. You could then use a different rule-set on a “admin-method” to create groups or so.

However, I’m currently not sure if the “base”-entity will save if saving the association fails…