save all data in single statement without loop - cakephp

How to save all data in cakePHP. Suppose I have number of records regarding single model I wish to save all data at a time. My array is in format.
Array
(
[Attendance] => Array
(
[0] => Array
(
[date] => 2013-10-09
[user_id] => 10
[attendance] => 1
)
[1] => Array
(
[date] => 2013-10-09
[user_id] => 8
[attendance] => 0
)
)
)
Is this possible to save all data a single time. I tried to do it using saveMany but it was not successful.
Do I need to do it in loop
foreach ($result as $data) {
$this->Attendance->create();
$this->request->data['Attendance'] = $data;
$this->Attendance->save($this->request->data);
}

Try saveMany instead of save
$this->Attendance->saveMany($this->request->data);
data should be in this format :
Array
(
[1] => Array
(
[Attendance] => Array
(
[field] => value
[field] => value
)
)
[2] => Array
(
[Attendance] => Array
(
[field_1] => value
[field_2] => value
)
)
)

CakePHP will save each record for each id you have on the array. The only requirement is to use the array structure convention by them, then use:
// Check method request
if ($this->request->is('post')) {
// Check not empty data
if (!empty($this->data)) {
// Save the data
if ($this-> Attendance->save($this->request->data)) {
// Set a session flash message and redirect.
$this->Session->setFlash('Attendance saved.');
$this->redirect('/Attendances');
} else {
$this->Session->setFlash('Error saving the data.');
}
}
}

Related

How to access the specific elements in the array?

This is the assigning part of the smarty variable in controller file.
$objSmarty->assign( 'seleted_customer_subsidy_race_types', $this->getRequestData( array( 'customer_subsidy_race_types' ) ) );
We get this displayed:
Array
(
[1] => Array
(
[subsidy_race_type_id] => 1
)
[2] => Array
(
[subsidy_race_type_id] => 2
[subsidy_race_sub_type_id] => 2
)
)
How to access subsidy_race_type_id and subsidy_race_sub_type_id fields specifically?
Follow this
foreach($arr as $item) {
print_r($item['subsidy_race_type_id']);
print_r($item['subsidy_race_sub_type_id']);
}

cakephp find all primary column as key

When I fire this:
$this->model->find('all',array());
I get an array with the data of the model:
Array
(
[0] => Array
(
// some data
)
[1] => Array
(
// some data
)
[2] => Array
(
// some data
)
...
)
Now is it possible instead of 0,1,2 to get the id as key for each of the data?
For example:
Array
(
[365] => Array
(
[model] => Array
(
[id] => 365
// some data
)
)
[442] => Array
(
[model] => Array
(
[id] => 442
// some data
)
)
[1000] => Array
(
[model] => Array
(
[id] => 1000
// some data
)
)
...
)
I know that find('list') can do something like that but only for 2 fields max (one key and one value).
you can build it maybe this code can do it :
$final_array = array();
foreach($returned_array as $k => $v){
$final_array[$v['id']] = $v;
}
print_r($final_array);
It's still an after-find operation but take a look at Set::combine (http://book.cakephp.org/2.0/en/core-utility-libraries/set.html) as a more elegant solution. Something like:
$newArray = Set::combine($yourArray, '{n}.Model.id');
/* $newArray now looks like:
Array
(
[365] =>
[442] =>
[1000] =>
)
*/
(more or less just the the docs example) might work in your case.

CakePHP placing array items into diferrent cells CsvView plugin

I have started to export csv files with the help of CsvView plugin, but am stuck at one place.
So here is the controller code:
function export(){
$data = array(
array('37899810', '50001', '1', '7616'),
);
$_serialize = 'data';
$this->response->download('export.csv');
$this->viewClass = 'CsvView.Csv';
$this->set(compact('data', '_serialize'));
}
The problem is that the whole array is printed in a single cell, where I would like every item of an array to be placed in its own cell.
Any help is much appreciated.
this seems working for me :-
$result contains :-
Array
(
[0] => Array
(
[Eshop] => Array
(
[name] => test shop
)
[Productlps] => Array
(
[name] => product
)
[ProductViewLog] => Array
(
[credits_left] => 4999
[ip_address] => 10.0.0.1
[created] => 2013-12-02 06:25:07
)
)
)
$excludePaths = array(); // Exclude all id fields
$_extract = $this->CsvView->prepareExtractFromFindResults($results, $excludePaths);
$customHeaders = array('ProductViewLog.created' => 'Date Accessed','Eshop.name'=>'Shop Name','Productlps.name'=>'Product Name','ProductViewLog.credits_left'=>'Credit Balance','ProductViewLog.ip_address'=>"Accessed From");
$_header = $this->CsvView->prepareHeaderFromExtract($_extract, $customHeaders);
$_serialize = 'results';
$this->response->download('my_file.csv');
$this->viewClass = 'CsvView.Csv';
$this->set(compact('results', '_serialize', '_header', '_extract'));

CakePHP - $this->data disappears before Model::save

I have a page for editing records of the Venue model in my app. This page was working at some stage, but is now broken.
in the controller action, debugging $this->data gives the expected array of form values. However, in the Venue model, debugging $this->data in beforeSave gives only the values for fields from a related (HABTM) model, Category:
app/models/venue.php (line 89)
Array
(
[Category] => Array
(
[Category] => Array
(
[0] => 1
[1] => 2
[2] => 8
)
)
)
What could be happening to this data between the form being submitted to the controller action, and the call to beforeSave? Where should I be looking to debug this?
THanks
Edit - here's what's in $this->data in the controller (actual data changed to remove phone numbers, addresses etc).
app/controllers/venues_controller.php (line 63)
Array
(
[Venue] => Array
(
[id] => 19
[city_id] => 1
[user_id] => 130
[name] => Acme Zoo
[email] => events#acmezoo.org.uk
[description] =>
Some text...
[blurb] => Truncated description...
[contact_id] =>
[address_1] => Acme Zoo
[address_2] => Some Road
[postcode] => PP9 4DD
[telephone] => 010101010101
[website] =>
[latitude] => 55.21222
[longtitude] => -2.111111
[featured] => 0
[active] => 1
[flagged] => 0
[smg] => 0
[smg_custom_icon] => 1
[listings] => 1
[send_email] => 0
[file] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
)
[Category] => Array
(
[Category] => Array
(
[0] => 3
[1] => 6
[2] => 10
)
)
)
And here's my code to save the data...
if (!empty($this->data)) {
if ($this->Venue->save($this->data)) {
$this->Session->setFlash('The venue has been saved','success');
$countryId = $this->Venue->City->field('country_id',array('id'=>$this->data['Venue']['city_id']));
if (!empty($this->data['Venue']['send_email'])){
$this->_emailVenue($this->Venue->id,'venue_added',$countryId);
}
$this->redirect(array('action' => 'index','city'=>$this->data['Venue']['city_id']));
} else {
$this->Session->setFlash('The venue could not be saved. Please, try again.','failure');
}
}
I think i found a solution to this but I am really unsure if this should be considered a "good" solution.
I backup the request data before the save and then restore it if it fails.
$temp = $this->request->data;
if ($this->Post->save($this->request->data)) {
}else{
$this->request->data = $temp;
}
Maybe a stupid question, but do you pass the content of controller $data to the model when you call the save() method ?
$this->Venue->save($this->data)
Are you trying to save an entry to the categories table at the same time? If so, you can use $this->Venue->saveAll($this->data) instead of save(). If you just want to save the Venue data, just pass that in to save() instead of the entire $this->data like this: $this->Venue->save($this->data['Venue']);

Save multiple records for one model in CakePHP

I would like to save several records for one model. This would have been done pretty easily with saveAll() if it hadn't been for a problem:
I have a notification form, where I select multiple users from a <select> and two fields, for subject and content respectively. Now, when I output what $this->data contains, I have:
Array([Notification] => Array
(
[user_id] => Array
(
[0] => 4
[1] => 6
)
[subject] => subject
[content] => the-content-here
)
)
I've read on Cake 1.3 book, that in order to save multiple records for a model, you have to have the $this->data something like:
Array([Article] => Array(
[0] => Array
(
[title] => title 1
)
[1] => Array
(
[title] => title 2
)
)
)
So, how do I 'share' the subject and content to all selected users?
First off, this database design needs to be normalized.
It seems to me like a Notification can have many Users related to it. At the same time, a User can have many Notifications. Therefore,
Introduce a join table named users_notifications.
Implement the HABTM Relationship: Notification hasAndBelongsToMany User
In the view, you can simply use the following code to automagically bring up the multi-select form to grab user ids:
echo $this->Form->input('User');
The data that is sent to the controller will be of the form:
Array(
[Notification] => Array
(
[subject] => subject
[content] => contentcontentcontentcontentcontentcontent
),
[User] => Array
(
[User] => Array
(
[0] => 4
[1] => 6
)
)
)
Now, all you have to do is called the saveAll() function instead of save().
$this->Notification->saveAll($this->data);
And that's the Cake way to do it!
Those values have to be repeat like this
Array([Notification] => Array(
[0] => Array
(
[user_id] => 4
[subject] => subjects
[content] => content
)
[1] => Array
(
[user_id] => 6
[subject] => subject
[content] => contents
)
)
)
$this->Notification->saveAll($data['Notification']); // should work
If you don't pass any column value, this cake will just ignore it
You're going to have to massage your form's output to suit Model::saveAll. In your controller:
function action_name()
{
if ($this->data) {
if ($this->Notification->saveMany($this->data)) {
// success! :-)
} else {
// failure :-(
}
}
}
And in your model:
function saveMany($data)
{
$saveable = array('Notification'=>array());
foreach ($data['Notification']['user_id'] as $user_id) {
$saveable['Notification'][] = Set::merge($data['Notification'], array('user_id' => $user_id));
}
return $this->saveAll($saveable);
}
The benefit here is your controller still knows nothing about your model's schema, which it shouldn't.
In fact, you could probably redefine saveAll in your model, which hands off correctly formatted input arrays to parent::saveAll, but handles special cases itself.
There might be a more cakey way of doing this, but I've used this kind of technique: First, change the form so that you get an array like this:
Array(
[Notification] => Array
(
[subject] => subject
[content] => contentcontentcontentcontentcontentcontent
),
[selected_users] => Array
(
[id] => Array
(
[0] => 4
[1] => 6
)
)
)
(Just change the multiselect input's name to selected_users.id)
Then loop through the user ids and save each record individually:
foreach( $this->data[ 'selected_users' ][ 'id' ] as $userId ) {
$this->data[ 'Notification' ][ 'user_id' ] = $userId;
$this->Notification->create(); // initializes a new instance
$this->Notification->save( $this->data );
}

Resources