Can't patchEntity assocciated entity

I am using CakePHP 4.0.2

I have tables like below
IcsParents <–many to many–> Kids–> hasOne–>EduTypes

All associations works fines , since I can retrieve them all well.

However, when I edit IcsParents, I want to update EduTypes of Kids as well in 1 form.

The code look like this:

$icsParent = $this->IcsParents->get($id, [
        'contain' => ['CourseTypes', 'Kids.EduTypes'],
    ]);
if ($this->request->is(['patch', 'post', 'put'])) {
        $icsParent = $this->IcsParents->patchEntity($icsParent, $this->request->getData()
                , ['associated' => ['Kids']]);

The $icsParent never patch the change of Kids.edu_type_id , hence nothing is updated.
I can see that the dirty property is empty.
I search this forum and google but still can’t find solution.
Below is debug output of posted data , the first record has newly entered edu_type_id to 4 , what i changed in form.

    'IcsParent' => [
		'kids' => [
			(int) 0 => [
				'edu_type_id' => '4'
			],
			(int) 1 => [
				'edu_type_id' => '3'
			]
		]
	],

This is patched IcsParent

object(App\Model\Entity\IcsParent) {

    	'id' => (int) 1,
    	'first_name' => 'f1-parent2',
    	'last_name' => 'tpln',
    	'mobile' => '0916825483',
    	'email' => 'general2000vn@yahoo.com',
    	'dob' => null,
    	'user_id' => null,
    	'is_mother' => false,
    	'address' => '',
    	'district_id' => null,
    	'ward_id' => null,
    	'register_status_id' => (int) 1,
    	'consult_status_id' => (int) 2,
    	'is_deleted' => false,
    	'is_active' => true,
    	'is_dupplicated' => true,
    	'picture' => 'parents/1.jpg',
    	'created' => object(Cake\I18n\FrozenTime) {
    	},
    	'modified' => object(Cake\I18n\FrozenTime) {
    	},
    	'kids' => [
    		(int) 0 => object(App\Model\Entity\Kid) {

    			'id' => (int) 1,
    			'first_name' => 'Fkid1',
    			'last_name' => 'Lkid1',
    			'dob' => object(Cake\I18n\FrozenDate) {},
    			'edu_type_id' => (int) 2,
    			'is_deleted' => (int) 0,
    			'created' => object(Cake\I18n\FrozenTime) {},
    			'modified' => object(Cake\I18n\FrozenTime) {},
    			'_joinData' => object(Cake\ORM\Entity) {

    				'id' => (int) 1,
    				'kid_id' => (int) 1,
    				'ics_parent_id' => (int) 1,
    				'[new]' => false,
    				'[accessible]' => [
    					'*' => true
    				],
    				'[dirty]' => [],
    				'[original]' => [],
    				'[virtual]' => [],
    				'[hasErrors]' => false,
    				'[errors]' => [],
    				'[invalid]' => [],
    				'[repository]' => 'KidsIcsParents'
    			
    			},
    			'edu_type' => object(App\Model\Entity\EduType) {

    				'id' => (int) 2,
    				'name' => 'Private School',
    				'[new]' => false,
    				'[accessible]' => [
    					'name' => true,
    					'kids' => true
    				],
    				'[dirty]' => [],
    				'[original]' => [],
    				'[virtual]' => [],
    				'[hasErrors]' => false,
    				'[errors]' => [],
    				'[invalid]' => [],
    				'[repository]' => 'EduTypes'
    			
    			},
    			'[new]' => false,
    			'[accessible]' => [
    				'first_name' => true,
    				'last_name' => true,
    				'dob' => true,
    				'is_deleted' => true,
    				'created' => true,
    				'modified' => true,
    				'pupils' => true,
    				'ics_parents' => true
    			],
    			'[dirty]' => [],
    			'[original]' => [],
    			'[virtual]' => [],
    			'[hasErrors]' => false,
    			'[errors]' => [],
    			'[invalid]' => [],
    			'[repository]' => 'Kids'
    		
    		},
    		(int) 1 => object(App\Model\Entity\Kid) {

    			'id' => (int) 2,
    			'first_name' => 'fkid2',
    			'last_name' => 'lkid2',
    			'dob' => object(Cake\I18n\FrozenDate) {},
    			'edu_type_id' => (int) 3,
    			'is_deleted' => (int) 0,
    			'created' => object(Cake\I18n\FrozenTime) {},
    			'modified' => object(Cake\I18n\FrozenTime) {},
    			'_joinData' => object(Cake\ORM\Entity) {

    				'id' => (int) 2,
    				'kid_id' => (int) 2,
    				'ics_parent_id' => (int) 1,
    				'[new]' => false,
    				'[accessible]' => [
    					'*' => true
    				],
    				'[dirty]' => [],
    				'[original]' => [],
    				'[virtual]' => [],
    				'[hasErrors]' => false,
    				'[errors]' => [],
    				'[invalid]' => [],
    				'[repository]' => 'KidsIcsParents'
    			
    			},
    			'edu_type' => object(App\Model\Entity\EduType) {

    				'id' => (int) 3,
    				'name' => 'International School',
    				'[new]' => false,
    				'[accessible]' => [
    					'name' => true,
    					'kids' => true
    				],
    				'[dirty]' => [],
    				'[original]' => [],
    				'[virtual]' => [],
    				'[hasErrors]' => false,
    				'[errors]' => [],
    				'[invalid]' => [],
    				'[repository]' => 'EduTypes'
    			
    			},
    			'[new]' => false,
    			'[accessible]' => [
    				'first_name' => true,
    				'last_name' => true,
    				'dob' => true,
    				'is_deleted' => true,
    				'created' => true,
    				'modified' => true,
    				'pupils' => true,
    				'ics_parents' => true
    			],
    			'[dirty]' => [],
    			'[original]' => [],
    			'[virtual]' => [],
    			'[hasErrors]' => false,
    			'[errors]' => [],
    			'[invalid]' => [],
    			'[repository]' => 'Kids'
    		
    		}
    	],
    	'course_types' => [],
    	'[new]' => false,
    	'[accessible]' => [
    		'first_name' => true,
    		'last_name' => true,
    		'mobile' => true,
    		'email' => true,
    		'yob' => true,
    		'user_id' => true,
    		'is_mother' => true,
    		'address' => true,
    		'district_id' => true,
    		'ward_id' => true,
    		'register_status_id' => true,
    		'consult_status_id' => true,
    		'is_deleted' => true,
    		'is_active' => true,
    		'picture' => true,
    		'created' => true,
    		'modified' => true,
    		'user' => true,
    		'district' => true,
    		'ward' => true,
    		'register_status' => true,
    		'consult_status' => true,
    		'course_types' => true
    	],
    	'[dirty]' => [],
    	'[original]' => [],
    	'[virtual]' => [],
    	'[hasErrors]' => false,
    	'[errors]' => [],
    	'[invalid]' => [],
    	'[repository]' => 'IcsParents'

    }

Can someone please kindly help? <— problem solved

SOLUTION: dreamingmind has pointed out for me that I need to add Kids into Accessible list in IcsParent entity

Is the ‘kids’ property set to be $_accessible in the IcsParent entity?

Do the entities report any errors after the patch?

1 Like

The solution I use are what I call tabbed panels. I use Semantic UI, see example link below.
Basic Tabs
So what I do on the admin view page is display the main entity record details (IcsParent) in the first tab, and record lists of associated models in subsequent individual tabs (CourseType, Kids), depending on how many models you have linked together, with an edit button opposite each record
On the admin add or edit page, similar but with a form instead of record details.
On the admin add page you can enter new records and have a save and stay on page button to add and save kids for example.
Implementing it in this way I can have all the details I need on one page. With long record lists on associated tabs don’t forget to include pagination.
Hope this makes sense!!

Thank you very much, this is really solution.
I have not add kids into accessible list in IcsParentEntity.

Love u

thank you for your idea, it is good design, I will learn from this. But it is not really my problem is.

I did not add Kids into Accessible list in IcsParens entity.

Hi [Progredi]

Could you please give me sample code of saving others Models (CourseTypes, Kids…) in the main Model (IcsParents) ?

I am at the stage of saving posted data, and I read somewhere that saving (or manipulating) data should happen in Model. The problem is I only know how to do that from Controller of main Model, loadModel of others and manipulate data. I dont really know how to do that in Model

Thank you very much.

I don’t know what you read, but calls to save should be happening in your controller.

I have a Register page that allow parents to register their child to courses.

The page contents:

  • Logging in data: new user data (Users table)
  • Parents data: The 2 parents (Parents table)
  • Pupil data: The registering child (Pupils table), only some data of the kid in here, other data in Kids table
  • Siblings data: other kids of the same parents (Kids table), the pupil also in this list.
  • Course ID : the course that Pupil enroll to (Courses table)
  • Education histories: of the pupil (EduHistories table)

Please advice me the better approach for this.

  • Should I patch and save them all in UsersController->register() action?
  • If splitting into many actions for each controller, how can I make them work together as 1 registering page for user GUI ?

Thank you very much for your advice.

Well,

I figure out that I can patchEntities with associations, then save them at once.

But there are some mutual relationship, what should I do? the association does not work till the end.

Yes, saving multiple all at once via associations is a great thing! Very nice how it fills in all the IDs in related records as it saves them.

What, specifically, are the mutual relationships that you’re struggling with?

Thank you for your reply.

My application has:

  • Users hasMany Pupils
  • Pupils hasOne Kids
  • Users hasMany Parents
  • Parents belongToMany Kids (1 kid has 2 parents, 1 parents may have more than 1 kid)

In my registration form, most of the data of those 4 tables submitted, at once.
And the 1st Kids entered will the be one which is being enrolled to the course, hence created user for him/her. Other kids are just sibling, added for extra information only.

Which model should I make the 1st level of model, and other are associations?

They kind of associated in a loop (what i meant mutual association, correct me if I am wrong).

Thank you very much for your help.