Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add whenKeyExists method to ConditionallyLoadsAttributes #32662

Closed
emargareten opened this issue May 3, 2020 · 6 comments
Closed

Add whenKeyExists method to ConditionallyLoadsAttributes #32662

emargareten opened this issue May 3, 2020 · 6 comments

Comments

@emargareten
Copy link
Contributor

emargareten commented May 3, 2020

  • Laravel Version: 7.9.2
  • PHP Version: 7.4.5
  • Database Driver & Version: MySQL 8.0.17

Description:

Classes JsonResource and ResourceCollection won't check whether the resource has the specified fields. e.g. when query has the select() method or specified columns in get().

Specifying fields is a JSON:API standard.

Steps To Reproduce:

Route::get('/users', function () {
    $users= \App\User::query();

    if (request()->has('fields')) {
        $fields = explode(',', request()->fields);
        $users = $users->select($fields);
    }

    return \App\Http\Resources\User::collection($users->get());
});
//app\Http\Resources\User.php

class User extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'email_verified_at' => $this->email_verified_at,
            'created_at' => $this->created_at
        ];
    }
}

After running http://example.test/users?fields=id,email,email_verified_at

Expected output:

{
    "data": [
        {
            "id": 1,
            "email": "krajcik.cecil@example.org",
            "email_verified_at": "2020-05-03T18:43:26.000000Z"
        },
        {
            "id": 2,
            "email": "gkub@example.com",
            "email_verified_at": null
        },
        {
            "id": 3,
            "email": "kovacek.ansel@example.com",
            "email_verified_at": null
        }
    ]
}

Actual output:

{
    "data": [
        {
            "id": 1,
            "name": null,
            "email": "krajcik.cecil@example.org",
            "email_verified_at": "2020-05-03T18:43:26.000000Z",
            "created_at": null
        },
        {
            "id": 2,
            "name": null,
            "email": "gkub@example.com",
            "email_verified_at": null,
            "created_at": null
        },
        {
            "id": 3,
            "name": null,
            "email": "kovacek.ansel@example.com",
            "email_verified_at": null,
            "created_at": null
        }
    ]
}
@koenhoeijmakers
Copy link
Contributor

Could you explain why you would want a resource in your example? It doesn't seem to add anything except for a "map" that doesn't do anything and returning the select directly would make more sense.

That being said, you can already conditionally merge attributes (please scroll to "Merging Conditional Attributes")

@emargareten
Copy link
Contributor Author

@koenhoeijmakers the example I provided is just an example of the functionality I want, in my case I am returning a paginated resource and am also using other conditional methods in the resource.

I am not sure what you meant by your second comment, can you please provide an example what you mean?

@koenhoeijmakers
Copy link
Contributor

public function toArray($request)
{
    return [
        'id' => $this->id,
        $this->mergeWhen(/** Condition to check if the field is requested */, [
           'name' => $this->name
        ]),
    ];
}

@driesvints
Copy link
Member

driesvints commented May 4, 2020

This is the way it works. You're explicitly stating the fields that you should returned in the toArray.

@emargareten
Copy link
Contributor Author

@koenhoeijmakers you mean like this? 😏

public function toArray($request)
{
    return [
        'id' => $this->id,
        $this->mergeWhen(array_key_exists('name', $this->resource->toArray()), [
           'name' => $this->name
        ]),
        $this->mergeWhen(array_key_exists('email', $this->resource->toArray()), [
           'email' => $this->email
        ]),
        $this->mergeWhen(array_key_exists('email_verified_at', $this->resource->toArray()), [
           'email_verified_at' => $this->email_verified_at
        ]),
        $this->mergeWhen(array_key_exists('created_at', $this->resource->toArray()), [
           'created_at' => $this->created_at
        ]),
    ];
}

@emargareten
Copy link
Contributor Author

I don't see why this is different form whenloaded()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants