1
votes

My website has comments. These comments can have "votes", upvotes and downvotes.

I have a Comment Model and a CommentVote model.

In my comment model I have a functions that returns the votes:

public function votes() {
    return $this->hasMany('App\CommentVote', 'comment_id');
}

public function upvotes() {
    return $this->hasMany('App\CommentVote', 'comment_id')->where('vote', 1);
}   

public function downvotes() {
    return $this->hasMany('App\CommentVote', 'comment_id')->where('vote', -1);
}       

Notice that upvotes are stored in the database in a tinyInt as 1 and downvotes are stored as -1

In my CommentVote model I have the belongsTo relationship:

public function comment() {
    return $this->belongsTo('App\Comment');
}   

Now I want to have a function that calculates the total "score" of the comment. Total upvotes minus total downvotes.

I try to make a function that counts all the upvotes - all the downvotes.

public function score() {
    return $this->upvotes()->count() - $this->downvotes()->count();
}   

This returns the error:

App\Comment::score must return a relationship instance.

In fact using the count() anywhere will return this error, despite it working fine in my other Models.

Doing something simple like:

public function voteCount() {
    return $this->hasMany('App\CommentVote', 'comment_id')->count();
    or even
    return $this->votes()->count();
}   

will return the error:

App\Comment::voteCount must return a relationship instance.

Why is this happening?

EDIT:

Here is the controller, as per requests in the comments:

public function getSubmission($subchan, $id, $URLtitle) {

    $submission = Submission::where('id', $id)->first();
    $comments = Comment::where('submission_id', $submission->id)->where('parent_id', NULL)->orderBy('created_at', 'desc')->get();

    $comments = $comments->sortByDesc(function($comment){
        return count($comment['upvotes']) - count($comment['downvotes']);
    });     

    if (!$submission) {
        return redirect()->route('home')->with('error', 'Submission not found.' );
    }       

    return view('submissions.submission')
    ->with('submission', $submission)
    ->with('navSubchan', $submission->getSubchan->name)
    ->with('submissionPage', 1)
    ->with('comments', $comments)
    ;

}   
1
Where and how are you using public function score() and public function voteCount()?Tim Lewis
the comment modelFelix Maxime
I mean what does the code that calls those functions look like? Comment::with(["score"])? $score = $comment->score? Etc etcTim Lewis
@FelixMaxime That answers the "where". What about the how?ceejayoz

1 Answers

3
votes

I suspect you're doing $model->score, which is going to look for a function called score(), but in a specific manner that expects that function to return a HasMany, HasOne, BelongsTo etc. style relationship object.

Consider an accessor function instead.

public function getScoreAttribute() {
    return $this->upvotes()->count() - $this->downvotes()->count();
}

allows you to do $model->score successfully.