Laravel Collection Returns Inconsistant Results - php

I have a collection that will switch between responding as an array or as an object seemingly at random. What would cause that to happen?
$events = Event::all();
$events = $events->map(function ($event) use ($request) {
$reducedEventName = Helper::alphaNum($event->name);
$reducedRequestName = Helper::alphaNum($request->name);
$distance = levenshtein($reducedEventName, $reducedRequestName);
return [
'name' => $event->name,
'url' => route('event.view', ['slug' => $event->slug]),
'distance' => $distance,
];
})
->filter(function ($event) {
return $event['distance'] <= Helper::threshold($event['name']);
})
->take(3)
->sortBy('distance');
return $events->toArray();
This method is called via XHR, so I want the raw JSON response. Sometimes it looks like this (👍):
[{
"name": "Taylor Swift - Reputation - Release",
"url": "http:\/\/localhost\/e\/lgKejoPSg",
"distance": 22
}, {
"name": "Wiz Khalifa \"Laugh now, fly later\"",
"url": "http:\/\/localhost\/e\/DdLnFD3Qf",
"distance": 24
}]
And sometimes it looks like this (👎):
{
"1": {
"name": "Wiz Khalifa \"Laugh now, fly later\"",
"url": "http:\/\/localhost\/e\/DdLnFD3Qf",
"distance": 18
},
"0": {
"name": "Taylor Swift - Reputation - Release",
"url": "http:\/\/localhost\/e\/lgKejoPSg",
"distance": 23
}
}
Laravel 5.4

As to your question, I am not sure what could cause that to happen as the sortBy() method states it returns a collection. Do you return that exact $events as is to your blade? If so that could be inconsistency on the browser deciding how to handle the collection that is sent back to it. You could always use ->toArray() at the end of your query to ensure that it always returns an array, or ->toJson() if you don't want to do anything else with it.

Resorting the results tries to preserve the original keys, so I needed to discard the original keys:
return array_values($events->toArray());

Related

Laravel Model created_at inconsistent display

I am new to laravel and php,
I have the code below, REST API
public function sendMessage(Request $request)
{
$message = Message::create($request->all());
return response()->json(['result'=>'success','created_at'=>$message->created_at],200);
}
This is displayed like this in the postman
{
"result": "success",
"created_at": "2020-06-29T23:31:32.000000Z"
}
If I change the return message-object by changing return statement to
return response()->json(['result'=>'success','created_at'=>$message],200);
Then time format is displayed differently as below
{
"result": "success",
"created_at": {
"sender": "47",
"receiver": "23",
"message": "hello world reply",
"updated_at": "2020-06-29 23:38:53",
"created_at": "2020-06-29 23:38:53",
"id": 515
}
}
I do not want this form "2020-06-29T23:31:32.000000Z" when I access it as a property,not sure what is this 00000Z at then end. want it like this "2020-06-29 23:38:53" Any help
When you access the data member ->created_at you get a Carbon instance, instead if you serialize the object, you get its attribute.
This is why you are getting two different serialization, because you are serializing two different things (one is a Carbon instance, the onthe one is a Model)
If you convert the Carbon instance to a string it will be in the same format as you see in the serialized model. When you pass it without doing this it is going to json_encode the value which will return it how you are currently seeing it.
return response()->json([
'result' => 'success',
'created_at' => (string) $message->created_at
],200);

Find the value of a key in an unknown multilevel array in PHP

I have a use defined json string inside a database.
The JSON string has lots of levels. I know my user will define a kay called "basevalue" and place it somewhere in the json.
The problem is, I don't know ahead of time where in the JSON it will be placed, and every use is likely to place is in different places in the array, perhaps at different levels.
This is an example of the JSON data being saved by the user:
{
"name": "",
"type": "layout",
"children": [
{
"name": "",
"type": "section",
"children": [
{
"name": "",
"type": "row",
"children": [
{
"name": "",
"type": "column",
"props": {
},
"children": []
},
{
"type": "column",
"children": [
{
"type": "itemdata",
"props": {
**"basevalue": "100",**
},
"children": []
}
]
}
]
}
]
}
I'm converting this data to an array using json_decode:
$json = json_decode($json, true);
No I need to search through the array, and find the key of 'basevalue' and then get whatever value the user has input, in the case above that would be '100'.
So to the issue is, I have no idea what 'node' the 'basevalue' key will be. It could be 40 deep, it could be in the first 'children' node.
This is up to the user.
So how do I take any version of the JSON string about and return the '100'?
Many thanks.
You can recursively iterate over the data and get the value of the key basevalue. To make this search faster, we can adopt an early exit approach similar to breadth first search. By this, we call add all values who are arrays in a queue and continue our search for the key basevalue and later on deal with pending queue. This would be faster than basic recursion because a lot of times it's possible that key was on the same level but we searched all the way down on all other trees which proved out to be trivial.
Snippet:
function getBaseValue($arr,$search_key){
$pending_calls = [];
foreach($arr as $key => $value){
if(is_array($value)){
$pending_calls[] = $value; // queue them for later judgement
}else if($search_key === $key){
return $value;
}
}
foreach($pending_calls as $call){
$returned_val = getBaseValue($call,$search_key);
if($returned_val !== false) return $returned_val;
}
return false;
}
echo getBaseValue($arr,'basevalue');
Demo: https://3v4l.org/gdLK1

Laravel is returning objects with key:value instead of array of objects

I am trying to return Json response as an array of objects. But instead I got response as object of objects. I have condition_question table where I save question_id and condition_id. I want to retrieve all questions which contains particular condition id. And sort them by answers_number. I am new to Laravel, here is my code:
$conditionsIdArray = array($chosenConditionsIds);
$results = Question::whereIn('question_id', function ($query) use ($conditionsIdArray) {
$query->select('question_id')
->from('condition_question')
->whereIn('condition_id', $conditionsIdArray);
})->get()->sortByDesc('answers_number')->take(5);
return response()->json([
'questions' => $results
], 200);
I get response:
{
"questions": {
"0": {
"question_id": 842,
"question_title": "Qui tempora...",
"question_body": "Repellendus non sint...",
"image": "https://lorempixel.com/640/480/?18901",
"question_view_count": 17,
"votes_number": 9,
"answers_number": 9,
"id_user": 9930,
"created_at": "2019-09-07 09:59:05",
"updated_at": "2019-09-08 18:23:41"
},
"28": {
"question_id": 20346,
"question_title": "Quaerat facere...",
"question_body": "Repudiandae culpa ...",
"image": "https://lorempixel.com/640/480/?91963",
"question_view_count": 2,
"votes_number": 2,
"answers_number": 9,
"id_user": 3546,
"created_at": "2019-09-07 10:07:38",
"updated_at": "2019-09-07 10:07:38"
},etc
}
As you can see, I get object with object. I do not want key/value, just simple array of objects type Question.
I am struggling two days now, have tried some different stuff like toArray() but do not know how to solve it. Any help would be most welcome.
If you change the keys in an indexed array, it will believe it has an associate array, due to sorting the index is off. On the Laravel collection there is a values() method, which you can call there that reindex the collection.
return response()->json([
'questions' => $results->values()
], 200);

JMSSerializerBundle and Symfony 2 - Output Doctrine/ODM to JSON file

I am trying to retrieve all records and display them in a JSON file.
My current function retrieves all Events that belong to a specific user.
/**
* create json files from doctrine/mongo
* #Route("/createjson", name="createjson")
*/
public function createJson()
{
// check user authentication
$this->denyAccessUnlessGranted('ROLE_USER', null, 'Unable to access this page!');
$dm = $this->get('doctrine_mongodb')->getManager();
$repository = $dm->getRepository('AppBundle:Event');
$events = $repository->findBy(array('user' => $this->getUser()));
$serializer = SerializerBuilder::create()->build();
$result = $serializer->deserialize($events, 'AppBundle\Document\Event', 'json');
var_dump($result);
exit;
}
This is not working because some of the elements passed into the serializer are of an array format. Error I am getting.
Warning: json_decode() expects parameter 1 to be string, array given
500 Internal Server Error - ContextErrorException
However if I use the inbuilt Symfony Serializer it works fine:
$serializer = $this->container->get('serializer');
$reports = $serializer->serialize($events, 'json');
return new Response($reports);
However the JSON to be produced will be different to my Document/Entity hence why I want/need to use the JMSSerializerBundle.
For example, a record looks like this:
[{
"id": "572041b3288b560e5e00451c",
"name": "Test",
"date": "2016-04-27T05:25:00+1000",
"enddate": "2016-04-30T11:55:00+1000",
"location": {
"name": "Sydney, NSW"
},
"key": {
"id": "1g43g34g34g23f32g32G32gGSDF"
},
"user": {
"id": "57203174288b560e5e0044da"
}, ...
}]
But I only want to display (output) to JSON
[{
"id": "572041b3288b560e5e00451c",
"name": "Test",
"date": "2016-04-27T05:25:00+1000",
"location": "Sydney, NSW"
}]
How would I go about doing this? There is not much documentation on JMSSerializerBundle online.
Edit: I should mention that the database collection I am querying has a relation to the User collection which is managed by FOSUserBundle. I'm not sure if this has any relation to my problem however
You should look at the documentation of the bundle, may be you will find more information
http://jmsyst.com/bundles/JMSSerializerBundle
http://jmsyst.com/libs/serializer/master/usage
You seems to use the wrong function of the serializer. In your case, you seems to need to get a json from your user object, so you need to use
$serializer = SerializerBuilder::create()->build();
$result = $serializer->serialize($events, 'AppBundle\Document\Event', 'json');
serialize($object):string : get a string from an object
deserialize($string):object : get an object from a representation of an object (json, xml...).

Laravel numeric array in select results

I'm using Lumen to set up a microservice for polling a database frequently and distribute the dataset through a wamp router to multiple clients. The database query is stored in a stored procedure, that's why i do the following in my controller:
$result = DB::select($query);
return $result;
The return gives the following dataset:
[
{
"0": "012345",
"1": "Moby Dick",
"2": "Herman Melville",
"3": "Hardcover",
"isbn": "012345",
"title": "Moby Dick",
"author": "Herman Melville",
"type": "Hardcover"
},
{
"0": "123456",
"1": "Laravel: Code Bright",
"2": "Dayle Rees",
"3": "Ebook",
"isbn": "123456",
"title": "Laravel: Code Bright",
"author": "Dayle Rees",
"type": "Ebook"
},
{
"0": "234567",
"1": "Easy Laravel 5",
"2": "W.J. Gilmore",
"3": "Ebook",
"isbn": "234567",
"title": "Easy Laravel 5",
"author": "W.J. Gilmore",
"type": "Ebook"
}
]
I want to remove the numeric key-value pairs prepending the associative key-value pairs. How can i do that?
Thanks in advance!
Edit: things I tried:
$result = DB::select($query)->get(); // Gives: Call to a member function get() on array. For obvious reasons
A dirty hack like Matei stated: Looping through the array and removing the KVP where the key is numeric. Which works, but I think the Laravel/Lumen framework offers cleaner solutions, which I am not able to find.
In config/database.php you can change 'fetch' => PDO::FETCH_CLASS, to 'fetch' => PDO::FETCH_ASSOC,
or
You can use array_reduce and array_filter like:
$result = json_decode(DB::select($query), true);
$result = array_reduce($result, function ($result, $item) {
$result[] = array_filter($result, function ($key) {
return !is_numeric($key);
}, ARRAY_FILTER_USE_KEY)
return $result;
}, array());
return json_encode($result);
NOTE: If the DB stmt is returning an array, rather than a json encoded string, then you must remove the json_decode and json_encode functions calls.

Categories