Laravel returning "Object" instead of Array? - laravel

I'm executing a query like this as well as some others and returning them via response()->json().
$transactions = Transaction::where('created_at', '>=',
now()->firstOfYear())->get()->groupBy(function ($transaction)
{
return Carbon::parse($transaction->created_at)->format('M');
});
return response()->json([
'user' => $user->toArray(),
'transactions' => $transactions->toArray()
]);
However, while transactions is an Array in php, when it goes through response()->json it gets turned into an Object. I was hoping someone could tell me how I can prevent this and keep it as an array so I can iterate over it?
Thanks.
Picture of transactions output as requested. (Had to blur a lot of stuff due to sensitive info.)

Your array is keyed with month names, meaning it is an associative array. If you want the JSON to be an array, you will need your PHP array to be indexed numerically.
One option you can do is this (untested):
$userArray = [];
foreach ($user as $key => $value) {
$userArray[] = (object) [
'month' => $key,
'data' => $value,
];
}
return response()->json([
'user' => $userArray,
'transactions' => $transactions->toArray()
]);
That will make it a numerically indexed array of objects with the month being a property on the object and another property containing the rest of the data.

A solution I used before is to check on the frontend whether the data is array or an object, and if it is an object just convert it to array. Associative arrays will get converted to objects in javascript unless its keys start from 0 and increment like a normal arrays index.
An example of doing this:
window.axios.post('api/endpoint', data)
.then(res => {
const transactions = Array.isArray(res.data.transactions)
? res.data.transactions
: Object.keys.(res.data.transactions).map(key => response.data.transactions[key]);
})

Related

Pass array into a single column in Laravel

i am trying to pass some values into a single column in laravel database table.
The values are like this 20,45,67,89
but i want them to enter into the colume like this
===USER_ID====
20
45
67
89
I have tried like below, but not working..any suggestions ?
foreach ($request->val2 as $value){
$str_explode = explode(",",$value);
DB::table('retirement')->insertGetId([
'user_id' => $str_explode,
'amount' => $request->val1,
'week' => $request->week
]);
}
Hope this will work
foreach ($request->val2 as $value){
$str_explode = explode(",",$value);
$insert = [];
foreach($str_explode as $str){
$insert[] = [
'user_id' => $str,
'amount' => $request->val1,
'week' => $request->week
];
}
DB::table('retirement')->insert($insert);
I'm not sure i understood your question clearly, i'm assuming you want to insert array to a column:
did you try to set the column in migration to Json?
did you set the $casts in the model to json or array?
protected $casts = [ 'user_id' => 'array' ];
then when you do this, you can have an array added to that column like
Posts::create(['user_id'=>[1,2,3,4]]);
normally the user_id field is set to unsignedBigInt(), that type will not accept anything but integers, you gotta check the migration column type first.
explode() is returning an array, not a single value, that's why it will fail. Instead, you should loop through all values like this:
foreach ($request->val2 as $value){
$str_explode = explode(",",$value);
foreach($str_explode as $str){
DB::table('retirement')->insertGetId([
'user_id' => $str,
'amount' => $request->val1,
'week' => $request->week
]);
}
}
As a side advice, as you are not saving the id returned by insertGetID, you can simply use insert. Moreover, it's usually a good practice to use create because this way you will also save timestamps for created and updated.

Laravel 5.6. How to test JSON/JSONb columns

$this->assertDatabaseHas() not working with JSON/JSONb columns.
So how can I tests these types of columns in Laravel?
Currently, I have a store action. How can I perform an assertion, that a specific column with pre-defined values was saved.
Something like
['options->language', 'en']
is NOT an option, cause I have an extensive JSON with meta stuff.
How can I check the JSON in DB at once?
UPD
Now can be done like that.
I have solved it with this one-liner (adjust it to your models/fields)
$this->assertEquals($store->settings, Store::find($store->id)->settings);
Laravel 7+
Not sure how far back this solution works.
I found out the solution. Ignore some of the data label, Everything is accessible, i was just play around with my tests to figure it out.
/**
* #test
*/
public function canUpdate()
{
$authUser = UserFactory::createDefault();
$this->actingAs($authUser);
$generator = GeneratorFactory::createDefault();
$request = [
'json_field_one' => [
'array-data',
['more-data' => 'cool'],
'data' => 'some-data',
'collection' => [
['key' => 'value'],
'data' => 'some-more-data'
],
],
'json_field_two' => [],
];
$response = $this->putJson("/api/generators/{$generator->id}", $request);
$response->assertOk();
$this->assertDatabaseHas('generators', [
'id' => $generator->id,
'generator_set_id' => $generator->generatorSet->id,
// Testing for json requires arrows for accessing the data
// For Collection data, you should use numbers to access the indexes
// Note: Mysql dose not guarantee array order if i recall. Dont quote me on that but i'm pretty sure i read that somewhere. But for testing this works
'json_field_one->0' => 'array-data',
'json_field_one->1->more-data' => 'cool',
// to access properties just arrow over to the property name
'json_field_one->data' => 'some-data',
'json_field_one->collection->data' => 'some-more-data',
// Nested Collection
'json_field_one->collection->0->key' => 'value',
// Janky way to test for empty array
// Not really testing for empty
// only that the 0 index is not set
'json_field_two->0' => null,
]);
}
Note: The below solution is tested on Laravel Version: 9.x and Postgres version: 12.x
and the solution might not work on lower version of laravel
There would be two condition to assert json column into database.
1. Object
Consider Object is in json column in database as shown below:
"properties" => "{"attributes":{"id":1}}"
It can assert as
$this->assertDatabaseHas("table_name",[
"properties->attributes->id"=>1
]);
2. Array
Consider array is in json column as shown below:
"properties" => "[{"id":1},{"id":2}]"
It can assert as
$this->assertDatabaseHas("table_name",[
"properties->0->id"=>1,
"properties->1->id"=>2,
]);
Using json_encode on the value worked for me:
$this->assertDatabaseHas('users', [
'name' => 'Gaurav',
'attributes' => json_encode([
'gender' => 'Male',
'nationality' => 'Indian',
]),
]);

Trying to send multiple Key value inside with function for a Route: Laravel 5.2

I am using the below function to send the key value to show a message based on database operation.
return redirect()->route("Roles")->with("UpdateRole", "updated");
Now, I am looking to send a status code key also but as per the doc for with function, we can send one key and it's corresponding value.
Is there any way to send multiple Keys and their corresponding values?
Looking at Laravel API:
RedirectResponse with( string|array $key, mixed $value = null)
This should works:
return redirect()->route("Roles")->with([
"key1" => "value1",
"key2" => "value2"
]);
What you want is referred to as flashing data. Redirecting With Flashed Session Data introduces the topic.
What is not explicit but is possible is to use more than one ->with().
return redirect()->route("Roles")
->with("page_view_time", date("Y-m-d H:i:s"))
->with("user_name", $user->name);
Also, as #AlexandreThebaldi said, the Laravel API shows that an array can be used (be sure to use an associative array).
return redirect()->route("Roles")
->with('alerts', [
'success' => 'Congratulations! Account created.',
'info' => 'Check your email to verify your account.'
])
->with([
'user_name' => $user->name,
'user_score' => $user->score,
'highest_score' => $highest_score
]);
It is important to remember that you must know what you will get in your blade template, e.g. array or string / number.

CakePHP data change during validation and beforeSave is not being save with the changes

I'm saving data sent from a form.
In the Controller I am doing :
$this->User->create();
$this->User->save($this->request->data)
The $this->request->data looks like this:
'User' => array(
'password' => '*****',
'username' => 'ddddd',
'role' => '256/aa01bdf80d42beb48dd3225acddf447fdd7a39f3',
'parent_id' => '0/b6ba9bd57f6c70cf738891d4c6fac22abed4161d'
)
There are validation rules that works on 'role' and 'parent_id' to insure the role/parent ids are among those the user can access.
The validation changes the field values if the data is valid.
I also have a Tree behavior that is setting some tree fields in a beforeSave() filter in the behavior.
The validation rule is writing the change to $this->data->[$model][$field] as shown below.
public function checkListHash($check, $field) {
$explodedCheck = explode('/', $check[$field]);
if ($this->secureId($explodedCheck[0], $explodedCheck[1])) {
$this->data['User'][$field] = $explodedCheck[0];
return true;
}
return false;
}
The beforeFilter() in the behavior is changing the data array with statements like this:
$Model->data[$Model->alias][$ancestors] = $ancestorList;
When validation and the beforeFilter() processing is complete, I have a beautiful and correct array of data at $this->User->data that looks like this:
'User' => array(
'password' => '*****',
'active' => '0',
'role' => '256',
'parent_id' => '0',
'node' => '0',
'username' => 'ddddd',
'modified' => '2013-09-15 09:55:02',
'created' => '2013-09-15 09:55:02',
'ancestor_list' => ',0,'
)
However, $this->request->data is unchanged. And that is what is being save.
Clearly I'm not understanding the relationship of these various ways to get to the data. I've tried a variety of ways to address the data in the three contexts:
Controller
Model
Behavior
And I've tried $this->User->create($this->request->data); before the Controller save() statement.
In the controller, what I'm seeing as available data arrays:
PRIOR TO THE SAVE
$this->request->data = $this->data = proper data from the form
$this->User->data = some default, unpopulated array
PRIOR TO THE SAVE when I use $this->User->create($this->request->data)
all three arrays contain raw form data
AFTER THE SAVE in either case
$this->request->data = $this->data = exactly as before
$this->User->data = the properly massaged data
Can anyone sort me out?
Don Drake
Just to explain the data arrays to you, when you submit the form, the data from it is stored in $this->request->data on the controller. You are then modifying $this->User->data from inside the model, which is a different array on the model itself. It would not affect $this->request->data because it's a completely different array which belongs to the controller, and the model has no knowledge of it.
You are then saving the User model using the request data, which remains unchanged from when the form was submitted. This is logical and normal behaviour because you're not actually using the $this->User->data array that you've modified.
Your save might always be failing because the data the model is trying to save isn't the updated data, it's just the basic data from $this->request->data.
Try this:
$this->User->set($this->request->data);
$this->User->save();
Also, if you are using a beforeSave in your model, make sure the method returns true, or it will never actually go on to save.

JRegistry exists() returns empty array

I was trying to save a form data to DB. In the controller save() function there is a statement
$data = $model->validate($form, $data);
But it always returns empty. I tracked down the problem to the filter() function in /libraries/joomla/form/form.php (comes with joomla package). Here is some code (shortened):
$input = new JRegistry($data);
$output = new JRegistry;
foreach ($fields as $field)
{
// Initialise variables.
$name = (string) $field['name'];
if ($input->exists($name)){
$output->set($name, $this->filterField($field, $input->get($name, (string) field['default'])));
}
}
$input looks like :
JRegistry Object ( [data:protected] => stdClass Object ( [jform] => stdClass Object ( [title] => Utility Model/Patent application [ap_name] => d ...) [option] => com_eipoapplications [task] => save ) )
And each $name in the loop always contain the form element name (like 'title', 'ap_name' ... ).
But the if conditional statement always returns false. Does any one help me know why JRegistry exists() function is not finding the elements?
I think you are having an inconsistency between form and data.
Let's say the form contains a field with name title.
$data array should have a value under key of same name:
$data = array(
'title' => 'Utility Model/Patent application',
'ap_name' => 'd'
);
Or using print_r
Array
(
[title] => Utility Model/Patent application
[ap_name] => d
)
If there's no data for such field, validation is omitted. If all data keys are wrong, function returns empty array.
The question is, how it happened :/

Resources