carstenjaksch's avatar

Custom collection not working as expected

Hey,

I have a Site model that uses newCollection(). When I try lazy eager loading, I get an error:

$page->load('sites')
// Argument #2 ($results) must be of type Illuminate\Database\Eloquent\Collection, App\Support\SiteCollection given

The Laravel docs tell me that all queries that return a collection should return the new collection when using newCollection(). What do I miss?

Model:

use Illuminate\Database\Eloquent\Model;
use App\Support\SiteCollection;

class Site extends Model
{
    /**
     * Create a new Eloquent Collection instance.
     *
     * @param  array<int, \Illuminate\Database\Eloquent\Model>  $models
     * @return SiteCollection<int, \Illuminate\Database\Eloquent\Model>
     */
    public function newCollection(array $models = []): SiteCollection
    {
        return new SiteCollection($models);
    }
}

SiteCollection:

namespace App\Support;

use Illuminate\Support\Collection;

class SiteCollection extends Collection
{
    // ...
}
0 likes
2 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

The issue you're encountering is due to the type hinting in the load method, which expects an instance of Illuminate\Database\Eloquent\Collection. However, your custom SiteCollection extends Illuminate\Support\Collection, not Illuminate\Database\Eloquent\Collection.

To resolve this, you should extend Illuminate\Database\Eloquent\Collection instead of Illuminate\Support\Collection in your SiteCollection class. Here's how you can modify your SiteCollection class:

namespace App\Support;

use Illuminate\Database\Eloquent\Collection;

class SiteCollection extends Collection
{
    // ...
}

By extending Illuminate\Database\Eloquent\Collection, your custom collection will be compatible with Eloquent's expectations, and the load method should work as intended.

Here's the updated SiteCollection class:

namespace App\Support;

use Illuminate\Database\Eloquent\Collection;

class SiteCollection extends Collection
{
    // Custom methods and properties for your SiteCollection
}

With this change, your Site model's newCollection method will return an instance of SiteCollection that is compatible with Eloquent's lazy eager loading.

Your Site model remains the same:

use Illuminate\Database\Eloquent\Model;
use App\Support\SiteCollection;

class Site extends Model
{
    /**
     * Create a new Eloquent Collection instance.
     *
     * @param  array<int, \Illuminate\Database\Eloquent\Model>  $models
     * @return SiteCollection<int, \Illuminate\Database\Eloquent\Model>
     */
    public function newCollection(array $models = []): SiteCollection
    {
        return new SiteCollection($models);
    }
}

This should resolve the error you're encountering when trying to lazy eager load the sites relationship.

1 like
carstenjaksch's avatar

@LaryAI LOL, somehow I got an error that I need to extend the Support variant of Collection. Now I tried that again with the Eloquent variant and it is working fine. Must have been fat fingered hardly there. Thanks, Lary!

Please or to participate in this conversation.