So, I noticed that if I correct an entity (editing method) and regardless of whether I make any changes to the data in the record, if it belongs to ToMany associations, they mark them as dirty. I would expect that if I did not make changes to the BTM multiple selection in the view, the data would not be dirty only if adding or removing options in the multiple selection would be marked as dirty after correction.
The data is saved correctly, it is just dirty, but I need to act if it is dirty or clean, since I have _join data in my map table. The map table is called users_locations and has id, user_id, location_id and static, where static is tinyint / bool.
What I'm trying to do is static only for newly created map table entries.
I noticed that patchEntity robs _joinData as part of the marshaling process.
So, looking at the debug output below, you can see that _joinData is deleted after fixing for locations and user_occupations.
It seems undesirable to me not to know whether the related data is clean or dirty. Perhaps it was intended to work in this way, and I am missing something. Thoughts?
In the edit form, I have:
<?php echo $this->Form->input('locations._ids', ['options' => $locations]) ?>
In the controller, I have:
<?php
public function edit($id = null)
{
$user = $this->Users->get($id, [
'contain' => ['Locations', 'UserOccupations']
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$user = $this->Users->patchEntity($user, $this->request->data);
if ($this->Users->save($user)) {
$this->Flash->success(__('The user has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The user could not be saved. Please, try again.'));
}
}
$securityGroups = $this->Users->SecurityGroups->find('list');
$locations = $this->Users->Locations->find('list', [
'order' => ['Locations.name' => 'ASC'],
'keyField' => 'id',
'valueField' => 'name',
'limit' => 200
]);
$userOccupations = $this->Users->UserOccupations->find('list');
$this->set(compact('user', 'securityGroups', 'locations', 'userOccupations'));
$this->set('_serialize', ['user']);
}
?>
In the model, I have this in the initialization function for the user:
$this->belongsToMany('Locations', [
'through' => 'Users.UsersLocations',
'foreignKey' => 'user_id',
'targetForeignKey' => 'location_id',
'className' => 'Locations.Locations'
]);
This is the result of debugging the request data:
[
'Referer' => [
'url' => '/login'
],
'security_group_id' => '',
'username' => 'test',
'email' => 'test@test.com',
'prefix' => '',
'first_name' => 'test',
'middle_name' => '',
'last_name' => 'test',
'suffix' => '',
'credentials' => '',
'birthdate' => '',
'timezone' => 'America/New_York',
'theme' => '',
'locations' => [
'_ids' => [
(int) 0 => '7',
(int) 1 => '33'
]
],
'user_occupations' => [
'_ids' => [
(int) 0 => '1'
]
]
]
This is a custom object before fixing request data:
object(Users\Model\Entity\User) {
'id' => '8b7197a4-5633-4bda-a6c7-a6e16f7cad64',
'identifier' => (int) 5,
'security_group_id' => null,
'sex_id' => null,
'username' => 'test',
'email' => 'test@test.com',
'prefix' => '',
'first_name' => 'test',
'middle_name' => '',
'last_name' => 'test',
'suffix' => '',
'credentials' => '',
'birthdate' => null,
'timezone' => 'America/New_York',
'theme' => '',
'ip' => '0.0.0.0',
'last_login' => null,
'created' => object(Cake\I18n\Time) {
'time' => '2015-09-16T16:17:57+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-12-16T22:22:49+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'user_occupations' => [
(int) 0 => object(Users\Model\Entity\UserOccupation) {
'id' => (int) 1,
'name' => 'Test',
'_joinData' => object(Cake\ORM\Entity) {
'user_occupation_id' => (int) 1,
'user_id' => '8b7197a4-5633-4bda-a6c7-a6e16f7cad64',
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'UsersUserOccupations'
},
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Users.UserOccupations'
}
],
'locations' => [
(int) 0 => object(Locations\Model\Entity\Location) {
'id' => (int) 7,
'ldap_name' => 'Test',
'name' => 'Test',
'address' => null,
'address_2' => null,
'city' => 'Test',
'state' => 'MD',
'zip' => null,
'phone' => null,
'fax' => null,
'active' => true,
'created' => object(Cake\I18n\Time) {
'time' => '2015-09-11T19:35:34+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-12-16T21:47:29+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'_joinData' => object(Users\Model\Entity\UsersLocation) {
'location_id' => (int) 7,
'id' => (int) 304,
'user_id' => '8b7197a4-5633-4bda-a6c7-a6e16f7cad64',
'static' => false,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Users.UsersLocations'
},
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Locations.Locations'
},
(int) 1 => object(Locations\Model\Entity\Location) {
'id' => (int) 33,
'ldap_name' => 'Test2',
'name' => 'Test2',
'address' => null,
'address_2' => null,
'city' => 'Test',
'state' => 'MD',
'zip' => null,
'phone' => null,
'fax' => null,
'active' => true,
'created' => object(Cake\I18n\Time) {
'time' => '2015-09-15T21:03:46+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-12-16T21:47:29+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'_joinData' => object(Users\Model\Entity\UsersLocation) {
'location_id' => (int) 33,
'id' => (int) 305,
'user_id' => '8b7197a4-5633-4bda-a6c7-a6e16f7cad64',
'static' => false,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Users.UsersLocations'
},
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Locations.Locations'
},
],
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [
(int) 0 => 'full_name',
(int) 1 => 'name_last_first'
],
'[errors]' => [],
'[repository]' => 'Users.Users'
}
This is what the debug output looks like after fixing with the request data:
object(Users\Model\Entity\User) {
'id' => '8b7197a4-5633-4bda-a6c7-a6e16f7cad64',
'identifier' => (int) 5,
'security_group_id' => null,
'sex_id' => null,
'username' => 'test',
'email' => 'test@test.com',
'prefix' => '',
'first_name' => 'test',
'middle_name' => '',
'last_name' => 'test',
'suffix' => '',
'credentials' => '',
'birthdate' => null,
'timezone' => 'America/New_York',
'theme' => '',
'ip' => '0.0.0.0',
'last_login' => null,
'created' => object(Cake\I18n\Time) {
'time' => '2015-09-16T16:17:57+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-12-16T22:22:49+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'user_occupations' => [
(int) 0 => object(Users\Model\Entity\UserOccupation) {
'id' => (int) 1,
'name' => 'Test ',
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Users.UserOccupations'
}
],
'locations' => [
(int) 0 => object(Locations\Model\Entity\Location) {
'id' => (int) 7,
'ldap_name' => 'Test',
'name' => 'Test',
'address' => null,
'address_2' => null,
'city' => 'Test',
'state' => 'MD',
'zip' => null,
'phone' => null,
'fax' => null,
'active' => true,
'created' => object(Cake\I18n\Time) {
'time' => '2015-09-11T19:35:34+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-12-16T21:47:29+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Locations.Locations'
},
(int) 1 => object(Locations\Model\Entity\Location) {
'id' => (int) 33,
'ldap_name' => 'Test2',
'name' => 'Test2',
'address' => null,
'address_2' => null,
'city' => 'Test',
'state' => 'MD',
'zip' => null,
'phone' => null,
'fax' => null,
'active' => true,
'created' => object(Cake\I18n\Time) {
'time' => '2015-09-15T21:03:46+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-12-16T21:47:29+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Locations.Locations'
}
],
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [
'locations' => true,
'user_occupations' => true
],
'[original]' => [
'locations' => [
(int) 0 => object(Locations\Model\Entity\Location) {
'id' => (int) 7,
'ldap_name' => 'Test',
'name' => 'Test',
'address' => null,
'address_2' => null,
'city' => 'Test',
'state' => 'MD',
'zip' => null,
'phone' => null,
'fax' => null,
'active' => true,
'created' => object(Cake\I18n\Time) {
'time' => '2015-09-11T19:35:34+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-12-16T21:47:29+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'_joinData' => object(Users\Model\Entity\UsersLocation) {
'location_id' => (int) 7,
'id' => (int) 304,
'user_id' => '8b7197a4-5633-4bda-a6c7-a6e16f7cad64',
'static' => false,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Users.UsersLocations'
},
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Locations.Locations'
},
(int) 1 => object(Locations\Model\Entity\Location) {
'id' => (int) 33,
'ldap_name' => 'Test2',
'name' => 'Test2',
'address' => null,
'address_2' => null,
'city' => 'Test',
'state' => 'MD',
'zip' => null,
'phone' => null,
'fax' => null,
'active' => true,
'created' => object(Cake\I18n\Time) {
'time' => '2015-09-15T21:03:46+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => object(Cake\I18n\Time) {
'time' => '2015-12-16T21:47:29+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'_joinData' => object(Users\Model\Entity\UsersLocation) {
'location_id' => (int) 33,
'id' => (int) 305,
'user_id' => '8b7197a4-5633-4bda-a6c7-a6e16f7cad64',
'static' => false,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Users.UsersLocations'
},
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[repository]' => 'Locations.Locations'
},
]
],
'[virtual]' => [
(int) 0 => 'full_name',
(int) 1 => 'name_last_first'
],
'[errors]' => [],
'[repository]' => 'Users.Users'
}