There are a few things i would change here. But let's tackle your issues from top to bottom:
In cases where you want to continue filtering (such as checking if an attribute is greater than 0), you should call the relationship as a method rather than a property.
Check this out:
$this->comments // returns a collection of comments. Think of Laravel calling the get() method behind the scenes
$this->comments() // returns an instance of the query builder and the relationship itself. You are then responsible for calling get(), but it's much more flexible
So changing this:
$this->comments->where('attr', '>' 0);
To this:
$this->comments()->where('attr', '>', 0)->get();
Will work as you're accessing an instance of the query builder, in other words, it hasn't finished querying until you say it has (by calling the get method).
If that's a little bit confusing, think of it like this:
$this->comments returns a collection of comments, and you can go on with your day such as looping through them
$this->comments() allows you to continue adding constraints to the query such as checking if a value is greater than X or whatever you wish
Okay now for your second question:
You'll generally keep it within the respective models. If it's a complicated query etc, you could extract it to another class.
Now, here's a tip you can use to improve your code:
- You could look into query scopes, this will often prove useful in a lot of situations where you need to filter results