Reputation: 385
I have these three tables:
In the BookingsController, I have two functions:
When a user first submits a new Booking data entry, while a newEntity is created and saved for Bookings and Sessions, no newEntity is created and saved for Files. However, when a Booking/Session is being updated and confirmed, that is when a newEntity in Files is created the very first time. Since the Confirm function can be used many times, I use a conditional if statement to determine if an associated Files entry exists or not - if one exists, a newEntity for Files is created, patched and then saved. If not, it is just patched and saved.
In my Confirm function:
public function confirm($id = null)
{
$booking = $this->Bookings->get($id,[
'contain' => ['Sessions']
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$booking = $this->Bookings->patchEntity($booking, $this->request->data,[
'contain' => ['Sessions']
]);
$fileTable = TableRegistry::get('Files');
$findFiles = $fileTable->find()->where([
'session_id' => $session['id']
])->first();
if($findFiles == null){
$findFiles = $fileTable->newEntity();
$findFiles = $fileTable->patchEntity($findFiles, $data);
$findFiles->session_id = $booking['session']['id'];
if($fileTable->save($findFiles)){
} else {
}
} else {
$findFiles = $filesTable->patchEntity($findFiles, $data);
if($filesTable->save($findFiles)){
} else {
}
}
if ($this->Bookings->save($booking)) {
$this->Flash->success(__('The booking has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The booking could not be saved. Please, try again.'));
}
$this->set(compact('booking'));
$this->set('_serialize', ['booking']);
}
}
However, when trying to use the Confirm function, I get a integrity constraint violation regarding the booking_id foreign key in the Sessions table. I've pinpointed that by removing all the conditional saving code regarding the Files table, the function works fine, however that means neither a newEntity for Files is created when needed.
The easier method is I think just including Files in the New function, but because some bookings could be cancelled, there could potentially be a lot of empty Files data entries.
Update: Including Model and Confirm function's View and form input.
Below is the View of the Confirm function in BookingsController:
<?= $this->Form->create($booking) ?>
<fieldset>
<legend><?= __('Confirm Booking') ?></legend>
<?php
echo $this->Form->input('session.startdate', ['class'=>'form-control']);
echo $this->Form->input('session.enddate', ['class'=>'form-control']);
echo $this->Form->input('session.no_people', ['class'=>'form-control']);
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
And the Models for the individual tables.
Bookings:
public function initialize(array $config)
{
parent::initialize($config);
$this->table('bookings');
$this->displayField('id');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->hasOne('Sessions', [
'foreignKey' => 'booking_id'
]);
}
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create');
return $validator;
}
Sessions:
public function initialize(array $config)
{
parent::initialize($config);
$this->table('sessions');
$this->displayField('id');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Bookings', [
'foreignKey' => 'booking_id',
'joinType' => 'INNER'
]);
$this->hasOne('Templates', [
'foreignKey' => 'session_id'
]);
}
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create');
$validator
->date('startdate')
->requirePresence('startdate', 'create')
->notEmpty('startdate');
$validator
->date('enddate')
->requirePresence('enddate', 'create')
->notEmpty('enddate');
$validator
->integer('no_people')
->requirePresence('no_people', 'create')
->notEmpty('no_people');
return $validator;
}
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->existsIn(['booking_id'], 'Bookings'));
return $rules;
}
Files:
public function initialize(array $config)
{
parent::initialize($config);
$this->table('files');
$this->displayField('id');
$this->primaryKey('id');
$this->addBehavior('Timestamp');
$this->belongsTo('Sessions', [
'foreignKey' => 'session_id',
'joinType' => 'INNER'
]);
}
public function validationDefault(Validator $validator)
{
$validator
->integer('id')
->allowEmpty('id', 'create');
$validator
->allowEmpty('link');
$validator
->allowEmpty('name');
return $validator;
}
public function buildRules(RulesChecker $rules)
{
$rules->add($rules->existsIn(['session_id'], 'Sessions'));
return $rules;
}
Upvotes: 1
Views: 1808
Reputation: 385
The foreign key session_id
was a required attribute (this was why Files couldn't ever save). I've changed up the function to the following:
public function confirm($id = null)
{
$booking = $this->Bookings->get($id,[
'contain' => ['Sessions', 'Sessions.Files']
]);
if ($this->request->is(['patch', 'post', 'put'])) {
if($booking->session->file == null){ //checks for existing Files array
$template = $this->Bookings->Sessions->Files->newEntity(); //creates new Files entity if one doesn't exist for the associated session
$template->session_id = $booking->session->id; //fills in the foreign key with the currently active session primary key.
if($this->Bookings->Sessions->Templates->save($template)){ //saves the File entity
} else {
}
}
$booking = $this->Bookings->patchEntity($booking, $this->request->data,[
'contain' => ['Sessions', 'Sessions.Files']
]);
$fileTable = TableRegistry::get('Files');
$file = $fileTable->find('all',[
'contain' => ['Sessions'],
'conditions' => ['Sessions.booking_id' => $booking->id, 'Files.session_id' => $booking->session->id]
])->first();
if($file->session_id != $data['session']['id']){ //checks for any changes in session_id
$file->engineer_id = $data['session']['id']; //changes value to match if there isn't a match
$fileTable->save($template);
}
if ($this->Bookings->save($booking)) {
$this->Flash->success(__('The booking has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The booking could not be saved. Please, try again.'));
}
$this->set(compact('booking'));
$this->set('_serialize', ['booking']);
}
}
Upvotes: 1
Reputation: 859
Something like this should work. Cake will change the query to an UPDATE if an id exists else uses an INSERT.
public function confirm($id = null)
{
$booking = $this->Bookings->get($id, [
'contain' => ['Sessions' => ['Files']]
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$booking = $this->Bookings->patchEntity($booking, $this->request->data, [
'associated' => ['Sessions' => ['associated' => ['Files']]]
]);
if ($this->Bookings->save($booking)) {
$this->Flash->success(__('The booking has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('The booking could not be saved. Please, try again.'));
}
$this->set(compact('booking'));
$this->set('_serialize', ['booking']);
}
}
Upvotes: 0