booni3's avatar

Retrieving a loaded relationship but do not hit database if missing

I have the relationship:

    public function collectionAddress(): BelongsTo
    {
        return $this->belongsTo(OrderAddress::class, 'collection_address_id');
    }

In some parts of my app, the relationship does not exist but I want to load in an object to use within the request. So I can do:

$model->collectionAddress = new OrderAddress($data);

This all works fine until the relationship or key does not exist within a particular table. i.e. a ReturnDelivery model is another model that can be used in this logic and it does not have a collection_address_id column in the table.

The second option below does work while the top two do not. I assume the relation loaded call is for an eagerly loaded collection as opposed to a single belongsTo

Is there a better way to check if the belongs to relationship is loaded, without querying the DB?

// Fails as we try to hit the DB
if ($this->shippable->collectionAddress) {
    return OrderAddressData::fromOrderAddress($this->shippable->collectionAddress);
}

// Fails as we try to hit the DB
if ($this->shippable->relationLoaded('collectionAddress')) {
    return OrderAddressData::fromOrderAddress($this->shippable->collectionAddress);
}

// doesn't work, tries to hit DB
if ($collectionAddress = $this->shippable['collectionAddress'] ?? null) {
    return OrderAddressData::fromOrderAddress($collectionAddress);
}

// Works
if ($collectionAddress = $this->shippable->toArray()['collectionAddress'] ?? null) {
    return OrderAddressData::fromOrderAddress($collectionAddress);
}
0 likes
4 replies
ftiersch's avatar

relationLoaded shouldn't actually hit the DB. Are you sure about that one, that the DB Query comes from this part?

booni3's avatar

Relation loaded does not hit the DB, but it also always shows false even if I can access the loaded collection through $this->shippable->collectionAddress

booni3's avatar

So I think RelationLoaded is not working because I am setting object to the relationship on the fly. i.e.

$this->shippable = Shippable::query()->first();
dump($this->shippable-> collectionAddress); //null

$this->shippable->collectionAddress = new OrderAddress($data);
dump($this->shippable->collectionAddress); // OrderAddress Model
dump($this->shippable->relationLoaded('collectionAddress'); // false

$this->shippable->collectionAddress()->first(); // throws query exception due to table not containing column

To check if the collection address exists, I need to strip any Eloquent-Ness from the model (i.e. toArray()) and the check that. I just wonder if there is a better way?

dogakorkmaz35's avatar

@booni3 I know this is old, for anyone else tho, as far as I know Laravel only considers relation "loaded" if you hit the db and load the relationship to that instance, it doesn't track the actual class setters. So you must load the relationship via Eloquent API first to get true from relationLoaded check, not by native PHP.

Please or to participate in this conversation.