I am trying to save my Laravel Eloquent model to the database.
All date properties are saved in wrong format to DB (even created_at and updated_at).
In example below, my updated_at has been renamed as S_MODDATE but it's still the "native" field.
Reading the date fields works fine.
Example
My date in PHP : 2021-12-07 (7th of December)
When saved to database : 2012-07-12 (12th of July)
When read again from database : 2012-07-12
Minimal example of my code :
$currentDatetime = new \DateTime();
Log::debug($currentDatetime->format("Y-m-d h:i:s")); // Looks correct
$approRecord = T_Appro::find($approvalId);
$approRecord->DATESTATUT = $currentDatetime;
DB::enableQueryLog();
$approRecord->save();
Log::debug(DB::getQueryLog());
Corresponding log
[2021-12-07 13:17:25] local.DEBUG: 2021-12-07 01:17:25
[2021-12-07 13:17:28] local.DEBUG: array (
0 =>
array (
'query' => 'update [t_appro] set [DATESTATUT] = ?, [t_appro].[S_MODDATE] = ? where [T_APPROID] = ?',
'bindings' =>
array (
0 =>
DateTime::__set_state(array(
'date' => '2021-12-07 13:17:25.981319',
'timezone_type' => 3,
'timezone' => 'Europe/Brussels',
)),
1 => '2021-12-07 13:17:28.035',
2 => 'S000000029',
),
'time' => 468.81,
),
)
Tested solutions
Add protected $dateFormat = 'Y-m-d H:i:s'; to my model
Add following code to my model
public function getDateFormat()
{
return 'Y-m-d H:i:s.v';
}
Set app.php timezone to Europe/Brussels
I have a store function that saves array items into my items table and together with that I am trying to check if the product_is is already in my Warehouse1StockSummaries. if still not, I will grab the product_id and its qty, If its there already then I want to ADD the value from the 'stock_in_qty' which is inside the array to the 'qty_in' in my Warehouse1StockSummaries. I hope my explanation make sense to you :)
here's my code.
public function store(Request $request)
{
$input = $request->all();
$items = [];
for($i=0; $i<= count($input['stock_in_qty']); $i++) {
if(empty($input['stock_in_qty'][$i]) || !is_numeric($input['stock_in_qty'][$i])) continue;
$acceptItem = [
'order_id' => $input['order_id'][$i],
'product_id' => $input['product_id'][$i],
'order_item_id' => $input['order_item_id'][$i],
'delivery_date' => $input['delivery_date'][$i],
'company_id' => $input['company_id'][$i],
'stock_in_qty' => intval($input['stock_in_qty'][$i]),
'stock_out_qty' => $input['stock_out_qty'][$i],
'transfer_to' => $input['transfer_to'][$i],
'delivery_note' => $input['delivery_note'][$i],
'user_id' => $input['user_id'][$i]
];
$product_id = $input['product_id'][$i];
$qty_in = intval($input['stock_in_qty'][$i]);
// dd($qty_in);
// ADD stock_in_qty TO QTY_IN ????
$stockSummary = Warehouse1StockSummaries::updateOrCreate(
['product_id' => $product_id ],
['qty_in' => $qty_in,
'qty_out' => null
]);
// dd($stockSummary);
array_push($items, Warehouse1stocks::create($acceptItem));
}
return redirect()->route('orders.index');
}
I check and everything is ok the only missing is the part where I need to grab the value from 'stock_in_qty' and add to 'qty_in' if the product id is already found in Warehouse1StockSummaries. Thank you so much in advance!
You could use the wasRecentlyCreated property on the model to determine if the model has just been created or not. If it hasn't then it won't have used $qty_in value, this means you could then use the increment() to add to the existing value in the database:
$stockSummary = Warehouse1StockSummaries::firstOrCreate(
['product_id' => $product_id ],
['qty_in' => $qty_in, 'qty_out' => null]
);
if (!$stockSummary->wasRecentlyCreated) {
$stockSummary->increment('qty_in', $qty_in);
}
I am trying to get away from doing things manually and repetitively by correctly utilizing loops and functions (methods) in oop programming; but I have hit a major stumbling block as it regards to multidimensional array groups, in passing the correct values to the necessary abstracted function (method) responsible for a database action.
Any help at all is very much welcomed and will enable me to move on from this stumbling block that I have been trying to push away for days upon days but without progress and it is out of true frustration and much agony that I am here begging for help.
Below is the code that for simplicity I have shortened as much as possible (can be easily tested locally by copying and pasting):
// array with table properties and form values - start
$form_fields_arr = [
'group' => [
'anime' => [ // genre
'table_prop' => [ // for update query - table properties
'table_name' => 'anime_tbl',
'account_id' => 2,
'visible' => 'yes'
],
'form_data' => [ // for update query - form values
'2' => 'Attack on Titan',
'4' => 'RWBY',
'6' => 'Rurouni Kenshin',
'8' => 'A Silent Voice'
]
],
'movie' => [ // genre
'table_prop' => [ // for update query - table properties
'table_name' => 'movie_tbl',
'account_id' => 4,
'visible' => 'yes'
],
'form_data' => [ // for update query - form values
'1' => 'Queen of Katwe',
'3' => 'Forest Gump',
'5' => 'War Horse',
'7' => 'The Fault in our Stars'
]
]
]
]; // ... end
// loop through multidimensional array and pass values to function - start
foreach ($form_fields_arr['group'] as $frm_key_1 => $frm_val_1) { // 2d array
foreach ($frm_val_1 as $frm_key_2 => $frm_val_2) { // 1d array
if (strcasecmp($frm_key_1, $frm_key_1) === 0) { // group by genre
foreach ($frm_val_2 as $frm_key_3 => $frm_val_3) { // 1d array
if (strcasecmp($frm_key_2, 'form_data') === 0) {
$title = $form_fields_arr['group'][$frm_key_1]['form_data'][$frm_key_3]; // anime/movie title
}
if (isset($frm_val_2['table_name']) &&
isset($frm_val_2['account_id']) &&
isset($frm_val_2['visible']) &&
isset($title)
) {
dbUpdate(
$frm_val_2['table_name'],
$frm_val_2['account_id'],
$frm_val_2['visible'],
$title
);
}
} // 1d array
} // if block
} // 1d array
} // 2d array
// ... end
// function that receives passed values - start
function dbUpdate($table_name, $account_id, $title_col, $form_value) {
$test_val_arr = [$table_name, $account_id, $title_col, $form_value];
return print_r($test_val_arr);
} // ... end
The above code outputs:
// array values passed to and returned from function
Array (
[0] = movie_tbl
[1] = 4
[2] = yes
[3] = A Silent Voice
)
Array (
[0] = movie_tbl
[1] = 4
[2] = yes
[3] = A Silent Voice
)
Array (
[0] = movie_tbl
[1] = 4
[2] = yes
[3] = A Silent Voice
)
Array (
[0] = movie_tbl
[1] = 4
[2] = yes
[3] = A Silent Voice
)
But the desired result that I am trying to achieve is:
// for anime genre - array values passed to and returned from function
Array (
[0] = anime_tbl
[1] = 2
[2] = yes
[3] = Attack on Titan
)
Array (
[0] = anime_tbl
[1] = 2
[2] = yes
[3] = RWBY
)
Array (
[0] = anime_tbl
[1] = 2
[2] = yes
[3] = Rurouni Kenshin
)
Array (
[0] = anime_tbl
[1] = 2
[2] = yes
[3] = A Silent Voice
)
// for movie genre - array values passed to and returned from function
Array (
[0] = movies_tbl
[1] = 4
[2] = yes
[3] = Queen of Katwe
)
Array (
[0] = movies_tbl
[1] = 4
[2] = yes
[3] = Forest Gump
)
Array (
[0] = movies_tbl
[1] = 4
[2] = yes
[3] = War Horse
)
Array (
[0] = movies_tbl
[1] = 4
[2] = yes
[3] = The Fault in our Stars
)
so upon everything royally failing with me spending literally about a week trying to fix this, telling myself that it is very simple and I really shouldn't be stuck here, out of desperation I decided to go back to my repetitive ways and tried the following:
// new array without table properties - start
$new_array = [];
$new_array['group']['anime'] = $form_fields_arr['group']['anime']['form_data'];
$new_array['group']['movie'] = $form_fields_arr['group']['movie']['form_data']; // ... end
// loop through multidimensional array and pass values to function - start
foreach ($new_array['group'] as $key_1 => $val_1) { // 2d array
foreach ($val_1 as $key_2 => $val_2) { // 1d array
if (strcasecmp($key_1, $key_1) === 0) {
dbUpdate('anime_tbl', 2, 'yes', $val_2);
dbUpdate('movie_tbl', 4, 'yes', $val_2);
} // if block
} // 1d array
} // 2d array
// ... end
But the results are still very much undesirable. Everything was working fine until I started using multidimensional arrays, simply because I realized that utilizing multidimensional arrays help me to shorten my code in other areas considerably. But I am stuck here and will have to go back further up and undo quite a lot of changes if I can't get this to work. I am pleading for help from any good soul out there. Please help me someone! Anyone!
I am being optimistic here and assuming that if by any chance I do get some help in fixing the above problem, could someone please also teach me how to loop through an array structure like the one below while yet getting the desired results without duplicates (I have truly tried but have truly failed):
// array with table properties and form values - start
$form_fields_arr = [
'table_prop' => [ // table properties group
'anime' => [ // for update query - table properties
'table_name' => 'anime_tbl',
'account_id' => 2,
'visible' => 'yes'
],
'movie' => [ // for update query - table properties
'table_name' => 'movie_tbl',
'account_id' => 4,
'visible' => 'yes'
]
],
'form_data' => [ // for update query - form values
'anime' => [ // genre
'2' => 'Attack on Titan',
'4' => 'RWBY',
'6' => 'Rurouni Kenshin',
'8' => 'A Silent Voice'
],
'movie' => [ // genre
'1' => 'Queen of Katwe',
'3' => 'Forest Gump',
'5' => 'War Horse',
'7' => 'The Fault in our Stars'
]
]
]; // ... end
You got a logic mistake in your for loops. First of all your variable namings are not very intuitive. $frm_key_1, $frm_key_2, etc. look alike and force the reader to have the array structure in mind all the time to understand the variables meaning. This led to a mistake like this one: if( strcasecmp($frm_key_1, $frm_key_1) === 0 ). This is always true.
Then you had two exclusive conditions:
if (strcasecmp($frm_key_2, 'form_data') === 0)
And:
if (isset($frm_val_2['table_name']) && /* ... */) {
If $frm_key_2 is 'form_data' you are in the second child of the genre array, yet the fields 'table_name', etc. are defined only in the first one (witht the key 'table_prop'). So both conditions can never be true at the same time.
Your condition to trigger the dbUpdate() function was, that all fields of the 'table_prop' array were present (which you iterated through at the same time), and a $title was set aswell. This was only true after your third for-loop iterated for the second time. During that iterations the $title variable got overwritten constantly, but no sbUpdate() was triggered, because $frm_val_2 had the values from 'form_data' instead of 'table_prop'. So after the 3rd for loop finished the 2nd time $title was 'A Silent Voice', which is simply the last child of the first 'form_data' array. Afterwards your 2nd for loop iterated the 2nd 'table_prop' array again, which means that now the 'dbUpdate()' condition was true, so it postet 4 times (number of childs in the 'table_prop' array) the parameters with $title = 'A Silent Voice'.
You tried to make everything as generic as possible, making everything over complicated. The best solution that works here is one that respects the specific structure.
This works:
<?php
// array with table properties and form values - start
$form_fields_arr = [
'group' => [
'anime' => [ // genre
'table_prop' => [ // for update query - table properties
'table_name' => 'anime_tbl',
'account_id' => 2,
'visible' => 'yes'
],
'form_data' => [ // for update query - form values
'2' => 'Attack on Titan',
'4' => 'RWBY',
'6' => 'Rurouni Kenshin',
'8' => 'A Silent Voice'
]
],
'movie' => [ // genre
'table_prop' => [ // for update query - table properties
'table_name' => 'movie_tbl',
'account_id' => 4,
'visible' => 'yes'
],
'form_data' => [ // for update query - form values
'1' => 'Queen of Katwe',
'3' => 'Forest Gump',
'5' => 'War Horse',
'7' => 'The Fault in our Stars'
]
]
]
];
// loop through multidimensional array and pass values to function - start
foreach ($form_fields_arr['group'] as $genreData) {
$tableProperties = $genreData['table_prop'];
if (!isset($tableProperties['table_name'])
|| !isset($tableProperties['account_id'])
|| !isset($tableProperties['visible'])) {
continue;
}
$data = $genreData['form_data'];
foreach ($data as $title) {
dbUpdate(
$tableProperties['table_name'],
$tableProperties['account_id'],
$tableProperties['visible'],
$title
);
}
}
// function that receives passed values - start
function dbUpdate($table_name, $account_id, $title_col, $form_value) {
$test_val_arr = [$table_name, $account_id, $title_col, $form_value];
return print_r($test_val_arr);
} // ... end
For the last part of the question that wasn't answered, thanks to Philipp Maurer's answer, after playing around with the code I got it to work. I am just placing the answer here for anyone who might have a similar problem and would like to better understand how to group and fetch values from a multidimensional array using a foreach loop without duplicates or incorrect results. See below code:
// array with table properties and form values - start
$form_fields_arr = [
'table_prop' => [ // table properties group
'anime' => [ // for update query - table properties
'table_name' => 'anime_tbl',
'account_id' => 2,
'visible' => 'yes'
],
'movie' => [ // for update query - table properties
'table_name' => 'movie_tbl',
'account_id' => 4,
'visible' => 'yes'
]
],
'form_data' => [ // for update query - form values
'anime' => [ // genre
'2' => 'Attack on Titan',
'4' => 'RWBY',
'6' => 'Rurouni Kenshin',
'8' => 'A Silent Voice'
],
'movie' => [ // genre
'1' => 'Queen of Katwe',
'3' => 'Forest Gump',
'5' => 'War Horse',
'7' => 'The Fault in our Stars'
]
]
]; // ... end
// loop through multidimensional array and pass values to function - start
foreach ($form_fields_arr as $index => $group_array) {
foreach ($group_array as $genre_key => $genre_val) {
if (!isset($group_array[$genre_key]['table_name']) ||
!isset($group_array[$genre_key]['account_id']) ||
!isset($group_array[$genre_key]['visible'])
) {
continue;
}
foreach ($form_fields_arr['form_data'][$genre_key] as $data_key => $data_title) {
dbUpdate(
$group_array[$genre_key]['table_name'],
$group_array[$genre_key]['account_id'],
$group_array[$genre_key]['visible'],
$data_title
);
}
}
}
// ... end
// function that receives passed values - start
function dbUpdate($table_name, $account_id, $title_col, $form_value) {
$test_val_arr = [$table_name, $account_id, $title_col, $form_value];
return print_r($test_val_arr);
} // ... end
I have an multidimensional array from which i need to get some data, make some simple math and display them on a js graphic chart.
My only problem is that i can't get the data from the arrays.
This is how to array looks:
object(stdClass) [211]
public 'countries' =>
array (size=30)
0 =>
array (size=1)
0 =>
object(stdClass)[215]
public 'country' => string 'RO' (lenght=2)
public 'clicks' => int 4
1 =>
object(stdClass)[215]
public 'country' => string 'RU' (lenght=2)
public 'clicks' => int 1
1 =>
array (size=1)
0 =>
object(stdClass)[215]
public 'country' => string 'RU' (lenght=2)
public 'clicks' => int 4
1 =>
object(stdClass)[215]
public 'country' => string 'RO' (lenght=2)
public 'clicks' => int 2
...and so on till 29 (there are 30 days) so each day has clicks from different countries.
What i need to do is to extract the data from the array in this format:
name: ['RO', 'RU']
data: [6, 5]
I hope you understand what i am trying to do.
I am no expert, just a beginner and i can't work this out.
EDIT: in the end, i need to say that x country has x clicks on the last 30 days.
Be aware that i don't know witch countries are in the array because this is from an API that provides the top 10 countries by clicks.
So, in each day could be a country that wasn't in the day before and so on.
EDIT 2: this is what i have tried based on my experience:
function getCountriesByClicks($data)
{
$jsData = [];
$clicks = [];
$country = [];
for ($x = 0; $x < sizeof($data->data[0]->data->countries); $x++) {
foreach ($data->data[0]->data->countries[$x] as $value) {
array_push($country, $value->country);
array_push($clicks, $value->clicks);
}
$jsData[] = ['name' => $country, 'data' => $clicks];
}
return json_encode($jsData);
}
Ignore the json return for it's just to use in my javascript graphic chart.
Thank you!
try the following:
$name = array();
$data = array();
array_map(function($array){
array_map(function($obj){
$name[] = $obj->country;
$data[] = $obj->clicks;
},$array);
},$yourObject->countries);
i'm newbie in Cake and wodering how to insert multiple rows in a single saveall function,
i got this table,
CREATE TABLE IF NOT EXISTS `dates` (
`date` varchar(10) COLLATE utf8_unicode_ci NOT NULL
)
what i'm trying to do is let user select start date and end date using JQuery calander, once submit all the dates between this range will be saved into database, i already got the array of dates eg:
`array(
(int) 0 => '5/8/2013',
(int) 1 => '6/8/2013',
(int) 2 => '7/8/2013',
(int) 3 => '8/8/2013',
)
`
then my controller looks like this:
public function index(){
if ($this->request->is('post')) {
$this->Date->create();
$data = array();
$data['dates']=array();
$startDate = $this->request->data['Date']['from'];
$endDate = $this->request->data['Date']['to'];
$datesBlocked = $this->loopDates($this->request->data['Date']['from'],$this->request->data['Date']['to']);
$data['dates'][] = $this->request->data['Blockdate']['from'];
$data['dates'][] = $this->request->data['Blockdate']['to'];
/*foreach($datesBlocked as $data) {
$data['dates'][] = $data;
}*/
if($this->Date->saveAll($data)) {
$this->Session->setFlash(__('done'));
if ($this->Session->read('UserAuth.User.user_group_id') == 1) {
// $this->redirect("/manages");
}
}
}
public function loopDates($from,$to){
$blockdates = array();
$start = strtotime($from);
$end = strtotime($to);
debug($start);
$counter = 0;
for($t=$start;$t<=$end;$t+=86400) {
$d = getdate($t);
$blockdates[$counter++] = $d['mday'].'/'.$d['mon'].'/'.$d['year'];
}
debug($blockdates);
return $blockdates;
}
issue was i can't get foreach work, if i uncomment the foreach, i got error said Illegal string offset 'dates' , so i commented that and try to only add the start date and end date to the array to see if that works, then i got another error said.
`array(
'dates' => array(
(int) 0 => '08/05/2013',
(int) 1 => '09/05/2013'
)
)
`
Notice (8): Array to string conversion [CORE\Cake\Model\Datasource\DboSource.php, line 1005]Code
cuz i'm trying to insert 2 values into one field...i know it should be sth like
`array(
'dates' => array( (int) 0 => '08/05/2013',
)
'dates' => array((int) 1 => '09/05/2013'
))
`but can't figure out how to do it. Any help would be much appreciate!!!!
The structure you'll want your array to save multiple dates using saveAll() is this:
array(
'Date' => array(
0 => array(
'date' => '08/05/2013',
),
1 => array(
'date' => '09/05/2013',
)
),
)
I know that this is a little late, but to write multiple rows in a loop, you have to proceed the save with a create().
eg:
foreach($items as $lineItem){
$this->Invoice->create();
$this->Invoice->save(array(
'user_id'=>$property['User']['id'],
'invoice_id'=>$invId['Invoices']['id'],
'item_id'=>$lineItem['item_number'],
'quantity'=>$lineItem['quantity'],
'price'=>$lineItem['mc_gross']
);
}
Just thought it was worth mentioning, hopefully it will help someone.