Support the ongoing development of Laravel.io →
Database Eloquent
Last updated 1 year ago.
0

I don't think you need to define so many relationships on one entity. Let me know if I am correct to assume the following:

  • One story has many comments
  • One user has many comments, each of which are related to a single story.
  • One comment has one rating ( and this rating is for the story. )
  • You would like to quickly access a rating made by a user for a specific post.

Also, I would like to know which db you are intending to use, and if you follow the repository pattern.

When I fully understand the problem, I will be happy to help make the models, repositories (if used), and the queries.

Last updated 1 year ago.
0

What you need is polymorphic relationship. I suggest something flexible, so you don't need to make changes to other models, only add relation definition there. Check this:

//Vote model

// relation
public function voteable()
{
    return $this->morphTo();
}

// setup some static methods on this model to easily fetch what you need, for example:
public static function up(Model $voteable)
{
	return (new static)->cast($voteable, 1);
}

public static function own(Model $voteable)
{
	return (new static)->cast($voteable, -1);
}

protected function cast(Model $voteable, $value = 1)
{
	if ( ! $voteable->exists) return false; // false as an example, throw meaningful exception here if you like

	$vote = new static;
	$vote->value = $value;
	return $vote->voteable()->associate($voteable)->save();
}

Now on every model you'd like to be voteable you need just the relation:

public function votes()
{
    return $this->morphMany('Vote', 'voteable');
}

With this setup you can do this:


$post = Post::find(15);

Vote::up($post); // true
Vote::down($post); // true

// on non-existing models
$comment = new Comment;

Vote::up($comment); // false
$comment->save();
Vote::up($comment); // true

// of course there are other useful methods to implement, for example
Vote::sum($post); // votes sum for given post
Vote::count($post); // votes count
Vote::countUps($post); // up votes count

Last thing would be accessor on the Vote model so you can restrict what values can be set:

public function setValueAttribute($value)
{
    $this->attributes['value'] = ($value == -1) ? -1 : 1;
}

And by the way, this very example I gave you, doesn't really require any changes at all on the voteable models, even the relationship there is not needed.

Last updated 1 year ago.
0

Thanks for the replies jarek and rowdy.

@jarek:

I don't think I need a polymorphic relationship. I'm not trying to attach a rating system to different types of models since I plan for only posts to have a rating. Your code did give me a better understanding of when a polymorphic relationship can be used and why though so thanks! I think your example could be really useful in an upcoming project.

Let me try to explain a little more clearly what I'm trying to accomplish and answer some of rowdy's questions.

My rating table has the columns: post_id, user_id, score.
My database is MySQL and I'm using Eloquent for queries.

#Page interactions:

  • Any user on the website can make a post.
  • Any user can rate the post (1 - 5 stars).
  • As of now, this rating is not related to a comment in any way.
  • A post can have many comments.
  • A user can have many comments for one post.

#What I would like for it to look like:

  • The page displays a star rating that is changeable for the current user under the post.
  • All comments from all users will display the rating that they gave the post.
  • This rating is unchangeable here even if it's the current user's comment.
  • Since a user can have multiple comments on a post, each comment will display the same single rating that the user gave the post.

Now that I think about it, the rating system I'm wanting is similar to the way that Amazon displays reviews. However, the user can have multiple comments instead of just 1 comment/review.

Last updated 1 year ago.
0

Let me know what you think of this and we can move ahead setting up the models:

Idea A:

User:

  • hasMany Post
  • hasMany Comment
  • belongsToMany Post (see pivot table)

Post:

  • belongsTo User
  • belongsToMany User (see pivot table)

Comment:

  • belongsTo User

pivot table post_user:

  • rating attribute

Naturally, there will be more models and relationships in your ecosystem. The pivot table allows us to join disparate types of relationships and store information on it. This will allow more flexibility than....

Idea B:

User:

  • hasMany Post
  • hasMany Comment
  • hasMany UserRating
  • ...

Post:

  • belongsTo User
  • hasMany UserRating
  • text body

UserRating:

  • belongsTo User
  • belongsTo Post
  • int rating

Comment:

  • belongsTo User
  • text comment
Last updated 1 year ago.
0

Sorry if I bump this after so long.

I really like jarektkaczyk's answer but I don't understand how he think the database migrations should work here. Any advice?

Are you suggesting a "votes" table with foreign keys for each resource or changing the single resource's tables to include a votes_up and a votes_down field?

Last updated 1 year ago.
0

Sign in to participate in this thread!

Eventy

Your banner here too?

dhatch6 dhatch6 Joined 9 Feb 2014

Moderators

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2024 Laravel.io - All rights reserved.