I need help with my laravel 11 project. I have a table which acts as a morph table which would work with morphedByMany. But for this particular model I only need to retrieve one entry. My tables are: Site, Domain and then the intermidiate table: Siteable. Siteable defines the site_id, siteable_type and siteable_id columns. The following relationship defined at the Site model would retrieve all of my domains for the site, but a site should only have one domain:
public function domains(): MorphToMany
{
return $this->morphedByMany(Domain::class, 'siteable');
}
I tried to change this to:
public function domain(): HasOneThrough
{
return $this->hasOneThrough(Domain::class, Siteable::class, 'siteable_id', 'id', 'id');
}
Basically, a Site
can have one domain, and as many of other models as it chooses, thus the following schema:
Schema::create('siteables', function (Blueprint $table) {
$table->ulid('id')->primary()->index();
$table->foreignUlid('site_id')->index()->constrained()->onUpdate('cascade')->onDelete('cascade');
$table->ulidMorphs('siteable');
$table->timestamps();
// define indexes for performance
$table->index(['site_id', 'siteable_type', 'siteable_id']);
});
What am i missing to retrieve one record?
UPDATE
SQL error I get after attempting morphOne
:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'domains.siteable_id' in 'field list' (Connection: mysql, SQL: select `domains`.* from `domains` inner join (select MAX(`domains`.`id`) as `id_aggregate`, `domains`.`siteable_id`, `domains`.`siteable_type` from `domains` where `domains`.`siteable_id` in (01hy0zwf63wpt6t8c64q1388q9, 01hy0zxw8yb1nncrw7ytg50wwr) and `domains`.`siteable_type` = AppModelsSite group by `domains`.`siteable_id`, `domains`.`siteable_type`) as `latestOfMany` on `latestOfMany`.`id_aggregate` = `domains`.`id` and `latestOfMany`.`siteable_type` = `domains`.`siteable_type` and `latestOfMany`.`siteable_id` = `domains`.`siteable_id`).
2
Answers
You could utilise a query scope for this that simply gets the latest domain id as a global select then eager loads the Domain using that id.
This is untested and simply just a PoC but from what I can guage from your OP, it should be enough on its own. Usage:
If you want to fetch only one domain, you can use the hasOne relationship with a condition to ensure it only retrieves a
Domain
model. ThehasOneThrough
method you tried is not suitable for polymorphic relationships. Instead, you should define a custom query in your relationship.Define a custom
hasOne
relationship with a condition to only get the domainVerify
Domain
andSiteable
models are set up to handle the polymorphic relationship properly:now fetching the data,