Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

How to get the related model in controller relationship hooks? #110

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

Closed
Mina-R-Meshriky opened this issue Aug 5, 2021 · 13 comments
Closed
Labels
enhancement New feature or request
Milestone

Comments

@Mina-R-Meshriky
Copy link

 public function updatingStatus(User $user, UserRequest $request, StatusQuery $query) {
        $data = $request->validatedForRelation();
       
        dd($status = $query->model());
    }

I would expect $status to be the status model, but the variable contains the $user model instead
Also, if u can explain what is the difference between the $request and the $query

@lindyhopchris
Copy link
Contributor

Hmm yeah I can see how that's confusing. The model() method on the request returns the model that is subject of the request, which in this case is user model.

I can see how this is confusing though in relationship methods... given your example, I don't think the StatusQuery class should have a model() method. Looking through the docs, it's only mentioned in the request class documentation.

At this point in the request the status that is the other side of the relationship has not yet been loaded. So to get it, you'd need to do:

$status = Status::find($data['status']['id']);

Assuming that Status is a model.

The difference between request and query...

The request relates to the JSON:API resource that is in the request JSON. In this case, the request JSON is the content of the user's status relationship, so it is validated by the UserRequest.

The query relates to the JSON:API query parameters - which affect the JSON:API resources in the response that the server will send. In this case, a status resource is going to be in the response JSON, so the query parameters have to be parsed by the StatusQuery (i.e. it would be wrong to use UserQuery).

@lindyhopchris
Copy link
Contributor

I'm going to label this as a bug because it shows I need to remove the model() method from the query classes.

@lindyhopchris lindyhopchris added the bug Something isn't working label Aug 5, 2021
@lindyhopchris
Copy link
Contributor

I could also potentially add a related() method to the request class (or something similar) that gets the model(s) from the relationship (i.e. what you're trying to do). I'll take a look at adding that and what it should be called.

@lindyhopchris lindyhopchris changed the title How to get the model of the related in controller Actions\UpdateRelationship hook ? How to get the related model in controller relationship hooks? Aug 5, 2021
@Mina-R-Meshriky
Copy link
Author

thanks,
I did query the status from the Model directly Status::find() as u mentioned.

so, the query will only be used when sending the response back, it seems. However, I have a follow up question
when I tried to send the response back (bearing in mind that the status definition on the user resource is

$this->relation('status')->withoutLinks()

)
and was using the following :

RelationshipResponse::make($user,$fieldName,$result)->withQueryParameters($query)

it was not able to encode the response: error: the status relationship does not have a self link. of course it works after removing the withoutLinks()
but if I encode it with the following

DataResponse::make($user)->withQueryParameters($query);

it works fine regardless of the withoutLinks presence.

@lindyhopchris
Copy link
Contributor

The RelationshipResponse adds top-level relationship links to the response. If your relationship does not have links, it fails - which is the error you've used.

Not sure why you're doing withoutLinks() on the relationship when the links do exist?

@Mina-R-Meshriky
Copy link
Author

actually on the route definitions I didn't put them, I only need the update route

$server->resource('users')
            ->relationships(function (Relationships $r) {
                $r->hasOne('status')->only('update');
            })

and I show it directly on the relation as a meta:

public function relationships($request): iterable {
        return [
            $this->relation('status')->withoutLinks()->withMeta([
                'name' => $this->status->name,
            ]),
        ];
    }

@lindyhopchris
Copy link
Contributor

Hmmm yeah so the work-around for the moment will be to return a DataResponse. Unfortunately the underlying encoder does not allow nullable return types for the links method at the moment, which is why you're getting that error. I'll need to fix it.

@lindyhopchris
Copy link
Contributor

See #111 for the bug about the relationship links.

@lindyhopchris lindyhopchris added enhancement New feature or request and removed bug Something isn't working labels Jan 3, 2022
@lindyhopchris
Copy link
Contributor

lindyhopchris commented Jan 3, 2022

I've dealt with the relationship links problem as part of #111. So to summarise here what I need to do with the original problem reported by this issue:

  • Add a related() link to the request class that can be used to get the inverse related model(s). This can be added in 1.x.

Remove the model() method from the query class, as it shouldn't really exist there. That'll need to be done in the 2.x release as it's breaking (even though it was never documented that it could be called on the query class).

@lindyhopchris lindyhopchris modified the milestones: 1.x, 2.x Jan 3, 2022
@lindyhopchris
Copy link
Contributor

Turns out I can't remove the model() method from the query class, because it is used internally e.g. in the authorizeResource() method. This is correctly being used, so I'll just have to leave it in.

@lindyhopchris
Copy link
Contributor

OK, have fixed by making model() and modelOrFail() public on the resource request and protected on the query classes. That means that they can't be used externally on the query class, which makes sense here (and it was never documented as usable on the query classes).

@lindyhopchris
Copy link
Contributor

I still need to add the method for access the inverse model or models on a relationship - my current thinking is I'll make those available via a toOne() and a toMany() method on the resource request. But haven't had time to implement it for sure, so will hopefully release in 2.1.0 when I have a chance.

lindyhopchris added a commit that referenced this issue Feb 9, 2022
The model and modelOrFail methods were never meant to be used
publicly on the resource query class - and were not documented as
a result. To prevent them being used on this class (as it is
confusing as to which model is returned), these methods are now
public on the resource request, and protected on the query request.

See #110
@lindyhopchris
Copy link
Contributor

This will be in 2.1.0. The resource request class has a toOne() and toMany() method that can be used on a modify relationship request.

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

No branches or pull requests

2 participants