Linking a Model (ie. comment) to many other Models (ie. post, profile) - php

I am building a PHP application with Laravel where I have a Comment Model and many other models to which Comment can be attached to.
For example, a Profile can have many Comment but also a Post can have many Comment.
Should I split Comment in two models (ProfileComment and PostComment) or should I keep them together like this?
class Comment {
public function user()
{
return $this->hasOne('User');
}
public function profile()
{
return $this->belongsTo('Profile');
}
public function post()
{
return $this->belongsTo('Post');
}
}
If I keep them together, then on a database level how should I manage the comments table?
I was thinking about having the following columns:
integer: id - auto-incrementing id
integer: user_id - the user id
integer: foreign_id - profile/post id
varchar: type - which model? profile or post?
varchar: content - the actual comment
Is this the wrong approach?

if you want to use 1 table you will need to make Comment model morph.
if you don't want to use morph, make separated.
I think if you will use schema from your question, you will use morph.
I don't tkink where is need to make more tables, because all comments will have same structure (id, user_id (author), comment)
so in this case you will need just to make it morph (tagable).

Related

Laravel naming convention with similar Model names

This is a very basic question but trying to wrap my head around the preferred naming conventions for models/tables with similar names.
A model 'Task' can have many 'Comments' so the tables would be
- tasks
- comments (with a foreign key for task_id)
However, I have another model 'Post' which will also need a 'Comments' which is of course separate from the Comments for Tasks
In this scenario, does one generally go with
- Task & TaskComment (model) / tasks & task_comments (database table)
- Post & PostComment (model) / posts & post_comments (database table)
or some other convention?
If you use polymorphic relations you can even make a Comments has its own comments (like a reply system).
In the model you want to have comments you need to add a method like this:
public function comments() {
return $this->morphMany(Comment::class, 'commentable');
}
Then in your Comment model, you just add
public function commentable() {
return $this->morphTo();
}
Notice how important it is that your method name in Comment matches with the second parameter passed to the morpMany() function.
Last but not least, the model in which you morph to needs to have special fields in its schema:
You must place them at the end of the traditional schema structure:
// Your comment dedicated schema
$table->integer('commentable_id');
$table->string('commentable_type');
I really don't know if it is important but notice how the field prefix matches with the method name in which we are morphing.
What you want for this is polymorphism.
Follow the example on https://laravel.com/docs/5.4/eloquent-relationships#polymorphic-relations . It's really close to what you are trying to do, so hopefully it will be enough. If you get stuck let me know and i'll help you along

Laravel 5.3 files table related to multiple tables

I have one table named "files" which I would like to contain all my users files.
The files can be uploaded from different views and should be related to different tables: questions table, answers table, comments table, messages table etc... but still, all of them will be related also to users table, that way I will know who is the owner of the file.
Example: "user asking a question, and attaching a picture to help other users understand the question more easily."
The question values goes into 'questions_table', the file goes to 'files_table', and the user ID also goes to 'files_table'.
The question is! (sorry for the long introduction):
Should I use a pivot table? or just a double one-to-many relation from 1.'users_table' to 'files_table' & 2.from 'question_table' to 'files_table'?
I think this is the perfect use case for a Polymorphic Relationship.
Here is the structure of the tables:
users
- id
- name
questions
- id
- title
files
- id
- user_id
- filable_id
- filable_type
In the files table, you can see a filable_id field that is going to reference either a question id, answer id, comment id. And the filable_type that is going to tell the record which object is associated with this file.
class Question extends Model
{
/**
* Get all of the question's files.
*/
public function files()
{
return $this->morphMany('App\File', 'filable');
}
}
class File extends Model
{
/**
* Get all of the owning filable models.
*/
public function filable()
{
return $this->morphTo();
}
}
I highly encourage you to learn more about this type of relationship on the Laravel Documentation

Laravel, do I need multiple database tables for votes on different models

I have a Question model which has a one to many relationship with an Answer model.
Now I want to add upvote/downvote funcionality to both of these models, do I need to create two tables like VotesQuestions and VotesAnswers or can I somehow manage with one? If so, how?
You can use a polymorphic relationship. This is built into Laravel. Documentation is here. The code shown here is for Laravel 4, but the functionality is the same for Laravel 5.
Create a votes table, and make sure it has at least two specific fields: votable_id and votable_type. In a database migration, you would use the statement $table->morphs('votable');, and it will create the two fields. You can have as many other fields as you like, but to make sure the relationship works, those two fields are required.
Next, setup the Vote model with the votable relationship. The name of this relationship should match the base name of the fields you created:
class Vote extends Eloquent {
public function votable() {
return $this->morphTo();
}
}
With this setup, you can now associate votes to any model you want. Go ahead and add the votes relationship to the Question and Answer models:
class Question extends Eloquent {
public function votes() {
return $this->morphMany('Vote', 'votable');
}
}
class Answer extends Eloquent {
public function votes() {
return $this->morphMany('Vote', 'votable');
}
}
You can now access the votes for any question/answer through the relationship:
$q = Question::first();
$qVotes = $q->votes; // Collection of votes for the question.
$a = Answer::first();
$aVotes = $a->votes; // Collection of votes for the answer.
You can also get the related question/answer model through the vote, if you ever need to:
$v = Vote::first();
$vRelated = $v->votable; // Will automatically be a Question or Answer object, depending on what the vote was for.
I would do an table for the question and when you want to up/downvote the question there should be a count column for both, otherwise you want to log it that an user can only vote for it once, so you need another table for user_id, question_id and type (up/down).
ofc you can handle it with one table, but that is really worth because you save many things that are not necessary.
you can create a table with an internal id, 1,2,3,4 and 1 is always the question or 0 and 2-xx (1-xxx) are always the answers. so you can handle it with one table
You could create a generic Votes model/table which has a field called "model" and "model_id" and then use reflection to get the correct object.

two foreign keys, how to map with laravel eloquent

I have two tables in MySQL, where the first one is called users and the second one is called games. The table structure is as follows.
users
id (primary)
email
password
real_name
games
id (Primary)
user_one_id (foreign)
user_one_score
user_two_id (foreign)
user_two_score
My games table is holding two foreign relations to two users.
My question is how do I make the model relations for this table structure?? - According to the laravel documentation, I should make a function inside the model and bind it with its relations
for instance
public function users()
{
$this->belongsTo('game');
}
however I can't seem to find anything in the documentation telling me how to deal with two foreign keys. like in my table structure above.
I hope you can help me along the way here.
Thank you
A migration:
$table->integer('player1')->unsigned();
$table->foreign('player1')->references('id')->on('users')->onDelete('cascade');
$table->integer('player2')->unsigned();
$table->foreign('player2')->references('id')->on('users')->onDelete('cascade');
And a Model:
public function player1()
{
$this->belongsTo('Game', 'player1');
}
public function player2()
{
$this->belongsTo('Game', 'player2');
}
EDIT
changed 'game' to 'Game' as user deczo suggested.
Unfortunately the way you have this setup is not likely to work in the current context. You may have more luck with the belongsTo method, but again that only supports one relationship.
You could implement a user1() belongsTo, a user2() belongsTo and finally just declare a non eloquent function to return both (something like $users = array($this->user1(), $this->user2())

Laravel 4 Eloquent select

I have 3 tables
--- Posts (all the posts)
rows = id, title, content
--- Boards (all the boards)
rows = id, title
--- board_post (the link between boards and posts: many <-> many)
rows = board_id, post_id
2 Eloquent classes named board and post
now I would love to select all the posts from a board, based on board_post
I was thinking in the way of:
Posts::whereIn('id', $board->post_ids())
how would I be able to do this, that first off
that if I do Board::find(1)->post_ids I get all the post id's of that board
And then how wuld I be able to get all the post opbjects from that?
greetings Glenn
Why are you using a many-to-many relationship for Posts and Boards? It would most likely be a one-to-many relationship: A Board may have several posts, but a Post should only belong to one board (this would simplify your database structure to remove the board_post table).
You would then do:
Inside of Board class:
public function posts() {
return $this->hasMany('Post', 'board_id');
}
Then, Board::find(1)->posts would get you all of the posts for that board (use posts, not posts()).
To do it with your current database setup, use belongsToMany instead:
public function posts() {
return $this->belongsToMany('Post', 'board_post');
}
If you want to load a Board WITH all of it's posts (eager-loading) use this:
Board::with('posts')->find(1)
Otherwise, just to get the posts for a particular board, use:
Board::find(1)->posts
In Board model make sure you define belongsToMany relationship
public function posts()
{
return $this->belongsToMany('Post', 'board_post');
}
Now you should be able to do this:
Board::find({id})->posts
Forther reading material: http://laravel.com/docs/eloquent#relationships

Categories