Table design for a forum - php

To be clear, I'm not looking for someone to design an entire forum here, rather, I need some help determining how to relate a couple of tables, and whether or not these tables need to exist in the first place.
Basics of a forum
Topics
topic_id // Unique topic ID, AI, PK
topic_name // name of the topic
... etc
Topics
Posts in these topics (which is what this is here, a post
Replies to posts, which is what the responses below are (your responses that is)
Users
user_id // Unique ID of the user, PK, AI
user_name
user_pass
user_email
user_date
Posts
post_id // unique ID of post - PK, AI
post_content
... etc
I also want to include the ability to like / dislike a post, and for that reason I created a table post_ranking which looks as follows
id // Auto increment ID
post_id // Foreign key, refers to post.post_id
user_id // Foreign key, refers to user.user_id
vote_up // Whether or not the post was voted up (0 for down, 1 for up)
rank_date // date the ranking occured
The problem I've just run into is that I cannot figure out how to incorporate the replies into this table. The only option I've thought of so far would be to create a second table called reply_ranking - but wouldn't this be somewhat unorganized?
So, my question:
Should I create two separate tables for rankings (post_ranking , reply_ranking) or is there another way that I should be arranging the tables above which would avoid this problem in the first place?

Your post is not very clear, I can't understand if in the table Topics you have inside also posts in that topic and replies to that topic.
In this case I think that this is not the good way, you should have posts separated from topic data. Let me explain.
A forum is formed by:
// MAIN PAGE, showing avaible forums
// |
// SPECIFIC FORUM, that show the threads (or topics) inside
// |
// POSTS that show part of the post related to that thread.
//
// USER_CP -------------- ADMIN_CP
We need at least 4 tables (I'm not considering admin_cp).
these are:
// TOPICS:
// +---------------+---------+-------------+----------+----------+----------------+
// | ID, p.k. a.i. | TITLE | SUB_TITLE | AUTHOR | CLOSED | PARENT FORUM |
// +---------------+---------+-------------+----------+----------+----------------+
//
// These are very few basic field for the table. No reference about the posts here.
//
//
// FORUMS:
// +---------------+---------+-------------+--------------+
// | ID, p.k. a.i. | TITLE | SUB_TITLE | VISIBILITY |
// +---------------+---------+-------------+--------------+
//
// Almost clear, visibility is a value to determine if the forum is private (such are
// forums like: "Moderator rooms" or "Admin stuff"), protected (i.e. for non registered
// users, or if the forum is public.
//
//
// POSTS:
// +---------------+----------+-------+-----------+--------+---------+-------+- - -
// | ID, p.k. a.i. | TOPIC_ID | TITLE | SUB_TITLE | AUTHOR | MESSAGE | VOTES | ...
// +---------------+----------+-------+-----------+--------+---------+-------+- - -
//
// In Votes you have a integer number (positive o negative, no matter) with the total
// of the votes for this post (not useful if you fully use the table like).
//
// REPLIES
// +---------------+----------+---------+--------+---------+
// | ID, p.k. a.i. | TOPIC_ID | POST_ID | AUTHOR | MESSAGE |
// +---------------+----------+---------+--------+---------+
//
//
// USERS
// +---------------+------+------+------------+------+---------+- - - - -
// | ID, p.k. a.i. | NICK | PASS | PRIVILEGES | NAME | SURNAME | ETC..
// +---------------+------+------+------------+------+---------+- - - - -
//
// Privileges determinate if a user is admin, mod, super_mod or simple user
//
//
// LIKES
// +---------------+---------+---------+----------+----------+---------+------+
// | ID, p.k. a.i. | USER_ID | POST_ID | TOPIC_ID | REPLY_ID | UP_DOWN | DATE |
// +---------------+---------+---------+----------+----------+---------+------+
This is, in my opinion the structure you should use.
home page, show all the forums:
read the privileges of the user
read the forums data from the table WHERE visibility >= user_privileges
impaginate each forum with proper links.
Forum page, show all the topics (and moderators):
read the topics from the table WHERE parent_forum = forum_id
read moderators of this forum
impaginate topics with proper links
shows moderator at the bottom of the page.
Topic page, show all the messages.
read the topi data from the table.
the topic is also the first message!
read the posts from the table WHERE topic_id = current_topic_id
for each post read from the table "LIKES" WHERE post_id = selected_post
sum all the votes
impaginate the post in proper pages and proper votes.
User page:
read all the data, WHERE id = user_id_that_want
read from "LIKE" WHERE user_id = actual_user
you have all the likes/dislike the user sent. do what you want.
impaginate
With this table structure you can also use a StackOverflow similar way to consider votes, i.e. UPvotes are 0 for the voter, but downvote are -1 for the voter. For each post, you can read from the like table just using post_id, so you know how many votes have the post (up and down) and with this you can count also up vote +10 to the post creator, downvote -5 to post creator.
Only with an extra table that is likes.
You can have:
votes on a topic
votes on a post
votes on a reply
votes total (reply+post+topic) of the topic.
When you insert a topic you will add:
user_id
topic_id = topic id
post_id = -1 (this is not a post, is the topic!)
repl
y_id = -1 (as above)
when you insert a post:
user_id
topic_id = current topic
post_id = post_id
reply_id = -1 (this is not a a reply)
when you insert a reply
user_id
topic_id = current topic
post_id = current post
reply_id = the reply id.
This will not have id problem issues. because the three are separated.
If you call for all the answer of a specific topic and a specific post you will add:
WHERE topic_id = current, post_id = current
if you need the reply of a topic, just put post_id = -1
And so on.
No issues with the ids!
I think I have explained almost all. for any question, ask!
EDITED: something here and there

Another thing you can do is make a single rankings table, with a field indicating whether the upvote/downvote is for a post or a ranking. You will have to use a non unique generic "item_id" instead of post id or reply id, but you do get one table if this is important to you.
EDIT: Just realised the foreign key field will be non unique anyway, since you may have multiple votes for the same post; the point is post ids and reply ids can't be told apart.
This WILL make it harder to deal with querying the table. My recommendation is you go with your current plan and make two tables; it is the most semantic way you can organise your data.

I usually think like this:
One user has many posts (this means you'll need a users table and a posts table, and every post will have a user_id to signal who owns it.
For some relations, (for example, when you realize that A has many B and B has many A, that's what we can an n to n relationship), you'll need a third table; this might be what you are hinting at in your comment as to what the reply entity should be translated to in your database....
Feel free to commit errors... almost never you will end up with the exact same model you started with... many things we don't know we need until we do.

Related

Giving several unique ID´s to a MySql row and using php to show all rows with one special ID

I am trying to make a system that manages a lot of articles and some articles are needed in more than one article series.
I am wondering how I can give one row in Mysql several unique ID´s and extracting them from the database with PHP.
It only reads the first ID and not the next.
I have tried seperating them with a comma, but if I write 10, 122.
Only 10 will be read as an ID and 122 will be ignored.
I am not very skilled with programming, but I am doing my best to learn it, Hope you can help me! :-)
The code I use to sort the articles in the system.
$id=$_REQUEST['id'];
$ro=mysql_query("SELECT * FROM blog_articles
WHERE fk_semikatagori_id=".$id."
ORDER BY ABS(sortering) ASC") or die(mysql_error());
Each article is unique, right? Keep it having a unique ID. What you should do is create an additional table, like #user574632 has suggested, where you don't have any unique fields but this will allow you to create your "categories" (or "series") and add each unique article to that table. You then search THAT table to obtain all the IDs of articles that are supposed to be in a series.
E.g.
Articles
========
ID | Title | Body
1 | My Article | This is my article
2 | StackExchange | My article on Stack Exchange...
Categories
========
SeriesID | ArticleID
1 | 1
1 | 2
2 | 1
You then query the categories table to obtain all the article IDs you require for your series...
If you can't fix the table design, use FIND_IN_SET:
$ro=mysql_query("SELECT * FROM blog_articles
WHERE FIND_IN_SET($id, fk_semikatagori_id)
ORDER BY ABS(sortering) ASC") or die(mysql_error());

How to link a row of MySQL database table to another row in another table

I know it makes little sense... and i'm new to using MySQL...
What i'm trying to do here is, link one tables row to another tables row...
for an example there are two tables..
one table is for user registration and same table is used for login as well...
and the next table is for user posts.. like status updates and all...
here is how i want it...
user_log_info:-
id ( primary )
firstname
lastname
username
email
password
posts:-
id ( primary )
userposts
posted_by
date_post
so as you can see, i want the user_log_info tables username to be automatically copied to posts posted_by row... And i have no idea how i can archive this...
You haven't given nearly enough information to give a full answer, but I'll do my best with what you've given.
Tables
+-----------------+ +-----------------+
| users_log_info | | posts |
+-----------------+ +-----------------+
| int ID (primary)| | int ID (primary)|
+-----------------+ | int posted_by |
+-----------------+
(I left off fields that are irrelevant to what you seem to want to do, I'm just simplifying it)
posted_by is an unofficial foreign key, or referencing the primary key of another table.
To insert, what you can do is along the lines of this:
INSERT INTO posts(...., posted_by) VALUES (...., user.ID)
Where .... is referencing all of your other information to insert
Then, to find information on someone who posted something:
SELECT * FROM users_log_info WHERE ID = Post.posted_by
Or if you want to find all posts by a user:
SELECT * FROM posts WHERE posted_by = user.ID
So, if Bob, who is User ID 3 wants to post "Hi", you might be able to do:
INSERT INTO posts(content, posted_by) VALUES('Hi', bob.ID)
And then when you are outputting the post you might do this:
post = (however you choose the post to put on the page)
userPosted = SELECT * FROM users_log_info WHERE ID = post.posted_by
print post.content + " posted by: " userPosted.Name
Essentially, the field "posted_by" is, to "posts" an arbitrary number, but you know that it links to, or references, a user. It does that by referencing "ID", which is the primary key of users_log_info, so that when you want to get information from users_log_info, is all you need to do is select the entry which has the ID that corresponds to "posted_by". I do recommend naming it something like posterID, however, for easier identification.

Up vote and down vote in Laravel eloquent

I want to create an up vote and down vote system for my website where a unique user can vote up/down for one post and next time he only allow to opposite to get off from database and after that he again can up or down vote.
In this case I have:
users table :
id
name
debates table :
id
post
upvotes table:
id
user_id
debate_id
and similarly downvote table:
id
user_id
debate_id
Is that a good way to manage and track up vote and down vote concept?
I think, you can use a single table to track the votes and the structure could be something like this
Table : votes
id | user_id | debate_id | vote
Here, vote field could be tinyInt with defauld null.
And, in vote field, you just keep two different values depending on the vote type, for example, if a user up votes then insert a value of 1 in the vote field and for down vote, insert the value of 0. So, your table may look something like this
id | user_id | debate_id| vote
1 | 10 | 4 | 1 <-- up
2 | 11 | 4 | 0 <-- down
3 | 12 | 4 | 1 <-- up
In this case, two users with id = 10 and id = 12 up voted the post whose debate_id = 4 and another user with user_id = 11 down voted on the same post.
IN this case, you may find out how many up or down votes a post got by counting the vote field's value, for example, you may count for up votes for debate_id = 4 using something like this
$count = Debate::where('debate_id', '=', 4)->where('vote', '=', 1)->count();
Also, you may use something Query Scope, this is just an idea and it's not possible to make an answer which covers everything in this scope. You should start using some basic idea and if you stuck at a certain point, then you may ask specific questions with your code.
Also, I would like to mention that, if you find a user id in the votes table with a certain debate_id then this user has voted on this post and to find out the vote type, just check the vote field 1 or 0.
I would prefer to only have one table containing the votes, this could be done with an extra column such as is_downvote int(1).
It seems that you havn't tried much which is always a negative. For this scenario the Laravel Eloquent Documentation should be plenty to figure this out.
I would of written this as a comment but it's pretty lengthy now.

count the number of comments (php/mysql)

i am using this code so i can count the number of comments for each article
SELECT *, COUNT(comment_id) as count
FROM article_comments
WHERE article_id =colname
GROUP BY article_id
this is what my comment table look like
http://i54.tinypic.com/2cdu3dk.png
i want to save these number in another table (the articles table.. each number next to it's article ) like this
http://i54.tinypic.com/2dgm82u.png
and when the user enter a comment..the number change automatically
someone help me with the code
or if there is another way to do this
i know it's a long question
but i have been trying to solve this for like..forever
thanx
You could set a TRIGGER that updates the comment count table every time a comment is added. Or you could simply add the UPDATE query right after the INSERT query in your comment page.
You probably do not need a lookup table. 1 article has many comments. Therefore, structure your comments table something like this (add an article field);
id | article | content
-------------------------
1 | 1 | Comment 1 for article 1.
2 | 1 | Comment 2 for article 1.
3 | 2 | Comment 3 for article 2.
When displaying your article, list comments using the following query;
SELECT a.id, a.content FROM articles a WHERE a.article = :myArticleId
When creating a new comment:
INSERT INTO comments (article, content) VALUES (:currentArticleId, :content)
UPDATE article SET commentCount = commentCount + 1 WHERE article = :currentArticleId
The articles table will look something like this;
id | commentCount | content
------------------------------
1 | 0 | Article with 0 comments.
2 | 3 | Article with 3 comments.
This requires some work on your part, but it has more benefits than drawbacks.
Your proposed solution has 2 large drawbacks;
COUNT() in SQL does not scale very well and can be slow, normally it can be avoided.
The lookup table adds unnecessary complexity to your application.
Triggers should also always be avoided. They create "magic" conditions - your database can be changed without you knowing about it. Triggers are often more difficult to change than code too.
$query = mysql_query("SELECT * FROM article_comments WHERE article_id =".$youarticleId);
//the number of comments is :
$number_Of_Comments = mysql_num_rows($query);
//save it to another table
$query2 = mysql_query("UPDATE yourTable set numberOfComments =".$number_Of_Comments);
on saving comments, try to:
update table_where_you_count_the_comments set number_of_comments = number_of_comments +1 where article_id = theID limit 1;
or look for mysql triggers.
you're asking the sql server to select everything and the count id at the same time, use one of them and give it a where close, and Bingo!

Rating System in PHP and MySQL

If we look at the stackoverflow website we have votes. But the question is what is the bestway to store who has voted and who has not. Lets also simplify this even more and say that we can only vote Up, and we can only Remove the Up vote.
I was thinking having the table to be in such form
question - Id(INT) | userId(INT) | title(TEXT) | vote(INT) | ratedBy(TEXT)
Thre rest is self explanitory but ratedBy is a Comma Seperated Id values of the Users.
I was thinking to read the ratedBy and compare it with the userId of the current logged in User. If he dosent exist in the ratedBy he can vote Up, otherwise he can remove his vote. Which in turn will remove the value from ratedBy
I think to make another table "vote" is better. The relationship between users and votes is n to n, therefore a new table should be created. It should be something like this:
question id (int) | user id (int) | permanent (bool) | timestamp (datetime)
Permanent field can be used to make votes stay after a given time, as SO does.
Other fields may be added according to desired features.
As each row will take at least 16B, you can have up to 250M rows in the table before the table uses 4GB (fat32 limit if there is one archive per table, which is the case for MyISAM and InnoDB).
Also, as Matthew Scharley points out in a comment, don't load all votes at once into memory (as fetching all the table in a resultset). You can always use LIMIT clause to narrow your query results.
A new table:
Article ID | User ID | Rating
Where Article ID and User ID make up the composite key, and rating would be 1, indicating upvote, -1 for a downvote and 0 for a removed vote (or just remove the row).
I believe your design won't be able to scale for large numbers of voters.
The typical thing to do is to create to tables
Table 1: question - Id(INT) | userId(INT) | title(TEXT)
Table 2: question - ID(INT) | vote(INT) | ratedBy(TEXT)
Then you can count the votes with a query like this:
SELECT t1.question_Id, t1.userId, t1.title, t2.sum(vote)
FROM table1 t1
LEFT JOIN table2 t2 ON t1.question_id = t2.question_id

Categories