skip to Main Content

I have two models Product and ProductType which both have a relationship with the Usp model. I have set up the models like this.

class Product extends Model
{
    use HasFactory, SoftDeletes;

    protected $guarded = [];

    public function usps(): MorphToMany
    {
        return $this->morphToMany(Usp::class, 'uspable');
    }
}


class ProductType extends Model
{
    use HasFactory, SoftDeletes;

    protected $guarded = [];

    public function usps(): MorphToMany
    {
        return $this->morphToMany(Usp::class, 'uspable');
    }
}

class Usp extends Model
{
    use HasFactory, SoftDeletes;

    protected $guarded = [];

    public function products(): MorphToMany
    {
        return $this->morphedByMany(Product::class, 'uspable');
    }

    public function productTypes(): MorphToMany
    {
        return $this->morphedByMany(ProductType::class, 'uspable');
    }
}

As far as I can see I have everything setup correctly but for some strange reason, when I call the property of the ProductType model it returns null (i.e. ProductType::find(1)->usps). But when I call the Query Builder method ProductType::find(1)->usps()->get() it gives me the correct results. For the Product model both ->usps and ->usps()->get() seem to work just fine. I have no idea what I am doing wrong here.

2

Answers


  1. Chosen as BEST ANSWER

    I fixed it by creating a trait called HasUsps and defining the builder method and custom attribute getter in it. and implemting the trait to every model that has a polymorphic relation with the Usp model. It still feels like a workaround for something that should just work, but I have no idea where the 'real' problem lays. So for now this is fine.

    trait HasUsps
    {
        public function usps(): MorphToMany
        {
            return $this->morphToMany(Usp::class, 'uspable');
        }
    
        public function getUspsAttribute(): Collection
        {
            return $this->usps()->get();
        }
    }
    

  2. It looks like you have set up your relationships correctly, but there might be an issue with eager loading. By default, relationships are not loaded until you explicitly request them. When you use ->usps, it may not be eager loading the relationship, resulting in null. However, when you use ->usps()->get(), you are explicitly triggering the loading of the relationship.

    To ensure that the relationship is loaded when you access it directly, you can use eager loading with the with method. Try modifying your code as follows:

    $productType = ProductType::with('usps')->find(1);
    $usps = $productType->usps; // This should now work as expected
    

    By using with(‘usps’), you are instructing Laravel to eager load the "usps" relationship along with the "ProductType" model, and then you can access it directly without having to call ->usps()->get().

    Alternatively, you can use the load method after retrieving the ProductType instance:

    $productType = ProductType::find(1);
    $productType->load('usps');
    $usps = $productType->usps; // This should now work as expected
    

    This should resolve the issue of returning null when accessing the usps relationship directly on the ProductType model.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search