Skip to content

[5.1] Add missing *orFail methods in relationships #9143

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

Merged
merged 1 commit into from
Aug 9, 2015
Merged

[5.1] Add missing *orFail methods in relationships #9143

merged 1 commit into from
Aug 9, 2015

Conversation

lukasgeiter
Copy link
Contributor

Fixes #9138

This adds findOrFail to BelongsToMany and findOrFail/firstOrFail to HasManyThrough

@taylorotwell
Copy link
Member

I'll be honest I have a little bit of a hard time understanding the value of these methods. Why not just use the related model directly?

@lukasgeiter
Copy link
Contributor Author

Hmm that's true. However why does find() exist then?

@taylorotwell
Copy link
Member

Not sure. To me it makes more sense to just go straight to the model you want. No point in going through the relationship.

@lukasgeiter
Copy link
Contributor Author

I agree with you. Should we deprecate the two find methods then?

@stevebauman
Copy link
Contributor

@taylorotwell I disagree. Going through the relationship methods help a ton when creating / finding records for belongsToMany() relations and others since query fields are auto-filled and filter the results that are attached to that record.

For an example, I can make sure that a Book has an Author of a specific ID, by using:

$book = Book::find($id);

$author = $book->authors()->find($authorId);

If I was using the related model directly, I'd need to query through the pivot table manually, or by using a $book->whereHas('authors') or something more complicated to just find the a specific author of the book (and in this case I'm using the relation anyway).

Going through a relationship is also great because you have a single point where your foreign key is declared in your relationship, and if I ever need to change it, I literally just change the string in the belongsToMany() relation.

Querying relations is advertised in the documentation for versions 4.2, 5.0, 5.1, and Master:

http://laravel.com/docs/master/eloquent-relationships#querying-relations

I really think these methods should be added to keep consistency with the query builder API. I'd really like to use $book->authors()->findOrFail($id); so I can continue catching ModelNotFoundException's and return the appropriate response.

Please let me know your thoughts, thanks!

@jarektkaczyk
Copy link
Contributor

@lukasgeiter @taylorotwell This one should be merged.

Lack of find* in relations leads to inconsistency - along with #9647.

It's helpful to have the relation constraint applied automatically when calling $model->relation()->findOrFail() and, for BelongsToMany, it is required, since otherwise there's pivot data missing from the result.

@taylorotwell
Copy link
Member

I still don't understand why even go through the relationship at all if you
already know the primary key of the model you are trying to find. Going
through the relationship is just a waste of resources at that point.

On Saturday, July 18, 2015, Jarek Tkaczyk [email protected] wrote:

@lukasgeiter https://github.com/lukasgeiter @taylorotwell
https://github.com/taylorotwell This one should be merged.

Lack of find* in relations leads to inconsistency - along with #9647
#9647.

It's helpful to have the relation constraint applied automatically when
calling $model->relation()->findOrFail() and, for BelongsToMany, it is
required, since otherwise there's pivot data missing from the result.


Reply to this email directly or view it on GitHub
#9143 (comment).

@jarektkaczyk
Copy link
Contributor

@taylorotwell Because you may want to check whether, say, a user owns a resource:

$loggedInUser->resources()->findOrFail($id)

rather than

Resource->whereHas('user', function ($q) use ($loggedInUser) {
    $q->where('id', $loggedInUser->id);
})

@stevebauman
Copy link
Contributor

Also, without going through the relationship, we'd need to retrieve extra pivot data manually, would we not?

@bryannielsen
Copy link
Contributor

I've been using this the same way @jarektkaczyk mentioned, if there's a more appropriate alternative way to do this I'm happy to change my ways, but this seems to be a pretty quick and convenient way to ensure ownership on related models.

@stevebauman
Copy link
Contributor

Any update on this?

@taylorotwell taylorotwell reopened this Aug 6, 2015
@GrahamCampbell
Copy link
Member

This needs rebasing.

@lukasgeiter
Copy link
Contributor Author

This needs rebasing.

Done.

$result = $this->find($id, $columns);

if (is_array($id)) {
if (count($result) == count(array_unique($id))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

=== please

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unless our other code uses == for some strange reason

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@taylorotwell
Copy link
Member

OK I'm confused again. I already use findOrFail on a belongsToMany relation many times in my last production project without this pull request. What am I missing?

taylorotwell added a commit that referenced this pull request Aug 9, 2015
[5.1] Add missing *orFail methods in relationships
@taylorotwell taylorotwell merged commit f4f3c0d into laravel:5.1 Aug 9, 2015
@taylorotwell
Copy link
Member

Nevermind, read original bug description.

@lukasgeiter lukasgeiter deleted the find-or-fail branch August 9, 2015 13:32
sebdesign added a commit to sebdesign/framework that referenced this pull request Oct 16, 2019
…ptions

The regression in laravel#7048 and laravel#19019 is also observed in laravel#9143, because the `find`,  `findMany` and `findOrFail` methods are copied from the Eloquent Builder to the `BelongsToMany` and `HasManyThrough` relations.

For this reason, we need to convert the passed ids to an array before executing the queries.
sebdesign added a commit to sebdesign/framework that referenced this pull request Oct 16, 2019
The regression in laravel#7048 and laravel#19019 is also observed in laravel#9143, because the `find`,  `findMany` and `findOrFail` methods are copied from the Eloquent Builder to the `BelongsToMany` and `HasManyThrough` relations.

For this reason, we need to convert the passed ids to an array before executing the queries.
sebdesign added a commit to sebdesign/framework that referenced this pull request Oct 16, 2019
The regression in laravel#7048 and laravel#19019 is also observed in laravel#9143, because the `find`,  `findMany` and `findOrFail` methods are copied from the Eloquent Builder to the `BelongsToMany` and `HasManyThrough` relations.

For this reason, we need to convert the passed ids to an array before executing the queries.
sebdesign added a commit to sebdesign/framework that referenced this pull request Oct 16, 2019
…regression in laravel#7048 and laravel#19019 is also observed in laravel#9143, because the `find`,  `findMany` and `findOrFail` methods are copied from the Eloquent Builder to the `BelongsToMany` and `HasManyThrough` relations.For this reason, we need to convert the passed ids to an array before executing the queries.
taylorotwell pushed a commit that referenced this pull request Oct 18, 2019
* Ensure Builder::findOrFail with Arrayable throws ModelNotFoundException

I found a regression in #7048 and #19019, where the Eloquent Builder will not throw a `ModelNotFoundException` when an `Arrayable` is passed to `findOrFail`.

In this #7048, we are checking if the `$ids` is an array and we count the results against the number of ids.

But since #19019, the `find` method also accepts an `Arrayable` for the ids.

So if an `Arrayable` is passed, the check is skipped and the method returns the results.

To fix this, we are first checking if the `$ids` is an  `Arrayable` and we convert the ids to an array before checking the results.

* Ensure find* methods on relationships are accepting Arrayable idsThe regression in #7048 and #19019 is also observed in #9143, because the `find`,  `findMany` and `findOrFail` methods are copied from the Eloquent Builder to the `BelongsToMany` and `HasManyThrough` relations.For this reason, we need to convert the passed ids to an array before executing the queries.
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

Successfully merging this pull request may close these issues.

6 participants