Cakephp's beforeSave not retaining new data when using saveAll? - php

I have a relatively simple entries model with just five fields:
id
type (what datatype this entry is)
amount (how many of whatever type it is)
unit (the unit of the type)
date (the datettime when this entry was entered)
user_id (the id of the user who enters
So, nothing fancy. Now a single form can have multiple entries (both already existing ones and new ones just created), the form is extended via ajax calls.
When I submit the form $this->data looks like this:
Array
(
[Entry] => Array
(
[date] => 2011-01-07
[0] => Array
(
[id] => 1
[type] => Eat
[amount] => 1 Steak, one baked potatoe
[unit] => lunch
[time] => Array
(
[hour] => 13
[min] => 31
)
)
[1] => Array
(
[type] => weight
[amount] => 78.5
[unit] => KG
[time] => Array
(
[hour] => 22
[min] => 22
)
)
)
)
The first entry in $this->data['Entry']['date'] is the date that shall be used by ALL the entries. And since also the user_id is missing I created a "beforeSave" function in the entry-model. It looks like this:
function beforeSave() {
App::import('Component','Session');
$this->Session = new SessionComponent();
if (isset($this->data) && isset($this->data['Entry'])) {
$date = $this->data['Entry']['date'];
unset($this->data['Entry']['date']);
foreach ($this->data['Entry'] as $n => $entry) {
if (is_array($entry)) {
$this->data['Entry'][$n]['date'] = $date . ' ' . $entry['time']['hour'] . ':' . $entry['time']['min'] . ':00';
$this->data['Entry'][$n]['user_id'] = $this->Session->read('Auth.User.id');
}
}
debug($this->data);
}
return true;
}
I remove the date, add it together with the time entry of the user, thus creating a mysql datetime entry and add the user_id of the logged in user. Straightforward, really. The resulting array (as output by that last debug()) looks like the following:
Array
(
[Entry] => Array
(
[0] => Array
(
[id] => 1
[type] => Eat
[amount] => 1 Steak, 1 baked potatoe
[unit] => lunch
[time] => Array
(
[hour] => 09
[min] => 31
)
[date] => 2011-01-07 09:31:00
[user_id] => 2
)
[1] => Array
(
[type] => Weight
[amount] => 78.5
[unit] => KG
[time] => Array
(
[hour] => 22
[min] => 22
)
[date] => 2011-01-07 22:22:00
[user_id] => 2
)
)
)
So it look exactly like I want it to look and it should be easily saved. But when I use $this->Entry->saveAll($this->data['Entry']) to save all the entries, not only does it not work, but when I debug $this->data directly after the saveAll, it looks exactly like before the saveAll function - the date is back in the array, the entries do not have a date or user_id entry.
I can see that beforeSave is called, I can see that it changes $this->data, but somewhere between the end of beforeSave and the usage of "saveAll" all my changes get lost and $this->data is reverted to it's original state. Therefore no saving takes place.

I had similar problem trying to implement some sanitization with hasMany through. As it turns out the problem lies in how saveAll() works. The $this->data in controller isn't the same as $this->data in Model::beforeSave() callback and the two are not synchronized. When You call Model::saveAll() passing $this->data from the controller You explicitly give the model "the old version" of data array. And when You look into saveAll definition in cake/libs/model/model.php it just does:
if (empty($data)) {
$data = $this->data
}
and nothing more to sync up the modified $data array in model and passed by parameter $data form the controller. The solution is to not pass the data to saveAll() but instead set the data on model first using Model::set() and then call Model::saveAll() (without the $data parameter).

When we call SaveAll, doesn't pass updated/submitted data to model's beforeSave. To come out from this issue,
create tmp_data array in model
i.e.
var $tmp_data = array();
before saveall call, set this variable,
i.e.
$this->model->tmp_data = $this->data;
$this->model->saveAll();
Then, amend code for model->beforeSaveBefore
Instead of $this->data use $this->tmp_data

You're not getting tripped up on validation are you?
Try
$this->Entry->saveAll($data,array('validate'=>false));
If it works then the problem lies in validation
However don't forget that you need to use create() before saving for single models if no primary key is specified. Maybe the mixing of new and existing data in the saveAll() is the issue.

as far as I know saveAll() updateAll() and deleteAll() dont trigger any callbacks by default
you need to enable them manually (last parameter of the method)

Related

Extract data from php array

I have the following array in my Moodle plugin:
Array (
[0] => stdClass Object (
[id] => 32
[sessionid] => 5
[sessiontimezone] => CET
[timestart] => 1464071400
[timefinish] => 1464102000 )
[1] => stdClass Object (
[id] => 33
[sessionid] => 5
[sessiontimezone] => CET
[timestart] => 1465281000
[timefinish] => 1465311600 )
)
How to get the data. Right now, when I make:
$pluginsessiondates = $DB->get_record('plugin_sessions', array('id'=>$sessionid));
I get only data from the frist array [0]
How to get the data from every array key and then the single values? Thanks in advance.
The Moodle DB functions are for getting data out of the database, rather than from an array somewhere inside your plugin.
If you have an array somewhere, then you can get fields from it by writing:
echo $myarray[0]->id;
echo $myarray[1]->id;
etc.
If you are not trying to get data out of an existing array and want, instead, to get it out of the database, then $DB->get_record() will, as its name implies, get you only a single record, whereas $DB->get_records() will get you all the matching records:
$sessions = $DB->get_records('plugin_sessions', array('sessionid' => $sessionid));
foreach ($sessions as $session) {
echo $session->id;
}

How to add an element to array in CodeIgniter controller

In my CodeIgniter controller called Leads
I am having a code which retrieve data from model (database):
$data['leads'] = $this->model_leads->get_leads_by_person($person_id);
Now I can get some fileds like:
Array ( [0] => Array ( [lead_id] => 79 [lead_date] => 2014-07-15 12:34:41 [lead_priv] => 0 [1] => Array ( [lead_id] => 395 [lead_date] => 2014-07-15 12:34:41 [[lead_priv] => 0))
Now I want to add to every lead in $data['leads'] additional value, in my example lead_chance.
So let's say that I have a variable $lead_chance='100';
How to add this as an element to an array $data['leads']?
foreach($data['leads'] as $id => $lead) {
$data['leads'][$id]['lead_chance'] = '100';
}
Something like this?
foreach ($data['leads'] as $x) {
$x['lead_chance']=$lead_chance;
}
This would give you one lead_chance per item. If you want only one lead_chance for the whole array, it is much easier:
$data['leads']['lead_chance']=$lead_chance;

Calling another function in PHP with Array as Parameter passing only first element (JSON RPC)

this might be quite a dummy question. I've been searching the web and trying around alot but i just can't find a solution.
I am sending out Core Data Objects as Dictionarys within an Array to my PHP JSON RPC web service. I will not dig further into this at this point, because i know that my JSON RPC is well formed.
On PHP side i do have one RPC Server which will take the JSON data and pass it to the respective function.
$request = json_decode(file_get_contents('php://input'),true);
Using print_r i get the following result
print_r($request['params']);
(Sorry, i don't know how to include 'Array (' and the closing ')' in the box)
Array
(
[0] => Array
(
[dayId] => 7
[dayName] => Sonntag
)
[1] => Array
(
[dayId] => 6
[dayName] => Samstag
)
[2] => Array
(
[dayId] => 4
[dayName] => Donnerstag
)
[3] => Array
(
[dayId] => 2
[dayName] => Dienstag
)
[4] => Array
(
[dayId] => 1
[dayName] => Montag
)
)
As mentioned before, this array is now passed to the respective function using
$result = #call_user_func_array(array($object,$request['method']),$request['params']))
This will call method updateDaysFromClient in my implementation class.
At this point, i would like to repeat, that my JSON RPC is well formed (method, id, params).
public function updateDaysFromClient($clientDaysArray) {
print_r($clientDaysArray);
return "Update test";
}
Now comes my problem: Within my implementation, when calling the print_r on the array passed as parameter, i will only receive the first element of that array.
Array
(
[dayId] => 7
[dayName] => Sonntag
)
Can anyone explain to me why not the whole Array but only the first element is passed?
Please try to pass like this,
$result = #call_user_func_array(array($object,$request['method']),array($request['params'])))
pass $request['params'] inside another array.

Saving Multiple Select in input

I have model for
user(id,name)
section(id,name)
section_users(id,user_id,section_id)
The admin adds all the users and sections separately. Once theses are added I want the admin to selects the section and add all the users in it in section_users
I have a select input with multiple set to true. How do i save this data the cakephp way along with validation.
<?php echo $this->Form->input("section_id"); ?>
<?php echo $this->Form->input("user_id", array('multiple'=>'checkbox')); ?>
This generates
Array
(
[section_id] => 1
[user_id] => Array
(
[0] => 3
[1] => 4
)
)
I know i can loop and convert to this and use saveAll or saveMany but what is the cakephp way/right way to do it.
Array
(
[0] => Array
(
[section_id] => 1
[user_id] => 3
)
[1] => Array
(
[section_id] => 1
[user_id] => 4
)
)
As already mentioned, this is exaplained in the docs, please read them, and in case you don't understand them (which would be understandable as the HABTM section is a little confusing and requires some trial & error), tell us what exactly you are having problems with.
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
Based on the examples shown, the format for saving multiple X to Y should be
Array
(
[Section] => Array
(
[id] => 1
)
[User] => Array
(
[User] => Array(3, 4)
)
)
The corresponding form could look like this:
<?php echo $this->Form->create('User'); ?>
<?php echo $this->Form->input('Section.id'); ?>
<?php echo $this->Form->input('User', array('multiple' => 'checkbox')); ?>
<?php echo $this->Form->end('Add Users'); ?>
And the data would be saved via the Section model, that way its modified column is being updated properly.
public function addUsersToSection($id) {
// ...
if($this->request->is('post')) {
if($this->Section->save($this->request->data)) {
// ...
} else {
// ...
}
} else {
$options = array(
'conditions' => array(
'Section.' . $this->Section->primaryKey => $id
)
);
$this->request->data = $this->Section->find('first', $options);
}
$users = $this->Section->User->find('list');
$this->set(compact('users'));
}
Another way would be to restructure the array as shown by Vinay Aggarwal, that works fine, the only difference is that it requires saving through the join model, and consequently it doesn't update the Section models modified column.
CakePHP has the saveMany function, as mentioned in the documentation:
Model::saveMany(array $data = null, array $options = array())¶
This is HABTM relation, first of all you need have relation setup in SectionUser model. Then you can use saveAll() method to save all records at once.
Array
(
[0] => Array
(
[user_id] => 33
[section_id] => 9
)
[1] => Array
(
[user_id] => 33
[section_id] => 10
)
)
Make sure your data array is in above given format.
$this->SectionUser->saveAll($data);

CakePHP 1.2.6 / PHP5.2.12 Error in Array Loop in Assignment by Reference

I'm working on retrieving a stack of data and for some reason some of the data gets corrupted. For instance, I've got some Post models that each are related to Comment models (hasMany), and each of the Comment models belongsTo a User. When retrieving the data, here's what I get from the database for the comments:
[Post] => Array
(
)
[Comments] => Array
(
[0] => Array
(
[content] => "2010 has definitely been a busy year!"
[created] => 2010-02-10 13:47:15
[user_id] => 18
[post_id] => 1
[User] => Array
(
[id] => U8
[username] => Uace
[first_name] => Uace
)
[_explicitType] => Comment
)
[0] => Array
(
[content] => "I can't wait..."
[created] => 2009-12-10 13:57:36
[user_id] => 18
[post_id] => 1
[User] => Array
(
[id] => U8
[username] => Uace
[first_name] => Uace
)
[_explicitType] => Comment
)
)
The first character of each of the Comments[i][User] arrays has been replaced with a capital U, though in each case it should be different (such as ID of 18, username of Jace, etc).
I traced it back to an array manipulation I was working with to assign an _explicitType field for Flex interaction (Thanks, Paweł Mysior!) in the afterFind() function. Here's the loop where I stuck in the _explicitType:
if (is_array($results)) {
foreach ( $results as &$item )
{
$item['_explicitType'] = $this->name;
}
} else {
$item[$this->name]['_explicitType'] = $this->name;
}
I assume it has to do with the assignment by reference, but I can't think of why it is happening.
It is very strange.
Set debug to 2 in core.php and look in the sql log at the bottom of the page, maybe you'll find something there. Also look through all models (app, post, user, comment). There might be some beforeFind() that are causing this to happen. Does it also happen when you do a simple User->find()?
Btw. how do you retrieve data here?
I think found the issue. I moved the check for the array inside the foreach() and that seems to be working correctly now. I assume this is because on non-array items, it actually broke things. Here's my altered loop with logging on the test cases:
foreach ( $results as &$item )
{
if(is_array($item)) {
$item['_explicitType'] = $this->name;
} else {
$copy = $item;
$copy['_explicitType'] = $this->name;
$this->log($copy, LOG_DEBUG);
}
}
And sure enough, it logged the data with capital U's replacing the first letter.

Categories