I’m working with a Laravel 11 project and need to link models together with a morph relationship. I’ve opted for a linking table called ModelHasModels
which defines:
source_id
– id of the source modelsource_type
– string for the source modeltarget_id
– id of the target modeltarget_type
– string for the target model
I have various models, a Site
model and Affiliate
model. affiliates can be linked to many sites, and sites would have affiliates.
I’ve defined my models, and inserted a row into the model_has_models
table, but when querying the Site
to get the affiliates I get nothing:
Querying:
Site::with('affiliates')->get(); <-- returns empty affiliates
Here’s the definition of each model:
Site
<?php
namespace AppModels;
use IlluminateDatabaseEloquentConcernsHasUlids;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentRelationsBelongsTo;
use IlluminateDatabaseEloquentRelationsMorphMany;
use IlluminateDatabaseEloquentRelationsMorphToMany;
class Site extends Model
{
use HasUlids, HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'description',
'url',
'is_enabled'
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'is_enabled' => 'boolean'
];
}
/**
* Define all of the related models for this model
*/
public function models(): MorphMany
{
return $this->morphMany(ModelHasModel::class, 'source');
}
/**
* Define all of the affiliates linked to this model
*/
public function affiliates(): MorphToMany
{
return $this->morphedByMany(Affiliate::class, 'source', 'model_has_models', 'source_id', 'target_id');
}
/**
* Link the model to the user
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
Affiliate
<?php
namespace AppModels;
use IlluminateDatabaseEloquentConcernsHasUlids;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentRelationsBelongsTo;
use IlluminateDatabaseEloquentRelationsMorphMany;
use IlluminateDatabaseEloquentRelationsMorphToMany;
class Affiliate extends Model
{
use HasUlids, HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'description',
'api_key',
'is_enabled'
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'is_enabled' => 'boolean'
];
}
/**
* Define all of the related models for this model
*/
public function models(): MorphMany
{
return $this->morphMany(ModelHasModel::class, 'target');
}
/**
* All of the sites that link to this model
*/
public function sites(): MorphToMany
{
return $this->morphedByMany(Site::class, 'target', 'model_has_models', 'target_id', 'source_id');
}
/**
* Link the model to the user
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}
ModelHasModel
<?php
namespace AppModels;
use IlluminateDatabaseEloquentConcernsHasUlids;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentRelationsMorphTo;
class ModelHasModel extends Model
{
use HasUlids, HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'source_id',
'source_type',
'target_id',
'target_type'
];
/**
* Define the model that this model is derived from
*/
public function source(): MorphTo
{
return $this->morphTo();
}
/**
* Define the model that this model must link to
*/
public function target(): MorphTo
{
return $this->morphTo();
}
}
And I’ve created an entry in the model_has_models
like the following:
INSERT INTO `model_has_models` (`id`, `source_type`, `source_id`, `target_type`, `target_id`, `created_at`, `updated_at`)
VALUES
('01HY083NK2THPY7A9M4SMKVVY3', 'App\Models\Site', '01hy07w8r8hc2v70h2zvbb6fz2', 'App\Models\Affiliate', '01hy07wp70a589gwpbqv0neh1a', '2024-05-16 08:26:10', '2024-05-16 08:26:12');
What am I missing?