Alexis Gatuingt
Alexis Gatuingt

Reputation: 547

Laravel - why json response return sometimes an array sometimes an object

Here is my code :

    public function list()
    {
        $users = User::with('group')->get()->toArray();
        return response()->json([

            'clients' => array_filter($users, function ($r) {
                return $r['group']['name'] === 'client';
            }),

            'employes' => array(array_filter($users, function ($r) {
                return $r['group']['name'] !== 'client';
            })),

        ]);
    }

Here is the response :

{
  "clients": {
    "2": {
      "id": 3,
      "name": "Client 1",
      "email": "[email protected]",
      "email_verified_at": null,
      "created_at": null,
      "updated_at": null,
      "group_id": 4,
      "group": {
        "id": 4,
        "name": "client"
      }
    },
    "3": {
      "id": 4,
      "name": "Client 2",
      "email": "[email protected]",
      "email_verified_at": null,
      "created_at": null,
      "updated_at": null,
      "group_id": 4,
      "group": {
        "id": 4,
        "name": "client"
      }
    },
    "4": {
      "id": 5,
      "name": "Client 3",
      "email": "[email protected]",
      "email_verified_at": null,
      "created_at": null,
      "updated_at": null,
      "group_id": 4,
      "group": {
        "id": 4,
        "name": "client"
      }
    }
  },
  "employes": [
    [
      {
        "id": 1,
        "name": "Alexis",
        "email": "[email protected]",
        "email_verified_at": null,
        "created_at": null,
        "updated_at": null,
        "group_id": 1,
        "group": {
          "id": 1,
          "name": "admin"
        }
      },
      {
        "id": 2,
        "name": "guest",
        "email": "[email protected]",
        "email_verified_at": null,
        "created_at": null,
        "updated_at": null,
        "group_id": 2,
        "group": {
          "id": 2,
          "name": "guest"
        }
      }
    ]
  ]
}

I tried to change the conditions of the array_filter. Sometimes I have an array, sometimes I have an object. I don't understand how this is determined

Stackoverflow tells me "It looks like your post is mostly code; please add some more details." So ... what details to add?

Thank you

Upvotes: 11

Views: 10744

Answers (3)

Kasun Ariyasinghe
Kasun Ariyasinghe

Reputation: 101

simply add ->values() it will reorder array keys

users = User::with('group')->values();

Upvotes: 2

Avnish Kumar
Avnish Kumar

Reputation: 1

This works for me. I hope this will help anyone.

return response(['STATUS'=>'true','message'=>'Your Message','response'=> 
array_values('clients' => array_filter($users, function ($r) {
   return $r['group']['name'] === 'client';
})),
'employes' => array_values(array_filter($users, function ($r) {
   return $r['group']['name'] !== 'client';
}))
)]);

If in response array you will get a result like an index key and you want the response in object array [{ ... }] then use array_values() will resolve your problem.

"clients": { "2": { "id": 3, "name": "Client 1", "email": "[email protected]", "email_verified_at": null, "created_at": null, "updated_at": null, "group_id": 4, "group": { "id": 4, "name": "client" } },

Upvotes: 0

Tim Lewis
Tim Lewis

Reputation: 29278

Internally array_filter() filters matching entries from the array, and returns them with their indices intact. This is very important, as it is the core reason you're getting an object and not an array in JavaScript.

In PHP, this is fine; arrays can start at 0, or another index, such as 2, and function as an array without issue. This is due to the existence of indexed (0-based) and associative (numeric/non-numeric key based) arrays.

In JavaScript, arrays cannot be "associative", i.e. they must start at 0. object classes on the other hand function similarly to associative arrays, but the key difference is that they aren't explicitly arrays.

Now that you know the why, the next question is "how do I fix this?" The simple method is to wrap array_filter() with a function that simply returns the values of the new array. This inherently will "re-index" the array with 0-based values, which when converted to JSON will result in correct arrays being returned:

$users = User::with('group')->get()->toArray();

$clients = array_filter($users, function($r){
  return $r['group']['name'] === 'client';
});

$groups = array_filter($users, function ($r) {
  return $r['group']['name'] !== 'client';
});

return response()->json([
  'clients' => array_values($clients),
  'groups' => array_values($groups)
]);

As a sidenote, Collection classes have similar logic, and I prefer to use Laravel's Collection class whenever possible:

$users = User::with('group')->get();

$clients = $users->filter(function($r){
  $r->group->name === 'client';
});

$groups = $users->filter(function($r){
  $r->group->name !== 'client';
});

return response()->json([
  'clients' => $clients->values(),
  'groups' => $groups->values()
]);

But again, that's my preference; either approach should work, so use what you're used to.

References:

PHP Array Methods:

https://www.php.net/manual/en/function.array-filter.php

https://www.php.net/manual/en/function.array-values.php

Laravel Collection Methods:

https://laravel.com/docs/5.8/collections#method-filter

https://laravel.com/docs/5.8/collections#method-values

Upvotes: 19

Related Questions