Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CakePHP 3.1 patchEntity always marking belongsToMany associations as dirty when clean

So I noticed that If I patch an entity (edit method) and whether or not I make any data changes to the record if it has belongsToMany associations it marks them as dirty. I would expect that if I make no changes to the BTM multiple select in the view the data would not be dirty, only if the adding or removing options in the multiple select would it be marked as dirty after patching.

The data does save correctly, it is just dirty, but I need to act on know if it is dirty or clean as I have _join data in my map table. The map table is named users_locations and has id, user_id, location_id and static where static is a tinyint/bool.

What I am trying to do is flag static only for newly created map table entries.

What I notice is that patchEntity is stripping the _joinData as part of the marshaling process.

So looking at the debug output below you can see that the _joinData is stripped after patching for locations and user_occupations both.

This seems undesirable to me to not know if the associated data is clean or dirty. Maybe it was intended to work 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 initialize function for User:

$this->belongsToMany('Locations', [
    'through' => 'Users.UsersLocations',
    'foreignKey' => 'user_id',
    'targetForeignKey' => 'location_id',
    'className' => 'Locations.Locations'
]);

This is the request data debug output:

[
    'Referer' => [
        'url' => '/login'
    ],
    'security_group_id' => '',
    'username' => 'test',
    'email' => '[email protected]',
    '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 the user entity before patching 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' => '[email protected]',
    '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 the what the debug output look like after patching 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' => '[email protected]',
    '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'

}
like image 786
darensipes Avatar asked Nov 08 '22 23:11

darensipes


1 Answers

Please open an issue in https://github.com/cakephp/cakephp/issues.

Thanks!

like image 106
Megs Lalk Avatar answered Nov 14 '22 22:11

Megs Lalk