Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel - Eloquent - Dynamically defined relationship

Is it possible to set a model's relationship dynamically? For example, I have model Page, and I want to add relationship banners() to it without actually changing its file? So does something like this exist:

Page::createRelationship('banners', function(){
    $this->hasMany('banners');
});

Or something similar? As they are fetched using the magic methods anyway, perhaps I can add the relationship dynamically?

Thanks!

like image 493
Giedrius Avatar asked Sep 12 '16 10:09

Giedrius


People also ask

What is the use of whereHas in Laravel?

whereHas() works basically the same as has() but allows you to specify additional filters for the related model to check.

What is BelongsTo in Laravel?

BelongsTo is a inverse of HasOne. We can define the inverse of a hasOne relationship using the belongsTo method. Take simple example with User and Phone models. I'm giving hasOne relation from User to Phone. class User extends Model { /** * Get the phone record associated with the user.

Is Laravel eloquent ORM?

Laravel includes Eloquent, an object-relational mapper (ORM) that makes it enjoyable to interact with your database.


2 Answers

I've added a package for this i-rocky/eloquent-dynamic-relation

In case anyone still looking for a solution , here is one. If you think it's a bad idea, let me know.

trait HasDynamicRelation
{
    /**
     * Store the relations
     *
     * @var array
     */
    private static $dynamic_relations = [];

    /**
     * Add a new relation
     *
     * @param $name
     * @param $closure
     */
    public static function addDynamicRelation($name, $closure)
    {
        static::$dynamic_relations[$name] = $closure;
    }

    /**
     * Determine if a relation exists in dynamic relationships list
     *
     * @param $name
     *
     * @return bool
     */
    public static function hasDynamicRelation($name)
    {
        return array_key_exists($name, static::$dynamic_relations);
    }

    /**
     * If the key exists in relations then
     * return call to relation or else
     * return the call to the parent
     *
     * @param $name
     *
     * @return mixed
     */
    public function __get($name)
    {
        if (static::hasDynamicRelation($name)) {
            // check the cache first
            if ($this->relationLoaded($name)) {
                return $this->relations[$name];
            }

            // load the relationship
            return $this->getRelationshipFromMethod($name);
        }

        return parent::__get($name);
    }

    /**
     * If the method exists in relations then
     * return the relation or else
     * return the call to the parent
     *
     * @param $name
     * @param $arguments
     *
     * @return mixed
     */
    public function __call($name, $arguments)
    {
        if (static::hasDynamicRelation($name)) {
            return call_user_func(static::$dynamic_relations[$name], $this);
        }

        return parent::__call($name, $arguments);
    }
}

Add this trait in your model as following

class MyModel extends Model {
    use HasDynamicRelation;
}

Now you can use the following method to add new relationships

MyModel::addDynamicRelation('some_relation', function(MyModel $model) {
    return $model->hasMany(SomeRelatedModel::class);
});
like image 133
Rocky Avatar answered Oct 05 '22 22:10

Rocky


As of laravel 7, dynamic relationship is officially supported. You can use the Model::resolveRelationUsing() method.

https://laravel.com/docs/7.x/eloquent-relationships#dynamic-relationships

like image 44
Alika Matthew Avatar answered Oct 05 '22 22:10

Alika Matthew