Reputation: 1684
Is it possible to create a quick method to return the first model from a one-to-many relationship? Here is my code, from the model file:
public function books() {
return $this->hasMany('App\Models\Book');
}
public function first_book() {
return $this->book()->first();
}
This is the error I'm getting:
Call to undefined method Illuminate\Database\Query\Builder::addEagerConstraints()
The reason I want to use this is so that I can collect the first record using the with() method, for example:
$authors = Author::with('first_book')->select('*');
I'm using these records with Datatables.
Upvotes: 31
Views: 59645
Reputation: 133
I know this is an old post but in case someone is looking for a quicker way to do this without modifying your Model class. You can grab the first record of a relationship directly from the Model hasMany relationship.
I have used this and it works well. For example if you have a hasMany relationship between Library
and Books
model;
$first_book = $library->books->first();
or to get the last book;
$last_book = $library->books->last();
Upvotes: 0
Reputation: 531
With laravel 9.x you can use the latestOfMany
or oldestOfMany
like so;
// your relationship
public function books() {
return $this->hasMany('App\Models\Book');
}
// Get the first inserted child model
public function first_book() {
return $this->hasOne('App\Models\Book')->oldestOfMany();
}
// Get the last inserted child model
public function last_book() {
return $this->hasOne('App\Models\Book')->latestOfMany();
}
BONUS: If you are on php 5.5 or later, you can get the fully qualified class name by using the scope resolution operator, looks clean, ie;
// your relationship
public function books() {
return $this->hasMany(Book::class);
}
// Get the first inserted child model
public function first_book() {
return $this->hasOne(Book::class)->oldestOfMany();
}
// Get the last inserted child model
public function last_book() {
return $this->hasOne(Book::class)->latestOfMany();
}
Link to the Laravel documentation
Upvotes: 9
Reputation: 1148
I might be late but for your future use and for other who want the same output try this one -
// If you need the last one
public function books() {
return $this->hasOne('App\Models\Book')->latest();
}
// If you need the first entry -
public function books() {
return $this->hasOne('App\Models\Book')->oldest();
}
Upvotes: 57
Reputation: 1478
A one-to-one relationship is a very basic relation. For example
public function books()
{
return $this->hasOne('App\Models\Book');
}
Upvotes: 2
Reputation: 33186
A relation that can be eager loaded has to return a query. The first()
function returns an eloquent object.
The solution is to limit the number of results of this query like so:
public function first_book() {
return $this->books()->take(1);
}
$author->first_book
will still be a collection, but it will only contain the first related book in your database.
Upvotes: 15
Reputation: 9749
To use with()
your method has to return a collection from a relation method, because your relation is hasMany. So what you could do is:
public function books() {
return $this->hasMany('App\Models\Book');
}
public function first_book() {
return $this->hasMany('App\Models\Book')->limit(1);
}
Which would return a collection with your first item, so you' still have to call first()
:
$authors = Author::with('first_book')->select('*');
$authors->first_book->first();
Upvotes: 7