Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 298
Alexis Gatuingt Avatar asked Mar 03 '23 22:03

Alexis Gatuingt


1 Answers

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

like image 58
Tim Lewis Avatar answered Mar 05 '23 16:03

Tim Lewis