Summary: I need to know how to retrieve models but have them sorted in a specific way based on related models.
I've got four related tables, three of which are used in a polymorphic relationship. Here's a simplified version of them:
checkcalls
id - integer
loadid - integer
type - string
stopid - integer
pickups
id - integer
loadid - integer
checkedin - boolean
loaded - boolean
pickuporder - integer
drops
id - integer
loadid - integer
checkedin - boolean
delivered - boolean
droporder - integer
checkcallstatus
id - integer
status - string
checkorder - integer
I've created a polymorphic relationship whereby the Checkcall is a child of either Pickup or Drop based on its type column. The stopid column is id of that Pickup or Drop. In addition, I've added a couple of accessors to unify those two parent models further:
class Checkcall extends Model
{
public function stop(): MorphTo
{
return $this->morphTo(__FUNCTION__, "type", "stopid");
}
}
class Pickup extends Model
{
protected $appends = ["completed", "order"];
public function getCompletedAttribute()
{
return $this->attributes["loaded"];
}
public function getOrderAttribute()
{
return $this->attributes["pickuporder"];
}
public function checkcalls(): MorphMany
{
return $this->morphMany(Checkcall::class, "stop");
}
}
class Drop extends Model
{
protected $appends = ["completed", "order"];
public function getCompletedAttribute()
{
return $this->attributes["delivered"];
}
public function getOrderAttribute()
{
return $this->attributes["droporder"];
}
public function checkcalls(): MorphMany
{
return $this->morphMany(Checkcall::class, "stop");
}
}
And, since checkcall's type column only consists of short codes rather than fully-qualified model names, I have to enforce a morph map in App\Providers\AppServiceProvider.php to make this polymorphic relationship work:
public function boot(): void
{
Relation::enforceMorphMap([
'PC' => 'App\API\v2\Models\Pickup',
'LD' => 'App\API\v2\Models\Pickup',
'DC' => 'App\API\v2\Models\Drop',
'DE' => 'App\API\v2\Models\Drop',
]);
}
Those are four possible values for Checkcall's type column and the only ones we're concerned with here.
Now, I aim to retrieve a bunch of checkcalls for a given loadid, but they need to be in a specific order. There can be multiple pickups and multiple drops, but they should be in PC -> LD -> DC -> DE order, with all the pickup checkcalls first, then all the drop checkcalls second, and in order of the stops' pickuporder/droporder columns (which can be retrieved through their new order accessor).
I've got a start on it here, but the sortBy() just doesn't work as expected:
$checkcalls = Checkcall::with("stop")
->with("checkcallStatus")
->where("loadid", $loadID)
// ->orderBy("checkcallStatus.checkorder", "asc")
->get()
->sortBy([
function ($checkCall) {
return 'App\API\v2\Models\Pickup' === Relation::getMorphedModel($checkCall->stop->getMorphClass()) ? 0 : 1;
},
["stop.order", "asc"],
["checkcallStatus.checkorder", "asc"],
]);
I thought this would separate all the Pickup checkcalls from the Drop checkcalls, listing the Pickups first; then it would put all the pickups & drops in order (based on that new order accessor); and finally use the linked table checkcallstatus (which kind of works like an ENUM) to put the checkcalls within each stop in order.
But that's not what happens.
The expected order of Checkcalls for a load that has 2 Pickups and 2 Drops should be as follows:
0 => Pickup #1, PC
1 => Pickup #1, LD
2 => Pickup #2, PC
3 => Pickup #2, LD
4 => Drop #1, DC
5 => Drop #1, DE
6 => Drop #2, DC
7 => Drop #2, DE
I do not know how to write an orderBy() or sortBy() in order to get this output.