2

I have an object in Illuminate that has a relation that can return different objets depending on a property of the main object

public function relation(){
    switch($this->type){
        case "type_1":
            return $this->belongsTo('\Models\Type1', 'idElement');
            break;
        case "type_2":
            return $this->belongsTo('\Models\Type2', 'idElement');
            break;
        default:
            return null;
    }
}

This produces an error of "Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation" when the "default" section is executed.

Also I can't instantiate a new Illuminate\Database\Eloquent\Relations\Relation() as it is an abstract class.

I could create an empty table and return a relation to this empty table that will always return an empty value, but this is not a solution.

How can I return an empty relation in the default option?

UPDATE:

I have changed it to use polymorphic relations, but now the problem is: how to set a polymorphic relation as an optional relation?

Relation::morphMap([
    'type_1' => \App\Models\Type1::class,
    'type_2' => \App\Models\Type2::class
]);

....

public function relation(){
    return $this->morphTo(null, 'type', 'idElement');
}
David Rojo
  • 2,337
  • 1
  • 22
  • 44
  • Hello Hilmi, I am not using Laravel, only the Illuminate component in an Slim framwork project. – David Rojo Sep 21 '16 at 14:43
  • 1
    That kind of relations will break the eager loading functionality of Eloquent. I think you should determine the type and load different relations from model instead of this single model. I am not sure (I don't know your case) but polymorphic relations might work as well. – Hilmi Erdem KEREN Sep 21 '16 at 14:47
  • It seems that polymorphic relations is what I am looking for, I am going to give it a try. – David Rojo Sep 21 '16 at 15:01
  • Well, I have been able to succecss using polymorphic relations but I am facing the same problem when a relation is optional: https://github.com/laravel/framework/issues/1450 – David Rojo Sep 21 '16 at 15:18

2 Answers2

0

I suggest creating a stub relationship class and use it when you need to return always empty (or fixed) collection.

<?php

namespace App;

use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\Collection;

/**
 * Stub relationship
 */
class EmptyRelation extends Relation
{
    public function __construct() {}
    public function addConstraints() {}
    public function addEagerConstraints(array $models) {}
    public function initRelation(array $models, $relation) {}

    public function match(array $models, Collection $results, $relation)
    {
        return $models;
    }

    public function getResults()
    {
        return new Collection();
    }
}

Then in your default section you do:

return new \App\EmptyRelation();
Gleb Varenov
  • 2,795
  • 3
  • 18
  • 18
-1

Well..this is probably not the best option but works

public function relation(){
    switch($this->type){
        case "type_1":
            return $this->belongsTo('\Models\Type1', 'idType1');
            break;
        case "type_2":
            return $this->belongsTo('\Models\Type2', 'idType2');
            break;
        default:
            return $this->hasOne('\Models\ThisModel', 'id','id')->where('id','<',0 );//Assuming you have an id autoincrement field that starts in 1  in your table, 
    }
}

This will return an empty collection, I'm not sure if this is what you are looking for

WindSaber
  • 323
  • 1
  • 3
  • 15