$user = User::find(1);
$user->posts()->orderBy("id","desc")->get(); // it will order it by id and get new collection of all items for this user
For example if I have
Model Post - belongsTo an User - hasMany Posts
Can I use any method to list values? Example: array [ 'belongsTo' => ['User'], 'hasMany' => ['Posts'], ]
$user = User::find(1);
$user->posts()->orderBy("id","desc")->get(); // it will order it by id and get new collection of all items for this user
@pisio FAR from the original question.
No,@rsferreira11, there are no way as of now.
I'm not getting the question. Are you trying to get all the relationships of a specific model, all relationships of all models, or something else?
There might be a way, if you use ReflectionClass ( http://php.net/manual/en/class.reflectionclass.php ) and it's method getMethods ( http://php.net/manual/en/reflectionclass.getmethods.php ).
Of course, you would have to filter out all the unneeded methods of the model yourself.
@mikemand thanks helped me a lot
@Francismori7, I've thought that there were a easy way to do it =/
@thomaskim I wanted a generic way to show all parents and children model from a model
@mikemand thanks, gonna try to think about something
@mikemand's solution cannot be used as the ReflectionClass cannot see what's inside the method - it will not detect "hasOne" or similar callbacks, you're better of using a regular expression on the file's content and filter it all out (complex IMHO).
You would have to list all the methods yourself in another method, not so bad if you ask me, because you always know what's in the code, nothing is "assumed", it's all there.
public function getRelationships() {
return [
'belongsTo' => [
'User',
],
'hasMany' => [
'Post',
],
];
}
I'm a little late, but if you're using PHP 7, and leveraging return types, you could do this:
$user = \App\User::class;
$reflector = new ReflectionClass($user);
$relations = [];
foreach ($reflector->getMethods() as $reflectionMethod) {
$returnType = $reflectionMethod->getReturnType();
if ($returnType) {
if (in_array(class_basename($returnType->getName()), ['HasOne', 'HasMany', 'BelongsTo', 'BelongsToMany', 'MorphToMany', 'MorphTo'])) {
$relations[] = $reflectionMethod;
}
}
}
dd($relations);
@sonoma Why are you responding to posts that have been inactive for years...
@MTHOMAS - My web search throw up this thread as the first result, I figured I'd provide a solution. Got a problem with that?
@derp - I came to the same conclusion. Including a return type on relationships seems to be the only conceivable way of doing this.
I've seen other solutions which involve actually invoking every method on a class and checking the return type - which is a truly terrible idea!
Thanks Derp for saving me time :)
Thanks @derp, thats actually quite a smart solution. I was using doc annotations for this so far, but realized this is a much nicer approach.
Thanks @derp , it worked. But i had to add the return type specification for my model relationships like this:
before (not working):
public function users()
{
return $this->belongsToMany('App\User');
}
after(working):
public function users(): BelongsToMany
{
return $this->belongsToMany('App\User');
}
@infoRR Make sure to add a return type to the methods. Then you can use a bit of reflection magic along with Collection.
Say you define the following method in a trait or an abstract base model
public static function definedRelations(): array
{
$reflector = new \ReflectionClass(get_called_class());
return collect($reflector->getMethods())
->filter(
fn($method) => !empty($method->getReturnType()) &&
str_contains(
$method->getReturnType(),
'Illuminate\Database\Eloquent\Relations'
)
)
->pluck('name')
->all();
}
Then you can get the defined method names as an array for eg: \App\User::definedRelations() will give the names of all relations defined for the App\User model
This is LEGEND! One of my client's apps does a lot of copying of models and one of the main ones has 17 relationships, and then all those have relationships, etc.
Thanks so much for this, very elegant.
@secondman Glad that it was helpful to you. I personally use this in a few projects. PHP Reflection is awesome. And Laravel Collection is way ahead of times & can't thank Taylor Otwell enough for this.
@neeravp I needed to get actual classes, so I added additional map to your great solution. Here it is in case someone needs to get all relationship classes:
public static function listAllRelatedClasses(): array
{
$reflector = new \ReflectionClass(get_called_class());
return collect($reflector->getMethods())
->filter(
fn ($method) => !empty($method->getReturnType()) &&
str_contains(
$method->getReturnType(),
'Illuminate\Database\Eloquent\Relations'
)
)
->map(
function ($method) {
return (with(new (get_called_class()))->{$method->name}()->getRelated())::class;
}
)
->unique()->values()->all();
}
Here is my method. It depends on the models properly including an Illuminate return type for the relationship method:
protected function hasRelationships($model): array
{
$reflectionClass = new ReflectionClass($model);
$reflectionMethods = $reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC);
$relationshipMethods = [];
foreach ($reflectionMethods as $reflectionMethod) {
$methodName = $reflectionMethod->getName();
$methodReturnType = $reflectionMethod->getReturnType();
if ($methodReturnType !== null) {
$methodReturnTypeString = $methodReturnType->getName();
$shortname = explode("\", $methodReturnTypeString);
$relationshipClass=strtolower(end($shortname));
$relationshipHelpers = [
'belongsto', 'hasone', 'hasmany', 'belongstomany',
'hasmanythrough', 'morphone', 'morphone', 'morphmany',
'morphto', 'morphtomany', 'through', 'embedsone',
'embedsmany', 'embedsmany', 'embedsmany'
];
if(in_array($relationshipClass, $relationshipHelpers))
$relationshipMethods[] = $methodName;
}
}
return $relationshipMethods;
}
Please or to participate in this conversation.