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 :)