11

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

4
  • 13
    It's an issue with the indices; JS will handle non-0-based arrays as objects. Your clients return has the first index of 2, not 0. I think you can just wrap array_filter with array_values to reset the indices. Commented Jan 10, 2020 at 16:09
  • 1
    "JS will handle non-0-based arrays as objects." Thank you for this information , its done Commented Jan 10, 2020 at 16:16
  • Exactly as he says, your array filter returns an array which start with the index 2, in JS you can't have that, so the json_encode turn it into an object Commented Jan 10, 2020 at 16:16
  • 1
    @TimLewis i suggest you put an answer with some documentation so he can close his question by selecting it as THE answer Commented Jan 10, 2020 at 17:03

3 Answers 3

19

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

Sign up to request clarification or add additional context in comments.

2 Comments

As a follow up, what causes the intermittent behavior? Just ran into this as well, and its interesting to me that sometimes the array will serialize as a JSON array and sometimes as a numerically indexed object.
It comes down to how indexed and associative arrays exist in PHP, but not in Javascript. If you send a PHP array [0, 1] to JS as JSON, you'll get an array, since in both languages, it's represented as [0, 1] (or [0 => 0, 1 => 1] in PHP vs {0: 0, 1: 1} in JS (a 0-based indexed array). If you send a PHP array [1 => 1, 2 => 2] to JS as JSON, you'll get an Object {1: 1, 2: 2}, since arrays can only be 0-based indexed in JS, but PHP allows arrays to have non-0 indices, like ['a' => 'a', 'b' => 'b'], etc. That would be {a: 'a', b: 'b'} as an object in JS.
2

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

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

Comments

0

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" } },

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.