I am trying to create a post-comment system, with simple php-mysqli, as simple as it is, it does not seem to give me the result in the fashion I want i.e:
---POST MESSAGE----
-----comments-----
Here is the code I used:
<?php
session_start();
include_once('php_includes/db_conx.php');
$user=$_SESSION['user'];
$o =mysqli_query($db_conx, "SELECT post.id,post.post,post.date,post_comments.poster,post_comments.comment,post_comments.date FROM post LEFT JOIN post_comments ON post.id=post_comments.post_id AND post.username='$user' ORDER BY post.date");
while($r=mysqli_fetch_array($o,MYSQLI_ASSOC)){
$status= $r['post'];
$date=$r['date'];
$com=$r['comment'];
$pid=$r['id'];
$poster=$r['poster'];
if(count($pid) > 1){
}
echo $status.'|'.$pid.'|'.$date.'<br>'.$poster.':'.$com.'<hr>';
}
?>
It seems to duplicate the post for each comment for same post.
Not sure am making sense, but i will appreciate an answer.
First, add post id to your query's ORDER BY. That will ensure that your post and all its comments appear together, and only once. (I'd recommend adding post_comments.date as well so your comments will appear in order, but that won't be necessary to get the grouping working.)
... ORDER BY post.date, post.id, post_comments.date
Then keep track of the post id as you go. Echo the post information only when the post id changes.
$id = null; // initialize to null
while ($r = mysqli_fetch_array($o, MYSQLI_ASSOC)) {
$pid = $r['id'];
$status = $r['post'];
$date = $r['date'];
$com = $r['comment'];
$poster = $r['poster'];
if ($pid !== $id) {
echo $status.'|'.$pid.'|'.$date.'<br>'; // new post, so echo post info here
$id = $pid; // $id becomes new post id
}
if ($com) {
echo $poster.':'.$com.'<br>'; // echo comment if present
}
}
One other thing that will probably cause some trouble is that you have selected both post.date and post_comments.date in your query, so I'm not sure which one will be in $r['date']. It would be a good idea to alias at least one of those columns to disambiguate them.
Related
I know this has been done before. You can see an example of it whenever you post a new blog post/page in Wordpress, and the title is the same title as an existing page/post. Here's an example:
some-page-slug
some-page-slug-1
some-page-slug-2
How would you programmatically (using PHP) deal with someone submitting the slug of "some-page-slug" with the given list. Obviously, you should result in "some-page-slug-3", but what does that code look like? For some reason, this escapes me. I'm assuming, and hopefully I'm wrong, you would have to use jQuery (or vanilla js, whatever), correct?
Here's a possible solution like Mathew MacLeans suggested in his comment:
$slug = 'slug';
$slugs = array('slug', 'slug-1', 'slug-2', 'slug-5');
$result = $slug;
$i = 1;
while(in_array($result, $slugs)) {
$result = $slug . '-' . $i;
++$i;
}
// prints 'slug-3'
print $result;
Of course you have to replace in_array with your function that checks for existence of a slug.
Demo
Try before buy
Just some pseudo-code to get you going, but I believe this is the route you should take.
$postTitle = <WhateverTheTitleIs>;
$result = mysql_query("SELECT id FROM mytable WHERE title = '$postTitle'");
if(mysql_num_rows($result) == 0) {
// title not found, submit to database
} else {
// title exists
$postTitle = $postTitle + 1;
}
Now, obviously this isn't anywhere near 100% correct syntax, but it should more than point you in the direction that you need to go. :)
I am testing out the Redbean ORM. I like how it works, less work for me :) I am using the redbean books example, from their website. I have been able to create new books with authors and titles, and display them to the page with no problem. I added another dimension to learn how to link pages to my books.
I am able to add an entry into the book table, as well as add an entry into the page table using the following code:
----------- dbmgmt.php ---------------------------------
function AddNewBook($FORMINFO){
$newBook = R::dispense('book');
$newBook->title = $FORMINFO['title'];
$newBook->author = $FORMINFO['author'];
$newBook->create_date = R::isoDateTime();
$newPage = R::dispense('page');
$newPage->pagetext = $FORMINFO['pagetext'];
$newBook->ownPage = $newPage;
$id = R::store($newBook);
return R::load('book', $id);
}
Both tables show the proper entries (new ids and populated fields). However, I am having a hard time accessing the pagetext field from the page table. This is the code I have been using for that:
----------- dbmgmt.php ---------------------------------
function GetBooks($id){
if($id == ""){
return R::find('book');
}
else{
return R::find('book','id = ?', array($id));
}
}
----------- GetBooks.php ---------------------------------
$id = "";
if(isset($_GET['id'])){
$id = $_GET['id'];
}
$books = GetBooks($id);
$booklist = "";
foreach($books as $book){
$pagetext = "";
foreach($book->ownPage as $page){
$pagetext .= $page->pagetext; //Errors with "Notice: Trying to get property of non-object"
}
$booklist .= "<tr id='$book->id'><td><a class='linkEdit' href='edit.php?id=$book->id'><img src='http://cdn1.iconfinder.com/data/icons/ledicons/page_white_edit.png' /></a> <span class='book-title'>$book->title</span></td><td><span class='book-author'>$book->author</span></td><td><span class='page-text'>$pagetext</span></td></tr>";
}
echo $booklist;
------------------------------------------------------------
When I print_r($book->ownPage), I don't even see the page entry that I can clearly see in the page table via phpmyadmin. I have tried many different ways of accessing the pagetext field via my script above, but can't get anywhere with it.
Any insight would be most welcome. Otherwise I will have to try a different, albeit bigger and more cumbersome, ORM.
Thanks in advance.
I am not 100% sure as I haven't encountered this problem yet myself, but I am almost positive, $book->ownPage needs to be an array:
$newPage = R::dispense('page');
$newPage->pagetext = $FORMINFO['pagetext'];
$newBook->ownPage[] = $newPage;
$id = R::store($newBook);
I code a weekly trivia program for one of my clients through facebook.
I have a bit of code commented out where we display the winner when we need to. Currently I just remove the comment brackets and update when it's time to display. I'm trying to make this so someone non-savvy can handle updates so I've moved my code into an include:
winner-display.php
I am trying to write a function so that if the winner is set in MySQL, it includes the file in-line, and if the winner field is empty in the database, it does not.
Here is what I have so far, any ideas?
<?php
$target="3";
$myDataID = mysql_query("SELECT topic_desc from ref_links WHERE ref_categories_id = '$target' AND topic_name = '$property'", $connectID);
while ($row = mysql_fetch_row($myDataID)) {
$displayvalue = $row ['topic_desc'];
}
if ( $displayvalue != 'null') {
include('../includes/winner-display.php');
} else {
}
?>
Ok, thanks for helping guys, got it to work as:
<?php
$target="3";
$myDataID = mysql_query("SELECT topic_desc from ref_links WHERE ref_categories_id = '$target' AND topic_name = '$property'", $connectID);
while ($row = mysql_fetch_row($myDataID)) {
foreach ($row as $field) {
if ($field != null) {
include('../includes/winner-display.php');
}
}
}
?>
You can definitely put an include within an if. That solution that you posted should work as you would like it to, although I personally would have used a function instead of a completely separate file to include (although that is personal preference).
All you have to do to make it work is remove the quotes around 'null'.
<?php
$target="3";
$myDataID = mysql_query("SELECT topic_desc from ref_links WHERE ref_categories_id = $target' AND topic_name = '$property'", $connectID);
while ($row = mysql_fetch_row($myDataID)) {
$displayvalue = $row ['topic_desc'];
}
if ( $displayvalue != null) {
include('../includes/winner-display.php');
}
?>
Keep in mind that if your query returns more than one row, only the last row will be retained. I don't know if that is the functionality you want (in which case, there are some changes you could make, just ask me to edit my answer), but I didn't change that.
I would like to have a comment section with replies to comments. The replies will only go one level. For example.
Parent Comment
-- Here is a reply
-- Here is another reply
-- It won't go further than this one tier
My MySQL looks like this:
comment_id, comment, parents_id
if parents_id is 0, it is the parent. if it has a number, that number will correspond to the comment_id, as it will be its child.
now, i've done this crappy code below, but it seems the second loop messes it up and only displays the first div correctly with its children. i believe it is because i'm calling mysql_fetch_row twice...
$query_show_comments = "SELECT * FROM article_comments WHERE article_id = '$article_id'";
$results_show_comments = mysql_query($query_show_comments);
$num_rows_comments = mysql_num_rows($results_show_comments);
for ($i = 0; $i < $num_rows_comments; $i++) {
$comment = mysql_fetch_row($results_show_comments);
echo "<p>comment_id: $comment[0]</p>";
if ($comment[5] == 0) {
echo <<<_HTML
<div class="dispArticle">
<p><strong>Commenter Name commented # 11/22/10 10:10:10pm</strong></p>
<p>$comment[2]</p>
_HTML;
for ($j = 0; $j < $num_rows_comments; $j++) {
$replies = mysql_fetch_row($results_show_comments);
if ($replies[5] > 0 AND $replies[5] == $comment[0]) {
echo <<<_HTML
<div class="comment"><p><strong>Reply Name replied # 11/22/10 10:10:10pm</strong></p>
<p>child_id: $replies[0]</p>
<p>parent_id: $comment[0]</p>
<p>$replies[2]</p>
</div>
<br />
_HTML;
}
}
}
echo "</div>";
}
Been searching for hours and this is what I've found.
Use multiple tables (would like to keep it in one table so less queries)
Use multiple queries (same as above)
Feed into an array first then sort it all out (what if the comments are long and there are a lot? I just did a query AND had to do more server side processing of feeding it into an array, sorting then displaying...)
The problem is that mysql_fetch_row() will always fetch the next row returned by the query, and that could be in any order. For what you are doing to work, you would need a post to be followed immediately by its child comments every time. This is a shaky solution, so I would suggest you use #3 as it is really the same thing as what you are doing.
I also have a couple of suggestions: use mysql_fetch_assoc() over mysql_fetch_row() and use the names of the columns rather than their numbers as this makes the code much more readable and easier to use. You will have to change your query to order by the ascending parent ID to ensure that all parents are set first. Then:
$query = "query";
$result = mysql_query($query);
$comments = array();
while ($row = mysql_fetch_assoc($result)) {
if ($row['parent_id']) {
$comments[$row['parent_id']]['children'][] = $row;
}
else {
$row['children'] = array();
$comments[$row['comment_id']] = $row;
}
}
Now all of the children are associated with parents. Just iterate through the array.
It's not too hard. You should store all comments in one table and have parent_id
parent_id of 0 means it's a comment, parent_id > 0 would point to id of a message in the same table for which it's a reply.
You would also have article_id, just like in your current example.
The trick you need is to do just one SQL select but reference the same table twice.
You sql will be something like this:
SELECT
M.id as id,
M.id as com_mid,
M.post_subject as com_subject,
M.message_body as com_body,
M2.id as rpl_mid,
M2.post_subject as rpl_subject,
M2.message_body as rpl_body,
M2.parent_id
FROM
MESSAGES AS M
LEFT JOIN MESSAGES as M2 on M2.parent_message_id = M.id
WHERE M.article_id = :aid
AND M.parent_id = 0
ORDER BY com_mid ASC,
rpl_mid ASC
Then once you get result of this sql, you will easily figure out how to handle the result array to display messages and replies
You need a second query. Here's an example TRYING to use your code.
$query_show_comments = "SELECT * FROM article_comments WHERE article_id = '$article_id'";
$results_show_comments = mysql_query($query_show_comments);
$num_rows_comments = mysql_num_rows($results_show_comments);
for ($i = 0; $i < $num_rows_comments; $i++) {
$row_comment = mysql_fetch_row($results_show_comments);
echo "<p>comment_id: $row_comment[0]</p>";
if ($row_comment[5] == 0) {
echo <<<_HTML
<div class="dispArticle">
<p><strong>Commenter Name commented # 11/22/10 10:10:10pm</strong></p>
<p>$row_comment[2]</p>
_HTML;
$query_show_replies = "SELECT * FROM article_comments WHERE parent_id = '$article_id'";
$result_replies = mysql_query($query_show_replies);
while( $row_reply = mysql_fetch_row($results_show_comments) ) )
echo "
<div class=\"comment\"><p><strong>Reply Name replied # 11/22/10 10:10:10pm</strong></p>
<p>child_id: $row_reply[0]</p>
<p>parent_id: $row_reply[1]</p>
</div><br />
";
}
}
echo "</div>";
}
You're doing several things in your code that I don't like to do, not saying it can't be don't that way. My advice is to take a more advanced approach to architecting your web applications:
Use while() loops when reading data from queries, it's more error tolerant
don't use the "echo <<<" blocks because it makes code harder to read
technically speaking, you'll want to use htmlspecialchars on all output to a web page, so the <<< shouldn't be used anyways
better yet, use a template system to extricate your markup (view) from your PHP, conside Smarty because it's easy even if performance isn't quite stellar
in fact, while you're at it, consider abstracting your data code into a separate layer
no matter how you get the data, you shouldn't rely on indexed fields when you're using a SELECT *.. because the order could change. What I mean is, instead of using $comment[0] or $comment[1], use $comment['id'] or htmlspecialchars($comment['text'])
Been trying to get my head around while loops for the last few days but the code seems very inefficient for what I'm trying to achieve. I'm assuming I'm over-complicating this though nothing I've tried seems to work.
Each topic in my forum can have related topic IDs stored in a separate table. A post ID is also stored in this table, as that specific post references why they are considered related.
DB Table contains only: topic_id, related_id, post_id
// Get related IDs and post IDs for current topic being viewed
$result = $db->query('SELECT related_id, post_id FROM related_topics WHERE topic_id='.$id.'');
// If related topics found, put both of the IDs into arrays
if ($db->num_rows($result)) {
while($cur_related = mysql_fetch_array($result)){
$reltopicarray[] = $cur_related['related_id'];
$relpost[] = $cur_related['post_id'];
}
// If the first array isnt empty, get some additional info about each related ID from another table
if(!empty($reltopicarray)) {
$pieces = $reltopicarray;
$glued = "\"".implode('", "', $pieces)."\"";
$fetchtopics = $db->query('SELECT id, subject, author, image, etc FROM topics WHERE id IN('.$glued.')');
}
// Print each related topic
while($related = mysql_fetch_array($fetchtopics)){ ?>
<?php echo $related['subject']; ?> by <?php echo $related['author']; ?>
// Id like to show the Post ID below (from the array in the first while loop)
// The below link doesnt work as Im outside the while loop by this point.
<br />View Relationship
<?php } ?>
The above currently works, however I'm trying to also display the post_id link below each related topic link, as shown above.
if you change the second while loop to something like this:
<?php
$i = 0;
while($related = mysql_fetch_array($fetchtopics)){
//show view link
// [...]
//show the view related link
?>
View Relationship
<?php
//increment the i so that you can get the next post in the next iteration of the loop
$i++;
}
?>
[sidenote]
You probably should not be doing database queries in the same location you are generating the html for future-you's sanity.
[/sidenote]
[edit]
You could also do it all as one query:
SELECT related_topics.related_id,
related_topics.post_id,
related_topics.topic_id,
topics.subject,
topics.author,
topics.image,
topics.etc
FROM related_topics
LEFT JOIN topics ON topics.id = related_topics.topic_id
WHERE topic_id= $id
Then you only have to loop through it once for all of the links.