Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Vlinderstichting's avatar

Eloquent question, get relationship from collection

Hi Everyone, I am only just getting into Laravel, and I am struggling with understanding (and implementing) eqloquent collections and I would really appreciate any help.

For example, if I have three classes: -project -task (A project can have many tasks, but a task can only belong to a single project) -action (same, a task can have many actions, but an action always belongs to a single task)

These should both be one-to-many relations. So in the project class I would use 'hasMany', and in the task class I would use 'belongsToMany'. Then, once I have an instance of a project, I can collect all the tasks like this: $project->tasks(); This gives me a collection of task objects. Can I than also get a collection of action objects like this? $project->tasks()->actions();

The first step I have working, but the second step, accessing the relation on a collection instead of an instance does not work. The obvious quick and dirty solution is to use pluck to get the id's out of the collection and use them to continue, but I was hoping for a more elegant solution. What is the appropriate way to get a collection of objects from another collection through an eloquent realtionship?

Also, it is not completely clear to me when to use '( )', is a relationship always a function or can it also be a property? Should it always be: $project->tasks()->actions(), or is it also possible to do: $project->tasks->actions(). And when should I use get(), I assume get executes the database query, but many queries are done without get().

This is an obvious question, so it will probably have been asked many times before. So sorry for the likely double post. I did look, but I suspect I looked with the wrong vocabulary. I would really appreciate your help!

0 likes
3 replies
bobbybouwmann's avatar

Ok, so lets first fix your relationship. If you have a one-to-many relationship you have a hasMany and a belongsTo relationship.

// App/Project.php

public function tasks()
{
    return $this->hasMany(Task::class);
}

// App/Task.php

public function project()
{
    return $this->belongsTo(Project::class);
}

public function actions()
{
    return $this->hasMany(Action::class);
}

// App/Action.php

public function task()
{
    return $this->belongs(Task::class);
}

With these relationships, you can already do a lot ;)

Let's discuss the (). When you do $project->tasks it will perform a query on the background and fetch the tasks for you based on the project. If the call was already done before, it will simply return the results from the previous relationship. So only if tasks is empty, it will try to fetch it again.

However, if you use tasks() it will return a query builder object. So it doesn't return a collection of tasks, but ir returns a query builder object that has the query available to fetch the tasks. With the query object, you can add more where statements for example.

The reason that $project->tasks()->actions() is not working is because tasks returns a query builder object and not a collection. In general, this won't' work because an action belongs to a single task, however $project->tasks returns a collection of actions.

If you want to fetch all the data you can do something like his

$project = Project::with('tasks.actions')->find(1);

Then in your view or controller, you can loop over the data

@foreach ($project->tasks as $task) 

    {{ $task->name }}

    @foreach ($task->actions as $action)

        {{ $action->name }}

    @endforeach

@endforeach

Let me know if you have more specific questions :)

1 like
Vlinderstichting's avatar

Thanks a lot, that makes it a lot clearer. I understand the difference between the query builder object and a collection much better now. And I suppose the ->get() converts the query builder object into a collection?

Could you maybe clarify this bit slightly more: 'In general, this won't' work because an action belongs to a single task, however $project->tasks returns a collection of actions.' Do you mean that because it is a one-to-many relationship the framework expects a single object instead of a collection, or is there another reason it will not work with a one-to-many relationship? So hypothetically, if I were to declare it is a many-to-many relationship this: $project->tasks->actions would work? Or would I still have to loop through everything, Even if I want, for example, a count of the number of actions in a project. I understand why declaring a many-to-many relationship when it is a one-to-many is bad practice and I am not going to do that, but I am just trying to understand the framework.

Thanks again, you already helped me a lot.

Please or to participate in this conversation.