Load all relationships for a model Load all relationships for a model laravel laravel

Load all relationships for a model


No it's not, at least not without some additional work, because your model doesn't know which relations it supports until they are actually loaded.

I had this problem in one of my own Laravel packages. There is no way to get a list of the relations of a model with Laravel. It's pretty obvious though if you look at how they are defined. Simple functions which return a Relation object. You can't even get the return type of a function with php's reflection classes, so there is no way to distinguish between a relation function and any other function.

What you can do to make it easier is defining a function that adds all the relationships.To do this you can use eloquents query scopes (Thanks to Jarek Tkaczyk for mentioning it in the comments).

public function scopeWithAll($query) {    $query->with('foo', 'bar', 'baz');}

Using scopes instead of static functions allows you to not only use your function directly on the model but for example also when chaining query builder methods like where in any order:

Model::where('something', 'Lorem ipsum dolor')->withAll()->where('somethingelse', '>', 10)->get();

Alternatives to get supported relations

Although Laravel does not support something like that out of the box you can allways add it yourself.

Annotations

I used annotations to determine if a function is a relation or not in my package mentioned above. Annotations are not officially part of php but a lot of people use doc blocks to simulate them.Laravel 5 is going to use annotations in its route definitions too so I figuered it not to be bad practice in this case. The advantage is, that you don't need to maintain a seperate list of supported relations.

Add an annotation to each of your relations:

/** * @Relation */public function foo() {    return $this->belongsTo('Foo');}

And write a function that parses the doc blocks of all methods in the model and returns the name. You can do this in a model or in a parent class:

public static function getSupportedRelations() {    $relations = [];    $reflextionClass = new ReflectionClass(get_called_class());    foreach($reflextionClass->getMethods() as $method)     {        $doc = $method->getDocComment();        if($doc && strpos($doc, '@Relation') !== false)         {            $relations[] = $method->getName();        }    }    return $relations;}

And then just use them in your withAll function:

public function scopeWithAll($query) {    $query->with($this->getSupportedRelations());}

Some like annotations in php and some don't. I like it for this simple use case.

Array of supported relations

You can also maintain an array of all the supported relations. This however needs you to always sync it with the available relations which, especially if there are multiple developers involved, is not allways that easy.

protected $supportedRelations = ['foo','bar', 'baz'];

And then just use them in your withAll function:

public function scopeWithAll($query) {    return $query->with($this->supportedRelations);}

You can of course also override with like lukasgeiter mentioned in his answer. This seems cleaner than using withAll. If you use annotations or a config array however is a matter of opinion.


There's no way to know what all the relations are without specifying them yourself. How the other answers posted are good, but I wanted to add a few things.

Base Model

I kind of have the feeling that you want to do this in multiple models, so at first I'd create a BaseModel if you haven't already.

class BaseModel extends Eloquent {    public $allRelations = array();}

"Config" array

Instead of hard coding the relationships into a method I suggest you use a member variable. As you can see above I already added $allRelations. Be aware that you can't name it $relations since Laravel already uses that internally.

Override with()

Since you wanted with(*) you can do that too. Add this to the BaseModel

public static function with($relations){    $instance = new static;    if($relations == '*'){        $relations = $instance->allRelations;    }    else if(is_string($relations)){        $relations = func_get_args();    }    return $instance->newQuery()->with($relations);}

(By the way, some parts of this function come from the original Model class)

Usage

class MyModel extends BaseModel {    public $allRelations = array('foo', 'bar');}MyModel::with('*')->get();


I wouldn't use static methods like suggested since... it's Eloquent ;) Just leverage what it already offers - a scope.

Of course it won't do it for you (the main question), however this is definitely the way to go:

// SomeModelpublic function scopeWithAll($query){    $query->with([ ... all relations here ... ]);     // or store them in protected variable - whatever you prefer    // the latter would be the way if you want to have the method    // in your BaseModel. Then simply define it as [] there and use:    // $query->with($this->allRelations); }

This way you're free to use this as you like:

// static-likeSomeModel::withAll()->get();// dynamically on the eloquent BuilderSomeModel::query()->withAll()->get();SomeModel::where('something', 'some value')->withAll()->get();

Also, in fact you can let Eloquent do it for you, just like Doctrine does - using doctrine/annotations and DocBlocks. You could do something like this:

// SomeModel/** * @Eloquent\Relation */public function someRelation(){  return $this->hasMany(..);}

It's a bit too long story to include it here, so learn how it works: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html