Saving multiple records for multiple models cakephp - cakephp

Hey guys, I'm super stuck after a long night.
I'm creating an app where you can create food menus dynamically, and have relationships set up as such: Menu hasMany Widget, Widget hasMany WidgetItem (and of course, WidgetItem belongsTo Widget, Widget belongsTo Menu).
The menu is created first, then the user is redirected to addSectionsToMenu, where I have set up multiple Widgets (title input), respectively with multiple items (menu items).
My widgets save and attach to the menu fine, but my WidgetItems don't save. My models are set up fine I am sure, and I spent 2 hours sorting out my $data structure. I just think I need to figure something out here.
Please help!
Thanks,
~Harley
function addSectionsToMenu($menu_id = null){
$this->layout = 'admin';
$this->set('menu_id', $menu_id);
$this->set('menu', $this->Widget->Menu->findById($menu_id));
if (!$menu_id && empty($this->data)) { $this->Session->setFlash(__('Pick a menu to add to please :)', true)); }
$saveSuccess = false;
if(!empty($this->data['Widget'])) {
$widget_count = 0;
foreach($this->data['Widget'] as $widgetKey => $widget) :
if($this->Widget->saveAll($widget)) : $saveSuccess = true; endif;
$widget_count++;
endforeach;
if ($saveSuccess) {
$this->Session->setFlash(__($widget_count.' sections have been added to the Menu', true));
$this->redirect(array('controller' => 'menus', 'action' => 'index'));
} else {
$this->Session->setFlash(__('The Menu and Sections could not be saved. Please, try again.', true));
}
}
}

I've had problems saving multiple models at once and I solved it by adjusting the validation option.
$this->Invoice->saveAll($this->data, array('validate' => true))
The explanation of the options array doesn't make complete sense to me, but the default was causing my insert to fail because the related records were not getting their foreign key from the insert of the parent record. Changing the option to "first" (the default) to "true" solved the problem and the rows are showing up in the database correctly.

Related

Add a user in Cakephp

There is a problem when I write an add() function for UsersController.
public function add() {
if ($this->request->is('post')) {
$this->request->data['User']['book_id'] = $this->Book('id');
if ($this->User->saveAssociated($this->request->data)){
$this->request->data['User']['book_id'] = "ff";
$this->Session->setFlash(__('Save User'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('User Error.'));
}
}
If I add a User I want to save the book ID in my User book_id.
Anyone know how to deal with this problem? Thanks!
When you're adding a new user, does he get to select a book from a drop down(in the form)? If so, $this->request->data['User']['book_id'] will already contain the Book id.
There's no need to explicitly write $this->request->data['User']['book_id'] = $this->Book('id'); like you have done.
The way I see it, the add.ctp view file should contain a select box containing a list of all books which the user can select. On selecting one of those and submitting the form, $this->request->data['User']['book_id'] will automatically store the book_id, without having to write anything in the controller.
Please specify the add.ctp form fields so that I can assist you better.
Thanks!

How do I make it so when a user deletes something it still exists, but is just hidden from everyone?

Currently when a user deletes an item, it gets properly deleted, but due to the structure of my database and wanting to preserve data I would rather simply hide it from everyone except the admin but have it appear deleted to the user.
Here is an example of how I am currently deleting items from the View:
<?php echo $this->Form->postLink(__('Delete'), array('action' => 'delete', $serial['Serial']['id']), null, __('Are you sure you want to delete # %s?', $serial['Serial']['id'])); ?>
And here is the delete function that is called in the Controller:
public function delete($id = null) {
$this->Serial->id = $id;
if (!$this->Serial->exists()) {
throw new NotFoundException(__('Invalid serial'));
}
$this->request->onlyAllow('post', 'delete');
if ($this->Serial->delete()) {
$this->Session->setFlash(__('The serial has been deleted.'));
} else {
$this->Session->setFlash(__('The serial could not be deleted. Please, try again.'));
}
return $this->redirect(array('action' => 'index'));
}
}
How do I make it so when a user deletes something it still exists, but is just hidden from everyone?
By not deleting, but just flagging it as deleted (using an extra deleted column or similar) and excluding such flagged records from your find operations (using for example the Model::beforeFind() callback to inject a condition like deleted = 0).
Just search for "soft delete", and you'll find ready made behaviors such as
CakeDC Utils - SoftDelete
dereuromark CakePHP Tools - SoftDelete
Use database flag like deleted as enum which can be 1 Or 0 , So If you click on delete , it updates as 1 , Like soft delete.
So in model , use condition to fetch only recs with deleted status as 0 .
Or in controller use find query with condition to fetch only recs with deleted status as 0 .

hard-code Form input field in cakephp so user can't edit it?

I have following form field in a registration form in cakephp. I want to make it 'hard-coded', so user can't edit it
echo $form->input('name', array('label' => __('Name *', true)));
Then don't add it to the form.
Those fields should be added in the controller (or even beforeValidate/beforeSave model layer) then right before saving:
if ($this->request->is('post')) {
$this->User->create();
// add the content before passing it on to the model
$this->request->data['User']['status'] = 1;
if ($this->User->save($this->request->data)) {
...
}
}
See "default values - hidden" here.
You can set the readonly property:
echo $form->input('name', array('label' => __('Name *', true), 'readonly' => true));
However, this only affects the UI, and so you still have to apply mark's answer to ensure the value doesn't get changed by the user.
Two options:
hard code the value before the save
use white list
If you want the field to be a read-only, from the moment it is set. use white list. this way - it doesn't matter if the user will submit the field or not. cake won't save it.
$white_list = array('title', 'category');
$this->Model->save($data,$validate,$white_list);
The other solution is as mark coded it:
$this->request->data['User']['status'] = 1;
if ($this->User->save($this->request->data)) {
...
}
Any solution should mix a UI indication that the field will not be changed. tho a good UX will not allow it in the first-place.

Weird problems while getting ID just after saving data

I have different models which are an extension of another one.
classes (SubModel1, SubModel2, ..,6) extends -> HighModel extends -> Appmodel
Everytime I save data in each submodel I call a function in my HighModel to save the id of the just saved SubModel. It works perfectly with five SubModels, but in one the id is always: ($shouldBeThisId - 1)in both add and edit functions.... o_O
Here's my add function:
public function add() {
if ($this->request->is('post')) {
$this->M18Tab->create();
if ($this->M18Tab->save($this->request->data)) {
$data = $this->M18Tab->findById($this->M18Tab->id); //<---problem's here
if($this->M18Tab->M18Model->saveVersion($data)){
$this->Session->setFlash(__('The m18 tab has been saved'));
$this->redirect(array('action' => 'view', $this->M18Tab->id));
} else {
$this->Session->setFlash(__('Error with versioning system'));
}
} else {
$this->Session->setFlash(__('The m18 tab could not be saved. Please, try again.'));
}
}
//view variables
}
ok. so after saving I recall the "just saved data" and pass it to $this->SubModel->HighModel->saveVersion($data). and the weird thing is that if I try to force the id to find:
$data = $this->M18Tab->findById(33);
it'll still find the id preceding the just inserted one :0.
what could this be caused by? the code is the same for all 6 models and in only one I have this issue..
This is more of a comment/suggestion than an answer, but anyway...
If you're adding a new record, after calling save, you can get it's ID via:
$this->MyModel->getInsertId();
See that method in the cookbook. I know the id should also be available at $this->MyModel->id, but since it's not working in this case, you might want to try:
$data = $this->M18Tab->findById($this->M18Tab->getInsertId());

Saving related model data (3 levels)

Really struggling with saving model info a few levels down.
Firstly, I have a expenseClaim – that hasMany expenses (expenses belongTo expenseClaim).
Expenses HABTM ExpenseCode. (these are things like train fare, petrol costs etc).
So, I have a Add a new Expense page – (ExpenseClaimsController /add).
This kinda looks a bit like a spreadsheet and it allows you to enter multiple rows (each row being a expense). On each row theres a drop down to select the expenseCode. The issue is that the expenseCode is not getting written to the join table (expenses_expense_codes).
If I add a single expense, through the unused and soon to be removed expenseController /add it works fine, so the issue is saving assoisiated models, models. Cant figure out how to do this as expenseCode is not directly related to the expenseClaim model and therefore not saving when I do ExpenseClaimsController /add.
Hope that makes sense….
Heres my ExpenseClaimsController code:
public function add() {
if ($this->request->is('post')) {
//debug($this->request->data);
// Test
$this->loadModel('ExpenseCode');
// Create the claim and the expenses
$this->ExpenseClaim->create();
$this->ExpenseClaim->Expense->create();
// Set the user ID
$this->request->data['ExpenseClaim']['user_id'] = $this->Auth->user('id');
// Set the claim status based on which submit btn was pressed
if ($this->request->data['submit'] == 'Submit') {
$this->request->data['ExpenseClaim']['claim_status_id'] = '2';
} else {
$this->request->data['ExpenseClaim']['claim_status_id'] = '1';
}
// Set the claim status
$now = date('Y-m-d H:i:s');
$this->request->data['ExpenseClaim']['date_submitted'] = $now;
// Save both expenses and the expense claim
if ($this->ExpenseClaim->saveAll($this->request->data)) {
$this->Session->setFlash('The expense claim has been saved', 'flash_success');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('The expense claim could not be saved. Please, try again.', 'flash_failure');
}
}
$users = $this->ExpenseClaim->User->find('list');
$claimStatuses = $this->ExpenseClaim->ClaimStatus->find('list');
$expenseCodes = $this->ExpenseClaim->Expense->ExpenseCode->find('list');
$mileageRate = $this->Auth->user('mileage_rate');
$this->set(compact('users', 'claimStatuses', 'expenseCodes', 'mileageRate'));
// Set errors for top of page
$this->set('errors', $this->ExpenseClaim->validationErrors);
}
Can anyone point me in the right direction? Thanks in advance.
Managed to track down the issue, I had to rename the field in ExpenseClaim add to
$this->Form->input('Expense.0.ExpenseCode.ExpenseCode');
This then solved the issue.
Hopefully this will help someone.

Resources