Need help with my model

Hello guys,

I need help for my timesheets app model …

What I want to do is an app that allows you to save your times for every day.

I built this model :

screen_timesheets

Note : I added the hasMany relation from timesheets to timesheets_tasks model because I didn’t manage to access days table by another way

At the end I am not sure the belongsToMany from timesheets to tasks is really appropriate in this situation …

I have 2 questions :

  • Does this model sound good to you ?
  • How to save days ?

Because when I save this :

\src\Controller\TimesheetsController.php (line 115)
object(App\Model\Entity\Timesheet) {

	'id' => (int) 2,
	'user_id' => (int) 1,
	'week_nb' => (int) 16,
	'year' => (int) 2018,
	'validated' => false,
	'created' => object(Cake\I18n\FrozenTime) {

		'time' => '2018-04-02T09:25:29+00:00',
		'timezone' => 'UTC',
		'fixedNowTime' => false
	
	},
	'modified' => object(Cake\I18n\FrozenTime) {

		'time' => '2018-04-28T22:17:29+00:00',
		'timezone' => 'UTC',
		'fixedNowTime' => false
	
	},
	'tasks' => [
		(int) 0 => object(App\Model\Entity\Task) {

			'id' => (int) 1,
			'name' => 'Atelier 1 - Compta',
			'scope' => 'global',
			'user_id' => null,
			'project_id' => (int) 1,
			'created' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-01T15:19:44+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'modified' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-01T15:19:44+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'[new]' => false,
			'[accessible]' => [
				'*' => true
			],
			'[dirty]' => [],
			'[original]' => [],
			'[virtual]' => [],
			'[errors]' => [],
			'[invalid]' => [],
			'[repository]' => 'Tasks'
		
		},
		(int) 1 => object(App\Model\Entity\Task) {

			'id' => (int) 2,
			'name' => 'Atelier 2 - Achats',
			'scope' => 'global',
			'user_id' => null,
			'project_id' => (int) 1,
			'created' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-01T15:20:13+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'modified' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-01T15:20:13+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'[new]' => false,
			'[accessible]' => [
				'*' => true
			],
			'[dirty]' => [],
			'[original]' => [],
			'[virtual]' => [],
			'[errors]' => [],
			'[invalid]' => [],
			'[repository]' => 'Tasks'
		
		}
	],
	'timesheets_tasks' => [
		(int) 0 => object(App\Model\Entity\TimesheetsTask) {

			'id' => (int) 13,
			'timesheet_id' => (int) 2,
			'task_id' => (int) 1,
			'created' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-28T22:04:45+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'modified' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-28T22:04:45+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'days' => [
				(int) 0 => object(App\Model\Entity\Day) {

					'date' => object(DateTime) {
						date => '2018-04-16 22:17:40.643236'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 1 => object(App\Model\Entity\Day) {

					'date' => object(DateTime) {
						date => '2018-04-17 22:17:40.647586'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 2 => object(App\Model\Entity\Day) {

					'date' => object(DateTime) {
						date => '2018-04-18 22:17:40.647655'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 3 => object(App\Model\Entity\Day) {

					'date' => object(DateTime) {
						date => '2018-04-19 22:17:40.647705'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 4 => object(App\Model\Entity\Day) {

					'date' => object(DateTime) {
						date => '2018-04-20 22:17:40.647754'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 5 => object(App\Model\Entity\Day) {

					'date' => object(DateTime) {
						date => '2018-04-21 22:17:40.647796'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 6 => object(App\Model\Entity\Day) {

					'date' => object(DateTime) {
						date => '2018-04-22 22:17:40.647838'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				}
			],
			'[new]' => false,
			'[accessible]' => [
				'*' => true
			],
			'[dirty]' => [
				'days' => true
			],
			'[original]' => [
				'days' => []
			],
			'[virtual]' => [],
			'[errors]' => [],
			'[invalid]' => [],
			'[repository]' => 'TimesheetsTasks'
		
		}
	],
	'[new]' => false,
	'[accessible]' => [
		'*' => true
	],
	'[dirty]' => [
		'tasks' => true
	],
	'[original]' => [
		'tasks' => [
			(int) 0 => object(App\Model\Entity\Task) {

				'id' => (int) 1,
				'name' => 'Atelier 1 - Compta',
				'scope' => 'global',
				'user_id' => null,
				'project_id' => (int) 1,
				'created' => object(Cake\I18n\FrozenTime) {

					'time' => '2018-04-01T15:19:44+00:00',
					'timezone' => 'UTC',
					'fixedNowTime' => false
				
				},
				'modified' => object(Cake\I18n\FrozenTime) {

					'time' => '2018-04-01T15:19:44+00:00',
					'timezone' => 'UTC',
					'fixedNowTime' => false
				
				},
				'_joinData' => object(App\Model\Entity\TimesheetsTask) {

					'id' => (int) 13,
					'timesheet_id' => (int) 2,
					'task_id' => (int) 1,
					'created' => object(Cake\I18n\FrozenTime) {

						'time' => '2018-04-28T22:04:45+00:00',
						'timezone' => 'UTC',
						'fixedNowTime' => false
					
					},
					'modified' => object(Cake\I18n\FrozenTime) {

						'time' => '2018-04-28T22:04:45+00:00',
						'timezone' => 'UTC',
						'fixedNowTime' => false
					
					},
					'[new]' => false,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'TimesheetsTasks'
				
				},
				'[new]' => false,
				'[accessible]' => [
					'*' => true
				],
				'[dirty]' => [],
				'[original]' => [],
				'[virtual]' => [],
				'[errors]' => [],
				'[invalid]' => [],
				'[repository]' => 'Tasks'
			
			}
		]
	],
	'[virtual]' => [],
	'[errors]' => [],
	'[invalid]' => [],
	'[repository]' => 'Timesheets'

}

I doesn’t save days … The controller :

public function add()
{
    $timesheet = $this->Timesheets->newEntity();
    if ($this->request->is(['patch', 'post', 'put'])) {
        if(!is_null($this->request->getData('id'))) {
            $timesheet = $this->Timesheets->get($this->request->getData('id'), ['contain' => ['TimesheetsTasks' => ['Days'], 'Tasks']]);
        }

        // Here I "create" 7 days entities if a new timesheet_task has been added
        $this->initEmptyTasks($timesheet);

        $timesheet = $this->Timesheets->patchEntity($timesheet, $this->request->getData(), ['associated' => ['TimesheetsTasks' => ['associated' => ['Days']], 'Tasks']]);

        if ($result = $this->Timesheets->save($timesheet)) {
            $this->Flash->success(__('The timesheet has been saved.'));
            return $this->redirect($this->referer());
        }
        $this->Flash->error(__('The timesheet could not be saved. Please, try again.'));
        return $this->redirect($this->referer());
    }
    $users = $this->Timesheets->Users->find('list', ['limit' => 200]);
    $this->set(compact('timesheet', 'users'));
}

I don’t have any error, but days are not saved …

after save check sql panel in debugKit copy paste it into your workbench/database admin tool and see if executing it doesnt give you any sql error/warning. By looking at your schema i would say date is not good field name and can cause sql errors.

Hello,

Thanks for your answer.

Changed date to ts_date, same result …

on second glance all those ‘associated’ should be in ->save https://book.cakephp.org/3.0/en/orm/saving-data.html#saving-associations , by default cake allows 1st level of association thats why its working.

Already tried … Same result

if ($result = $this->Timesheets->save($timesheet, ['associated' => ['TimesheetsTasks' => ['Tasks', 'Days'], 'Tasks']])) {
    //debug($result);exit;
    $this->Flash->success(__('The timesheet has been saved.'));
    return $this->redirect($this->referer());
}

and what the result of dd($timesheet) after save is?

Do you mean the $result var?

object(App\Model\Entity\Timesheet) {

	'id' => (int) 2,
	'user_id' => (int) 1,
	'week_nb' => (int) 16,
	'year' => (int) 2018,
	'validated' => false,
	'created' => object(Cake\I18n\FrozenTime) {

		'time' => '2018-04-02T09:25:29+00:00',
		'timezone' => 'UTC',
		'fixedNowTime' => false
	
	},
	'modified' => object(Cake\I18n\Time) {

		'time' => '2018-04-29T20:03:17+00:00',
		'timezone' => 'UTC',
		'fixedNowTime' => false
	
	},
	'tasks' => [
		(int) 0 => object(App\Model\Entity\Task) {

			'id' => (int) 1,
			'name' => 'Atelier 1 - Compta',
			'scope' => 'global',
			'user_id' => null,
			'project_id' => (int) 1,
			'created' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-01T15:19:44+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'modified' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-01T15:19:44+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'[new]' => false,
			'[accessible]' => [
				'*' => true
			],
			'[dirty]' => [],
			'[original]' => [],
			'[virtual]' => [],
			'[errors]' => [],
			'[invalid]' => [],
			'[repository]' => 'Tasks'
		
		},
		(int) 1 => object(App\Model\Entity\Task) {

			'id' => (int) 2,
			'name' => 'Atelier 2 - Achats',
			'scope' => 'global',
			'user_id' => null,
			'project_id' => (int) 1,
			'created' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-01T15:20:13+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'modified' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-01T15:20:13+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'[new]' => false,
			'[accessible]' => [
				'*' => true
			],
			'[dirty]' => [],
			'[original]' => [],
			'[virtual]' => [],
			'[errors]' => [],
			'[invalid]' => [],
			'[repository]' => 'Tasks'
		
		},
		(int) 2 => object(App\Model\Entity\Task) {

			'id' => (int) 3,
			'name' => 'Test tache',
			'scope' => 'global',
			'user_id' => null,
			'project_id' => (int) 2,
			'created' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-02T13:58:22+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'modified' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-02T13:58:22+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'_joinData' => object(App\Model\Entity\TimesheetsTask) {

				'timesheet_id' => (int) 2,
				'task_id' => (int) 3,
				'created' => object(Cake\I18n\Time) {

					'time' => '2018-04-29T20:03:17+00:00',
					'timezone' => 'UTC',
					'fixedNowTime' => false
				
				},
				'modified' => object(Cake\I18n\Time) {

					'time' => '2018-04-29T20:03:17+00:00',
					'timezone' => 'UTC',
					'fixedNowTime' => false
				
				},
				'id' => (int) 21,
				'[new]' => false,
				'[accessible]' => [
					'*' => true
				],
				'[dirty]' => [],
				'[original]' => [],
				'[virtual]' => [],
				'[errors]' => [],
				'[invalid]' => [],
				'[repository]' => 'TimesheetsTasks'
			
			},
			'[new]' => false,
			'[accessible]' => [
				'*' => true
			],
			'[dirty]' => [],
			'[original]' => [],
			'[virtual]' => [],
			'[errors]' => [],
			'[invalid]' => [],
			'[repository]' => 'Tasks'
		
		}
	],
	'timesheets_tasks' => [
		(int) 0 => object(App\Model\Entity\TimesheetsTask) {

			'id' => (int) 20,
			'timesheet_id' => (int) 2,
			'task_id' => (int) 1,
			'created' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-29T19:55:36+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'modified' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-29T19:55:36+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'days' => [
				(int) 0 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 20,
					'ts_date' => object(DateTime) {
						date => '2018-04-16 20:03:17.405432'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 1 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 20,
					'ts_date' => object(DateTime) {
						date => '2018-04-17 20:03:17.410332'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 2 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 20,
					'ts_date' => object(DateTime) {
						date => '2018-04-18 20:03:17.410403'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 3 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 20,
					'ts_date' => object(DateTime) {
						date => '2018-04-19 20:03:17.410457'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 4 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 20,
					'ts_date' => object(DateTime) {
						date => '2018-04-20 20:03:17.410510'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 5 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 20,
					'ts_date' => object(DateTime) {
						date => '2018-04-21 20:03:17.410558'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 6 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 20,
					'ts_date' => object(DateTime) {
						date => '2018-04-22 20:03:17.410604'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				}
			],
			'task' => object(App\Model\Entity\Task) {

				'id' => (int) 1,
				'name' => 'Atelier 1 - Compta',
				'scope' => 'global',
				'user_id' => null,
				'project_id' => (int) 1,
				'created' => object(Cake\I18n\FrozenTime) {

					'time' => '2018-04-01T15:19:44+00:00',
					'timezone' => 'UTC',
					'fixedNowTime' => false
				
				},
				'modified' => object(Cake\I18n\FrozenTime) {

					'time' => '2018-04-01T15:19:44+00:00',
					'timezone' => 'UTC',
					'fixedNowTime' => false
				
				},
				'[new]' => false,
				'[accessible]' => [
					'*' => true
				],
				'[dirty]' => [],
				'[original]' => [],
				'[virtual]' => [],
				'[errors]' => [],
				'[invalid]' => [],
				'[repository]' => 'Tasks'
			
			},
			'[new]' => false,
			'[accessible]' => [
				'*' => true
			],
			'[dirty]' => [
				'days' => true
			],
			'[original]' => [
				'days' => []
			],
			'[virtual]' => [],
			'[errors]' => [],
			'[invalid]' => [],
			'[repository]' => 'TimesheetsTasks'
		
		},
		(int) 1 => object(App\Model\Entity\TimesheetsTask) {

			'id' => (int) 19,
			'timesheet_id' => (int) 2,
			'task_id' => (int) 2,
			'created' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-29T19:51:24+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'modified' => object(Cake\I18n\FrozenTime) {

				'time' => '2018-04-29T19:51:24+00:00',
				'timezone' => 'UTC',
				'fixedNowTime' => false
			
			},
			'days' => [
				(int) 0 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 19,
					'ts_date' => object(DateTime) {
						date => '2018-04-16 20:03:17.410660'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 1 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 19,
					'ts_date' => object(DateTime) {
						date => '2018-04-17 20:03:17.410707'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 2 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 19,
					'ts_date' => object(DateTime) {
						date => '2018-04-18 20:03:17.410752'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 3 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 19,
					'ts_date' => object(DateTime) {
						date => '2018-04-19 20:03:17.410797'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 4 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 19,
					'ts_date' => object(DateTime) {
						date => '2018-04-20 20:03:17.410849'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 5 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 19,
					'ts_date' => object(DateTime) {
						date => '2018-04-21 20:03:17.410896'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				},
				(int) 6 => object(App\Model\Entity\Day) {

					'timesheet_task_id' => (int) 19,
					'ts_date' => object(DateTime) {
						date => '2018-04-22 20:03:17.410941'
						timezone_type => (int) 3
						timezone => 'UTC'
					},
					'[new]' => true,
					'[accessible]' => [
						'*' => true
					],
					'[dirty]' => [
						'timesheet_task_id' => true,
						'ts_date' => true
					],
					'[original]' => [],
					'[virtual]' => [],
					'[errors]' => [],
					'[invalid]' => [],
					'[repository]' => 'Days'
				
				}
			],
			'task' => object(App\Model\Entity\Task) {

				'id' => (int) 2,
				'name' => 'Atelier 2 - Achats',
				'scope' => 'global',
				'user_id' => null,
				'project_id' => (int) 1,
				'created' => object(Cake\I18n\FrozenTime) {

					'time' => '2018-04-01T15:20:13+00:00',
					'timezone' => 'UTC',
					'fixedNowTime' => false
				
				},
				'modified' => object(Cake\I18n\FrozenTime) {

					'time' => '2018-04-01T15:20:13+00:00',
					'timezone' => 'UTC',
					'fixedNowTime' => false
				
				},
				'[new]' => false,
				'[accessible]' => [
					'*' => true
				],
				'[dirty]' => [],
				'[original]' => [],
				'[virtual]' => [],
				'[errors]' => [],
				'[invalid]' => [],
				'[repository]' => 'Tasks'
			
			},
			'[new]' => false,
			'[accessible]' => [
				'*' => true
			],
			'[dirty]' => [
				'days' => true
			],
			'[original]' => [
				'days' => []
			],
			'[virtual]' => [],
			'[errors]' => [],
			'[invalid]' => [],
			'[repository]' => 'TimesheetsTasks'
		
		}
	],
	'[new]' => false,
	'[accessible]' => [
		'*' => true
	],
	'[dirty]' => [],
	'[original]' => [],
	'[virtual]' => [],
	'[errors]' => [],
	'[invalid]' => [],
	'[repository]' => 'Timesheets'

}

hm i thought it was some error from buildRules or validation but i dont see any errors there, so all is left to check generated sql in debugKit as i said in the beginning.

How do you do this ?

EDIT : Ok sorry :

Query	Rows	Took (ms)
SELECT 
  Timesheets.id AS `Timesheets__id`, 
  Timesheets.user_id AS `Timesheets__user_id`, 
  Timesheets.week_nb AS `Timesheets__week_nb`, 
  Timesheets.year AS `Timesheets__year`, 
  Timesheets.validated AS `Timesheets__validated`, 
  Timesheets.created AS `Timesheets__created`, 
  Timesheets.modified AS `Timesheets__modified` 
FROM 
  timesheets Timesheets 
WHERE 
  Timesheets.id = 2 
LIMIT 
  1
1	1
SELECT 
  TimesheetsTasks.id AS `TimesheetsTasks__id`, 
  TimesheetsTasks.timesheet_id AS `TimesheetsTasks__timesheet_id`, 
  TimesheetsTasks.task_id AS `TimesheetsTasks__task_id`, 
  TimesheetsTasks.created AS `TimesheetsTasks__created`, 
  TimesheetsTasks.modified AS `TimesheetsTasks__modified`, 
  Tasks.id AS `Tasks__id`, 
  Tasks.name AS `Tasks__name`, 
  Tasks.scope AS `Tasks__scope`, 
  Tasks.user_id AS `Tasks__user_id`, 
  Tasks.project_id AS `Tasks__project_id`, 
  Tasks.created AS `Tasks__created`, 
  Tasks.modified AS `Tasks__modified` 
FROM 
  timesheets_tasks TimesheetsTasks 
  INNER JOIN tasks Tasks ON Tasks.id = (TimesheetsTasks.task_id) 
WHERE 
  TimesheetsTasks.timesheet_id in (2)
1	0
SELECT 
  Days.id AS `Days__id`, 
  Days.timesheet_task_id AS `Days__timesheet_task_id`, 
  Days.ts_date AS `Days__ts_date`, 
  Days.value AS `Days__value`, 
  Days.comment AS `Days__comment` 
FROM 
  days Days 
WHERE 
  Days.timesheet_task_id in (22)
0	0
SELECT 
  TimesheetsTasks.id AS `Tasks_CJoin__id`, 
  TimesheetsTasks.timesheet_id AS `Tasks_CJoin__timesheet_id`, 
  TimesheetsTasks.task_id AS `Tasks_CJoin__task_id`, 
  TimesheetsTasks.created AS `Tasks_CJoin__created`, 
  TimesheetsTasks.modified AS `Tasks_CJoin__modified`, 
  Tasks.id AS `Tasks__id`, 
  Tasks.name AS `Tasks__name`, 
  Tasks.scope AS `Tasks__scope`, 
  Tasks.user_id AS `Tasks__user_id`, 
  Tasks.project_id AS `Tasks__project_id`, 
  Tasks.created AS `Tasks__created`, 
  Tasks.modified AS `Tasks__modified` 
FROM 
  tasks Tasks 
  INNER JOIN timesheets_tasks TimesheetsTasks ON Tasks.id = (TimesheetsTasks.task_id) 
WHERE 
  TimesheetsTasks.timesheet_id in (2)
1	0
SELECT 
  Tasks.id AS `Tasks__id`, 
  Tasks.name AS `Tasks__name`, 
  Tasks.scope AS `Tasks__scope`, 
  Tasks.user_id AS `Tasks__user_id`, 
  Tasks.project_id AS `Tasks__project_id`, 
  Tasks.created AS `Tasks__created`, 
  Tasks.modified AS `Tasks__modified` 
FROM 
  tasks Tasks 
WHERE 
  Tasks.id in (1, 2)
2	0
BEGIN
0	0
UPDATE 
  timesheets 
SET 
  modified = '2018-04-29 20:46:15' 
WHERE 
  id = 2
1	0
(
  SELECT 
TimesheetsTasks.id AS `TimesheetsTasks__id`, 
TimesheetsTasks.timesheet_id AS `TimesheetsTasks__timesheet_id`, 
TimesheetsTasks.task_id AS `TimesheetsTasks__task_id`, 
TimesheetsTasks.created AS `TimesheetsTasks__created`, 
TimesheetsTasks.modified AS `TimesheetsTasks__modified` 
  FROM 
timesheets_tasks TimesheetsTasks 
  WHERE 
(
  timesheet_id = 2 
  AND task_id = 1
)
) 
UNION 
  (
SELECT 
  TimesheetsTasks.id AS `TimesheetsTasks__id`, 
  TimesheetsTasks.timesheet_id AS `TimesheetsTasks__timesheet_id`, 
  TimesheetsTasks.task_id AS `TimesheetsTasks__task_id`, 
  TimesheetsTasks.created AS `TimesheetsTasks__created`, 
  TimesheetsTasks.modified AS `TimesheetsTasks__modified` 
FROM 
  timesheets_tasks TimesheetsTasks 
WHERE 
  (
    timesheet_id = 2 
    AND task_id = 2
  )
  )
1	0
SELECT 
  TimesheetsTasks.id AS `TimesheetsTasks__id`, 
  TimesheetsTasks.timesheet_id AS `TimesheetsTasks__timesheet_id`, 
  TimesheetsTasks.task_id AS `TimesheetsTasks__task_id`, 
  TimesheetsTasks.created AS `TimesheetsTasks__created`, 
  TimesheetsTasks.modified AS `TimesheetsTasks__modified` 
FROM 
  timesheets_tasks TimesheetsTasks 
WHERE 
  TimesheetsTasks.timesheet_id = 2
1	0
SELECT 
  1 AS `existing` 
FROM 
  timesheets Timesheets 
WHERE 
  Timesheets.id = 2 
LIMIT 
  1
1	0
SELECT 
  1 AS `existing` 
FROM 
  tasks Tasks 
WHERE 
  Tasks.id = 2 
LIMIT 
  1
1	0
INSERT INTO timesheets_tasks (
  timesheet_id, task_id, created, modified
) 
VALUES 
  (
2, 2, '2018-04-29 20:46:15', '2018-04-29 20:46:15'
  )
1	0
COMMIT
0	0
SELECT 
  Users.id AS `Users__id`, 
  Users.email AS `Users__email`, 
  Users.password AS `Users__password`, 
  Users.first_name AS `Users__first_name`, 
  Users.last_name AS `Users__last_name`, 
  Users.role AS `Users__role`, 
  Users.company_id AS `Users__company_id`, 
  Users.created AS `Users__created`, 
  Users.modified AS `Users__modified` 
FROM 
  users Users 
LIMIT 
  200

No any insert nor update in the Days table :frowning:

your:

is not the same as

you need:

‘TimesheetsTasks’ => ['associated' => ['Days', 'Tasks']]

In fact I have this :

$timesheet = $this->Timesheets->patchEntity($timesheet, $this->request->getData(), ['associated' => ['TimesheetsTasks' => ['Tasks', 'Days'], 'Tasks']]);

Because I need Tasks in order to automatically fill the form, is that ok ?

Complete action:

public function add()
{
    $timesheet = $this->Timesheets->newEntity();
    if ($this->request->is(['patch', 'post', 'put'])) {
        if(!is_null($this->request->getData('id'))) {
            $timesheet = $this->Timesheets->get($this->request->getData('id'), ['contain' => ['TimesheetsTasks' => ['Tasks', 'Days'], 'Tasks']]);
        }

        // Init week days
        $this->initEmptyTasks($timesheet);

        $timesheet = $this->Timesheets->patchEntity($timesheet, $this->request->getData(), ['associated' => ['TimesheetsTasks' => ['Tasks', 'Days'], 'Tasks']]);

        if ($result = $this->Timesheets->save($timesheet, ['associated' => ['TimesheetsTasks' => ['Tasks', 'Days'], 'Tasks']])) {
            $this->Flash->success(__('The timesheet has been saved.'));
            return $this->redirect($this->referer());
        }
        $this->Flash->error(__('The timesheet could not be saved. Please, try again.'));
        return $this->redirect($this->referer());
    }
    $users = $this->Timesheets->Users->find('list', ['limit' => 200]);
    $this->set(compact('timesheet', 'users'));
}

iirc you need to use dot notation to associated table as in link i gave or associated in every level as i showed you, you dont use any of it and cake is just ignoring it.

I don’t this this is the root cause because I do 2nd association level save in other actions and it works

The only difference I see is that the first level table is not a pivot table …

For the dot syntax I changed to that :

public function add()
{
    $timesheet = $this->Timesheets->newEntity();
    if ($this->request->is(['patch', 'post', 'put'])) {
        if(!is_null($this->request->getData('id'))) {
            $timesheet = $this->Timesheets->get($this->request->getData('id'), ['contain' => ['TimesheetsTasks' => ['Tasks', 'Days'], 'Tasks']]);
        }

        // On initialise la semaine
        $this->initEmptyTasks($timesheet);

        $timesheet = $this->Timesheets->patchEntity($timesheet, $this->request->getData(), ['associated' => ['TimesheetsTasks', 'TimesheetsTasks.Days', 'Tasks']]);
        //debug($timesheet);exit;
        if ($result = $this->Timesheets->save($timesheet, ['associated' => ['TimesheetsTasks', 'TimesheetsTasks.Days', 'Tasks']])) {

            $this->Flash->success(__('The timesheet has been saved.'));
            //return $this->redirect($this->referer());
        }
        //debug($timesheet->getErrors());exit;
        $this->Flash->error(__('The timesheet could not be saved. Please, try again.'));
        //return $this->redirect($this->referer());
    }
    $users = $this->Timesheets->Users->find('list', ['limit' => 200]);
    $this->set(compact('timesheet', 'users'));
}

Still the same.

I tried several configurations (without ‘TimesheetsTasks’ at the beggining, with ‘TimesheetsTasks.days’ and ‘TimesheetsTasks.Tasks’, etc.) and same result :frowning:

Oh my god I found the root cause …

I was modifying the entity instead of the data I was patching the entity with …

But now I have one question :

Can you have a BTM pivot table to have hasMany relation with another Table ?

Because I can save _joinData for additionnal field (comment field here), but not for hasMany relation (days table)

Here’s my $data before I call the patchEntity method :

[
	'id' => '2',
	'week_nb' => '16',
	'year' => '2018',
	'tasks' => [
		(int) 0 => [
			'id' => (int) 1,
			'_joinData' => [
				'comment' => 'Hihi tache 1 new',
				'days' => [
					(int) 0 => [
						'timesheet_task_id' => (int) 35,
						'ts_date' => object(DateTime) {
							date => '2018-04-16 19:04:45.150726'
							timezone_type => (int) 3
							timezone => 'Europe/Paris'
						}
					]
				]
			]
		],
		(int) 1 => [
			'id' => (int) 2,
			'_joinData' => [
				'comment' => 'Hihi tache 2'
			]
		]
	]
] 

Here’s my data after I call the patchEntity method :

$timesheet = $this->Timesheets->patchEntity($timesheet, $data, ['associated' => ['Tasks._joinData.Days']]);

The _joinData part :

'_joinData' => object(App\Model\Entity\TimesheetsTask) {

	'id' => (int) 35,
	'timesheet_id' => (int) 2,
	'task_id' => (int) 1,
	'comment' => 'Hihi tache 1 new',
	'created' => object(Cake\I18n\FrozenTime) {

		'time' => '2018-05-01T18:39:17+02:00',
		'timezone' => 'Europe/Paris',
		'fixedNowTime' => false
	
	},
	'modified' => object(Cake\I18n\FrozenTime) {

		'time' => '2018-05-01T18:58:55+02:00',
		'timezone' => 'Europe/Paris',
		'fixedNowTime' => false
	
	},
	'days' => [
		(int) 0 => object(App\Model\Entity\Day) {

			'timesheet_task_id' => (int) 35,
			'ts_date' => object(DateTime) {
				date => '2018-04-16 19:02:01.023189'
				timezone_type => (int) 3
				timezone => 'Europe/Paris'
			},
			'[new]' => true,
			'[accessible]' => [
				'*' => true
			],
			'[dirty]' => [
				'timesheet_task_id' => true,
				'ts_date' => true
			],
			'[original]' => [],
			'[virtual]' => [],
			'[errors]' => [],
			'[invalid]' => [],
			'[repository]' => 'Days'
		
		}
	],
	'[new]' => false,
	'[accessible]' => [
		'*' => true
	],
	'[dirty]' => [
		'days' => true
	],
	'[original]' => [],
	'[virtual]' => [],
	'[errors]' => [],
	'[invalid]' => [],
	'[repository]' => 'TimesheetsTasks'

},

It seems to be working as cakePHPis converting my day record to a day entity, but same result now, it’s not saving.

when your structure becomes too complex just use $table->get($id, ['contain' => [ ... ] ]) to see how cake is building it and just try to replicate it in Form

from looking at what you gave it doesnt seem like its correct $data structure

It’s exactly what I’am doing, but I logged an issue on github and it appears (of what Iunderstand) that this kind of relation is not currently supported (planned for 3.7 maybe, crossing fingers).