I'm beginning web development and started using PHP and MySQL. I'm trying to make a CMS similar to a technical blog and stuck at database design. Each post can be of any one of the following type.
Rich text - Single part
Rich text - Multiple parts
Video link - Single part
Video links - Multiple parts
Attachment - Single part
Attachments - Multiple parts
(The attachments can be pdf, doc, ppt)
Each post is under section. The sections are stored in a table. Examples for sections are
Tutorial - all types are allowed
Code snippet - only 1 is allowed
Tips or hacks - only 1,2,3,4 are allowed
News update - only 1 and 3 are allowed
Review - only 1 and 3 are allowed
So my question are
How do I store and distinguish single and multipart posts?
What is the feasible/best way to store attachments?
How do I relate sections and posts? ie., How to know/store that a particular section can support post types(all, only 1, only 1 and 2, etc).
Edit:
By single means, I mean 1 post has only 1 part and by multipart I mean 1 post can have several parts
I guess with "single" you mean that one post is related to one section, multipart means several posts relate to one section?
db-design could be...
table section
---------------
id (int, a-i)
type (int) 1=tutorial, 2=code-snippet etc.
name (varchar)
...
table post
---------------
id (int, a-i)
section_id (int) key to section.id
ordering (int) if multi for controlling which part is first, second etc.
type (int) 1=rich-text, 2=video, 3=attachment <---- drop single/multi discrimination here
single (int) 1=yes, 2=no <---- and put it here instead
content (varchar) --> see below
description (varchar) of this post
note: a single is one post, a multi several post linked to the same section.
where to store attachments:
in the file-system of your web server, the db holding the file-name in table.content.
small post-types (e.g. a link) can be stored directly in table.content
--> keeping your db lean and performing
relating sections and posts:
by post.section_id. Like this, you can link 1 or more posts to a section. use post.ordering to put them in the right order.
section
--------------------------
id | 1
name | "How to build a CMS"
type | 1 (tutorial)
post
--------------------------
id | 1
section_id | 1
ordering | 0
type | 1 (rich-text)
content | "/files/130224_1_1_cms.rtf"
...
id | 2
section_id | 1
ordering | 1
type | 3 (video link)
content | "http://www.youtube.com/hgstersh/showid=23jfjr&blabla"
...
which section.type can have which post.types?
on creating a new section, the section.type is set (e.g. drop-down-list in a form)
on creating a new post for this section, the drop-down-list for post-type offers only permitted types based on section.type, this is done in the php-script with if... or switch...case.
If a post can have multiple images, posts, links that's a one-to-many relationship and the typical schema is:
POST: id, title, ...
RICHTEXT: id, post_id, content
LINK: id, post_id, url
If you need a many-to-many relationship, for example a story can have many links but the same link can be on multiple stories you would have:
POST: id, title, ...
LINK: id, url
POSTS_LINKS: id, post_id, link_id
Also take a quick look at schemas for other popular platforms
Related
I'm making a blog system and I want to add 'tags' to my blogposts. These are similar to the tags you see here, they can be used to group posts with similar subjects.
I want to store the tags in the database as a comma-separated string of words (non-whitespaced strings). But I'm not quite sure how I would search for all posts containing tag A and tag B.
I don't like a simple solution that works with a small database where I retrieve all data and scan it with a PHP loop, because this won't work with a large database (hundreds if not thousands of posts). I do not intend to make this many blogposts, but I want the system to be solid and save worktime on the PHP scripts by getting right results straight from the database.
Let's say my table looks like this (it's a bit more complex actually)
blogposts:
id | title | content_html | tags
0 | "hello world" | "<em>hello world!</em>" | "hello,world,tag0"
1 | "bye world" | "<strong>bye world!</strong>" | "bye,world,tag1,tag2"
2 | "hello you" | "hello you! :>" | "hello,tag3,you"
How would I be able to select all posts that contain "hello" as well as "world" in the tags? I know about the LIKE statement, where you can search for substrings, but can you use it with multiple substrings?
You can't index a field of csv values in a meaningful way, and SQL doesn't support being able to find a unique value in a field of CSV values. Instead, you'll want to set up two more tables, and make the following alteration to your table.
blogposts:
id | title | content_html
tags:
id | tag_name
taxonomy table:
id | blogpost_id | tag_id
When you add a tag to a blog post, you will insert a new record into the taxonomy table. When you query for data, you'll join across all three tables to get the information similar to this:
SELECT `tag_name` FROM `blogposts` INNER JOIN `blogposts_taxonomy` ON
`blogposts`.`id`=`blogposts_taxonomy`.`blogpost_id` INNER JOIN `blogpost_tags` ON
`blogposts_taxonomy`.`tag_id`=`blogpost_tags`.`id` WHERE `blogposts`.`id` = someID;
//UPDATE
Setting up the N:M relationship gives you a lot of options during the build out of your application. For example, say you wanted to be able to search for blogposts that were all tagged "php." You could do that as follows:
SELECT `id`,`html_content` FROM `blogposts` INNER JOIN `blogposts_taxonomy` ON
`blogposts`.`id`=`blogposts_taxonomy`.`blogpost_id` INNER JOIN `blogposts_tags` ON
`blogposts_taxonomy`.`tag_id`=`blogposts_tags`.`id` WHERE `blogposts_tags`.`tag_name`="php";
That will return all blogposts that have been tagged with the "php" tag.
Cheers
If you really wanted to store the data like this the FIND_IN_SET mysql function would be your friend.
Have the function twice in the where clause.
But it will perform horribly - having a linked table one-to-many style as already suggested is MUCH better idea. If you have lots of the same tags a many-to-many could be used. Via a 'post2tag' table.
I am designing a blog site in php where users can add manually related posts to a post.
I thought to use an autoincrement integer for all posts related.
This is the table:
Blog:
-id
-related ( it's 0 if there aren't related posts or it contain an autoincremet integer that it is the same for all posts related )
-id_user
-title
-body
-date
I prefer not to use a "related table" if possible to avoid complex queries.
So I need a way to get an auto increment integer in this case or you can suggest me other solutions :)
Why not have a second table? It's probably the most robust solution, and it doesn't complify your queries much at all.
You should have a second table, related-posts, with two fields: original and related.
Neither are unique, so the following is possible (assuming 1,2,3,4 are post IDs)
o | r
--+--
1 | 2
1 | 3
2 | 3
2 | 4
4 | 1
When you need to find posts related to post 1 (for example), you query
SELECT `related` FROM `related-posts` WHERE `original` = 1;
This will give you all related post IDs.
This kind of relationship is called many-to-many relationship, one post can have many related posts, and one post can be related to many original posts.
You can just set related as NULL, and after that you can check, whether it's NULL — then there is no related posts.
To select all related posts:
SELECT * FROM Blog where related=:blog_id
For a project I am making I need the possibility (like stackoverflow does) to save all the previous edit (revisions) for posts.
Consider I can have some 1 to N association with the post (for example 1 post with 5 images associated).
How would you suggest me to design the database for this?
Of course the ID of the post should stay the same to don't broke URLs:
site/post/123 (whenever revisions it is)
Each revisions to posts should be manually approved so you can't show directly the last revisions inserted. How would you suggest me to design the db?
I have tought
Table: Post
postID | reviewID | isApproved | authorID | text
And the image table (for example image, but it could be everything)
Secondary Table: Image
imageID | postID | reviewID | imagedata
Actually, I would split the post table in two, with the approved revisions in one, and the latest (not approved) revision in another. The rational is that any non approved revision which is not the latest would be supersceded by the next one (unless you really want to keep track of all the intermediate modifications, approved or not).
Table: OldPost
postID | reviewID | authorID | text
Table: PendingPost
postID | authorID | text
In that layout, whenever a new revision has been approved, it must be moved to the approved ones, but you don't have to filter them out when displaying the whole history, and conversely, you wont have to filter the approved revisions in the approval part of your site.
You could even refine the layout with yet another dedicated table for the latest approved revision (so three tables for the post in total, not counting attachements). This partitioning would improve the overall performance of your site for the most common queries, at the cost of more complex queries when you need all the data (less frequent operations).
Table: CurrentPost
postID | authorID | text
As you can see, this table structure is the same as the one for pending posts, so the updates would be trivial.
moving a revision to the old post table requires to find out the revision count, but you would have to do that operation anyway with a more classic db layout.
Regarding the attachment table, the layout seems to work.
Separate all aspects of a post between global information and versionable information. In other words, what things can be changed in a revision and what are always going to apply to any revision. These are going to be the fields in your two tables, one for your posts, and one for the revisions. You will also need a row to specify what post the revision is for as well as whether the revision is approved, and on the posts table, you need a row to specify what the current revision in.
I'm currently have around 100 rows in a table on my website, which include a URL and few sets of numbers pulled from a database on my server. What I would like to do is to dynamically create pages based on a cell of each row, which would contain data pulled from the same database. For example, each row (displayed in the table) would look like this:
Icon (url) | Name (url) | Number 1 | Number 2 | Number 3 | Number 4 | Number 5
Inside my database however, each row is like this:
Icon (url) | Name (url) | Number 1 | Number 2 | Number 3 | Number 4 | Number 5 | Description (large body of text) | LargeImage (url)
Since I have so many entries, I would like to be able to have some way to generate the pages based on the name of the row in the database (it would take too long to make each page individually, and I will be updating this table frequently with content), so I can display more of the information out of the database row (the description, largeimage etc) that I wouldn't be able to fit into the table.
Are there any plugins for Wordpress that can do this, and if not, how would I go about doing this in PHP?
I'm not sure how to best integrate this into WP, but it's fairly straightforward in PHP. You just have a file like mypage.php?id={#} where the # is the individual record's ID. You pull the ID using GET ($id = $_GET["id"];) and then run an SQL query with it as the WHERE, take the results and populate the page with that row of data. Then, using .htaccess, you can do what WP does and make this look like a URL (ie. mypage/2/).
You can create the custom page by using a method like this for example.
You could integrate this into WP by creating a separate file (other than single.php, for example) that would run this PHP script, but include the WP header and footer to make it fit into the theme. However, this wouldn't really be fully integrated into single.php and therefore wouldn't appear in the posts section in the admin or anything. Is that a requirement?
I want to make a music playing website where users can save playlists of songs to be regenerated later. I'm kind of a newbie to sql, but it seems like databases are meant to hold fixed-length variables, whereas a user-generated playlist would be an arbitrary length. There are a couple ways I've thought of to handle this:
Separate tables (maybe another table for each playlist? )
XML
I feel like there's an easy third way I'm missing. I'm doing this in php, but if there's a super easy way using django I'd also be interested.
2 tables:
Playlists. Fields: id | title | owner_id (reference to user.id)
Songs. Fields: id | title | length | playlist_id (reference to playlist.id)
How about this:
Playlists: list_id|title|owner_id
Songs: song_id|title|artist|album|year|length|style|whatevereelseyouwnattoadd
Songs_In_Lists: song_id|list_id
Third table just ties songs to playlists.
otherwise there will be a lot of redundancy with song info if song goes to multiple playlists.
The primary key for the third table will be on both columns. Same song goes to same list only once, so it works fine.