Template system while in a while - php

I am trying to make put comments below the answers that I loop (just like answers on stackoverflow) But I can't find out how to put the right comment below the right answer. I am using the template system with this.
With what I currently have it only shows the comments of the query with the last $row['id']
PHP Code:
<?php
//Query setup for answers
$answerquery = "SELECT a.id, a.post_id, a.username, a.date, a.text FROM answers_tbl AS a, posts_tbl AS p WHERE a.post_id = p.id";
$result = $mysqli->query($answerquery);
//Replace answers
$layout_a = file_get_contents("tpl/question_answer_layout.html");
$search_a = array("%username%", "%date_a%", "%text_a%");
$answer_r = NULL;
while($row = $result->fetch_array()){
$replace_a = array($row['username'], $row['date'], $row['text']);
$answer_r .= str_replace($search_a, $replace_a, $layout_a);
//Query setup for comments of the question
$commentquery = "SELECT c.username, c.comment
FROM answer_comments_tbl AS c
INNER JOIN answers_tbl AS a ON a.id = c.answer_id
WHERE answer_id =".$row['id'];
$result2 = $mysqli->query($commentquery);
//Replace comments
$layout_c = file_get_contents("tpl/question_comment_layout.html");
$search_c = array("%comment_c%", "%username_c%");
$answer_c = NULL;
while($row2 = $result2->fetch_assoc()){
$replace_c = array($row2['comment'], $row2['username']);
$answer_c = str_replace($search_c, $replace_c, $layout_c);
$answer_r = str_replace("%answer_comment%", $answer_c, $answer_r);
}
}
$template = str_replace("%answer_post%", $answer_r, $template);
?>
question_answer_layout.html:
<div id="AnswerCarTop">
</div><!--Question-->
<div id="QuestionBottom">
<div id="QuestionTitle">%username%</div><!--QuestionTitle-->
<div id="Paragraph">%text_a%</div><!--Paragraph-->
%answer_comment%
question_comment_layout.html:
<div id="CommentPlaced">
<div id="Paragraph1">%comment% - <span class="bold">%username%</span></div>
<!--Paragraph--></div>

There are a few problems with your code that prevent it from working correctly.
First of all, the query to retrieve the comments needs to do a join between the two tables you are using, otherwise it will perform a cartesian product of the two tables (every answer is joined to every comment and then filtered by where). You should rewrite it as:
SELECT c.username, c.comment
FROM answer_comments_tbl AS c
INNER JOIN answers_tbl AS a ON a.id = c.answer_id
WHERE answer_id = $row['id']
Of course, using prepared statements is another matter entirely.
The second problem is the order in which you're doing your replacements. The basic structure (in pseudocode) should be:
for each answer {
for each comment {
comment = apply the comment template
comments_string += comment
}
apply the posts template, using the previously calculated comments_string
}
The third problem is the general approach of performing a separate query for every answer. You can solve this problem with just 2 queries (or even a single one, but then it's a more delicate matter which will certainly derive into its own discussion). The better approach would be to get all the answers for the post, then get all the comments that are related to that post. After that you can group up the comments to know where each one comes from.
Here is the fully edited code. I didn't add prepared statements because it's beyond the scope of this answer, but you should definitely use them.
<?php
//Query setup for answers
$answerquery = "
SELECT a.id, a.post_id, a.username, a.date, a.text
FROM answers_tbl AS a
INNER JOIN posts_tbl AS p ON a.post_id = p.id
WHERE p.id = " . (int) $post_id;
$answerResult = $mysqli->query( $answerquery );
// Query setup for comments
$commentsQuery = "
SELECT c.username, c.comment, c.answer_id
FROM answer_comments_tbl AS c
INNER JOIN answers_tbl AS a ON a.id = c.answer_id
WHERE a.post_id = " . (int) $post_id;
$commentsResult = $mysqli->query( $commentsQuery );
// Group the comments by answer
$groupedComments = array();
while( $row = $mysqli->fetch_assoc( $commentsResult ) ) {
if( ! isset( $groupedComments[ $row['answer_id'] ] ) ) {
$groupedComments[ $row['answer_id'] ] = array();
}
$groupedComments[ $row['answer_id'] ][] = $row;
}
// Loading the template files only once
$layout_a = file_get_contents( 'tpl/question_answer_layout.html' );
$search_a = array( '%username%', '%date_a%', '%text_a%');
$layout_c = file_get_contents( 'tpl/question_comment_layout.html' );
$search_c = array( '%comment%', '%username%');
// This will hold the string with all the answers and their comments
$answers = null;
while( $row = $answerResult->fetch_assoc() ) {
// This will hold all the comments for the current answer
$answer_comment = null;
foreach( $groupedComments[ $row['id'] ] as $comment ) {
// Apply the comment layout
$replace_c = array( $comment['comment'], $comment['username'] );
$answer_comment .= str_replace( $search_c, $replace_c, $layout_c );
}
// Apply the answer layout
$replace_a = array( $row['username'], $row['date'], $row['text'], $answer_comment );
$answers .= str_replace( $search_a, $replace_a, $layout_a );
}
// Add all the answers and the comments to the main template
$template = str_replace( '%answer_post%', $answers, $template );

This worked for me and solved my question:
<?php
//Query setup for answers
$answerquery = "SELECT a.id, a.post_id, a.username, a.date, a.text FROM answers_tbl AS a, posts_tbl AS p WHERE a.post_id = p.id";
$result = $mysqli->query($answerquery);
//Replace answers
$layout_a = file_get_contents("tpl/question_answer_layout.html");
$search_a = array("%username%", "%date_a%", "%text_a%");
$answer_r = NULL;
while($row = $result->fetch_array()){
$replace_a = array($row['username'], $row['date'], $row['text']);
$answer_r .= str_replace($search_a, $replace_a, $layout_a);
//Query setup for comments of the question
$commentquery = "SELECT c.username, c.comment
FROM answer_comments_tbl AS c
INNER JOIN answers_tbl AS a ON a.id = c.answer_id
WHERE answer_id =".$row['id'];
$result2 = $mysqli->query($commentquery);
//Replace comments
$layout_c = file_get_contents("tpl/question_comment_layout.html");
$search_c = array("%comment%", "%username%");
$answer_c = NULL;
while($row2 = $result2->fetch_assoc()){
$replace_c = array($row2['comment'], $row2['username']);
$answer_c .= str_replace($search_c, $replace_c, $layout_c);
}
$answer_r = str_replace("%answer_comment%", $answer_c, $answer_r);
}
$template = str_replace("%answer_post%", $answer_r, $template);
?>

Related

Three SELECT and two jsons

I created a SELECT to get my communities.
And create two SELECTs to get the communities I'm following.
But I get just my communities.
I do not get the communities I'm following.
$user_id = $_GET["id"];
$row1 = array();
$row2 = array();
// get my communities
$res1 = mysql_query("SELECT * FROM communities where user_id = '$user_id'");
while($r1 = mysql_fetch_assoc($res1)) {
$row1[] = $r1;
}
// get "id" of my communities I'm following
$res = mysql_query("SELECT * FROM communities_follow where user_id = '$user_id'");
while($r = mysql_fetch_assoc($res)) {
$coid = $r["coid"];
// get my communities I'm following
$res2 = mysql_query("SELECT * FROM communities where id = '$coid'");
while($r2 = mysql_fetch_assoc($res2)) {
$row2[] = $r2;
}
}
$resp = array_replace_recursive($row1, $row2);
print json_encode( $resp );
The inner join will get you those communities only, where you are following:
SELECT c.* FROM communities c
INNER JOIN communities_follow cf ON c.id = cf.coid
WHERE cf.user_id = '$user_id';
Or, without a JOIN:
SELECT * FROM communities
WHERE EXISTS (SELECT 1 FROM communities_follow cf
WHERE c.id = cf.coid AND cf.user_id = '$user_id')
Try this sql.
SELECT * FROM communities c LEFT JOIN communities_follow cf ON c.user_id = cf.user_id where
cf.user_id = '$user_id';

php if else statement: display data if there are results from either 2 functions

I'd really appreciate some help with this code as I can't get it to work properly.
I have two separate functions that both check a table in my database for data against an ID that is fetched from the page's URL. On displaying the information, I want to use an IF ELSE statement to check if there are results from either of those functions, and if there are no results, post nothing, and if there are results, post the results.
Below are my functions:
function getArtistsBySongId($id) {
$query = "SELECT * FROM `Credit_To_Artist` AS c2a
INNER JOIN `Credits` AS cr ON cr.credit_id = c2a.credit_id
INNER JOIN `Artist` AS a ON a.artist_id = c2a.artist_id
LEFT OUTER JOIN `Song` AS s ON s.song_id = c2a.song_id
LEFT OUTER JOIN `Remix` AS r ON r.remix_id = c2a.remix_id
LEFT OUTER JOIN `Project` AS p ON p.project_id = s.project_id
WHERE c2a.song_id = $id
ORDER BY a.artist_name ASC";
$res = mysql_query($query);
$artists = Array();
$artisttoid = Array();
$songtoid = Array();
while( $row = mysql_fetch_array($res) ) {
$artist = $row[artist_name];
$credit = $row[credit_name];
$songcr = $row[song_id];
if(!array_key_exists($artist, $artists) ) {
$artists[$artist] = Array();
$artisttoid[$artist] = $row[artist_id];
$songtoid[$songcr] = $row[song_id];
}
$artists[$artist][] = $credit;
}
return array($artists, $artisttoid, $songtoid);
}
function getGroupsBySongId($id) {
$query = "SELECT * FROM `Credit_To_Artist` AS c2a
INNER JOIN `Credits` AS cr ON cr.credit_id = c2a.credit_id
INNER JOIN `Artist_Group` AS ag ON ag.group_id = c2a.group_id
LEFT OUTER JOIN `Song` AS s ON s.song_id = c2a.song_id
LEFT OUTER JOIN `Remix` AS r ON r.remix_id = c2a.remix_id
LEFT OUTER JOIN `Project` AS p ON p.project_id = s.project_id
WHERE c2a.song_id = $id
ORDER BY ag.group_name ASC";
$res = mysql_query($query);
$groups = Array();
$grouptoid = Array();
$song2id = Array();
while( $row = mysql_fetch_array($res) ) {
$group = $row[group_name];
$credits = $row[credit_name];
$songcred = $row[song_id];
if(!array_key_exists($group, $groups) ) {
$groups[$group] = Array();
$grouptoid[$group] = $row[group_id];
$song2id[$songcred] = $row[song_id];
}
$groups[$group][] = $credits;
}
return array($groups, $grouptoid, $song2id);
}
At the moment I have this code:
<?php
if ((getArtistsBySongId($id) != NULL) OR (getGroupsBySongId($id) != NULL)) {
include 'songs/getsongcredits.php';
}
?>
While the code works in displaying my data, it seems to be ignoring my IF statement, and just posting what's in the include. Would someone be able to let me know the correct way to do this? Thanks in advance.
Both of your functions are returning an array regardless of the outcome of the query. Therefore you should check if the result returned from your functions are empty or not.
<?php
if (!empty(getArtistsBySongId($id)) OR !empty(getGroupsBySongId($id))) {
include 'songs/getsongcredits.php';
}
?>
Since both of your functions return arrays I would consider checking the size of the arrays returned. If you have data then the array size would be greater than 0 otherwise it would be 0.
<?php
$artistsBySongId = count(getArtistsBySongId($id));
$groupsBySongId = count(getGroupsBySongId($id));
if (($artistsBySongId != 0) || ($groupsBySongId != 0)) {
include 'songs/getsongcredits.php';
}
?>
Thanks all for taking the time to answer my question. However, neither of the codes worked in my site. A friend of mine has helped me though and it is now working. This is the code he used:
<?php
$errors = array_filter(getArtistsBySongId( $id ));
$errors1 = array_filter(getGroupsBySongId( $id ));
if (empty($errors) AND empty($errors1)) {
} else {
include 'songs/getsongcredits.php';
}
?>

select down and up votes for each post php mysql

I have a forum where users can post questions and can upvote and downvote.
I want to get the upvote and downvote of each post.
What i did previously was do that in 3 sets queries.
$data = mysqli_query($con,"select * from posts");
while($row = mysqli_fetch_assoc($data)){
$pid = $row['post_id'];
$up = mysqli_fetch_assoc(mysqli_query("SELECT COUNT(*) as c FROM up WHERE post_id = $pid"))['c'];
$down = mysqli_fetch_assoc(mysqli_query("SELECT COUNT(*) as c FROM down WHERE post_id = $pid"))['c'];
}
Can anyone show me how can i do these things in one single query because if a get a lot of posts in 1st query then there will be lots of queries to do.
You can use subqueries and put everything in the first query.
This could be a good start :
$data = mysqli_query($con, "select posts.*, " .
"(SELECT COUNT(*) FROM up WHERE post_id = posts.post_id) as totalUp, " .
"(SELECT COUNT(*) FROM down WHERE post_id = posts.post_id) as totalDown " .
"from posts");
while($row = mysqli_fetch_assoc($data)){
// ...
}
you can use corelated subquery for this where upvotes
and downvotes are counted based on the post id
SELECT p.*,
( select count(*) from up where post_id = p.post_id ) as upVotesCount,
( select count(*) from down where post_id = p.post_id ) as downVotesCount,
FROM posts p

Getting each variable from an array

I am trying to retrieve tags that are associated with a society. The code below works, but it is only retrieving the first tag and not the rest in the table.
$user = $_SESSION['user'];
$society = $_SESSION['society'];
$soc_q = mysql_query("SELECT socID, creator, socName, type, datetime
FROM societies.society WHERE socName = '$society'");
$soc_row = mysql_fetch_array($soc_q, MYSQL_ASSOC);
$tag_q = mysql_query("SELECT society.socID, tagID, name
FROM societies.society
INNER JOIN societies.tags ON society.socID = tags.socID
WHERE society.socID = '$soc_row[socID]'");
$tag_row = mysql_fetch_array($tag_q, MYSQL_ASSOC);
$the_tags = $tag_row['name'];
if (!#$_SESSION['existing_tags']) {
$_SESSION['existing_tags'] = $the_tags;
}
$existing_tags = $_SESSION['existing_tags'];
$tags = explode(' ', $the_tags);
// ajax
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && #$_GET['tag']) {
$match = array();
foreach ($tags as $tag) {
if (stripos($tag, $_GET['tag']) === 0) {
$match[] = $tag;
}
}
echo json_encode($match);
exit;
You have to load tags in loop like this (get each row):
$the_tags = array();
while( $tag_row = mysql_fetch_assoc( $tag_q)){
$the_tags[] = $tag_row['name'];
}
Edit: using GROUP BY
If you are willing to play with mySQL and element grouping you may use GROUP_CONCAT (if you need only tag names):
$tag_q = mysql_query("
SELECT GROUP_CONCAT( DISTINCT tags.name SEPARATOR ', ') as `tags`
FROM societies.society
INNER JOIN societies.tags ON society.socID = tags.socID
WHERE society.socID = '$soc_row[socID]'
GROUP BY NULL");
$tag_row = mysql_fetch_array($tag_q, MYSQL_ASSOC);
$tag_names = explode( ', ', $tag_row['tags']);
The code above isn't that useful, but when you'll combine it with your first query, you'll get:
$soc_q = mysql_query("SELECT socID, creator, socName, type, datetime,
GROUP_CONCAT( DISTINCT tags.name SEPARATOR ', ') as `tags`
FROM society
LEFT JOIN societies On societies.socID = society.socID
LEFT JOIN tags ON societies.tagsID = tags.socID
WHERE socName = '$society'
GROUP_BY society.id");
$soc_row = mysql_fetch_array($soc_q, MYSQL_ASSOC);
Note: prefixing tables with database names makes your code hard to read because once you're doing that, other time not.

Is it possible to combine these 3 mySQL queries?

I know the $downloadfile - and I want the $user_id. By trial and error I found that this does what I want. But it's 3 separate queries and 3 while loops. I have a feeling there is a better way. And yes, I only have a very little idea about what I'm doing :)
$result = pod_query("SELECT ID FROM wp_posts WHERE guid LIKE '%/$downloadfile'");
while ($row = mysql_fetch_assoc($result)) {
$attachment = $row['ID']; }
$result = pod_query("SELECT pod_id FROM wp_pods_rel WHERE tbl_row_id = '$attachment'");
while ($row = mysql_fetch_assoc($result)) {
$pod_id = $row['pod_id']; }
$result = pod_query("SELECT tbl_row_id FROM wp_pods_rel WHERE tbl_row_id = '$pod_id' AND field_id = '28'");
while ($row = mysql_fetch_assoc($result)) {
$user_id = $row['tbl_row_id']; }
Assuming I am understanding your queries correctly, this should work:
SELECT wp.ID, wpr.pod_id, wpr.tbl_row_id
FROM wp_pods_rel AS wpr
JOIN wp_posts AS wp
ON wp.ID = wpr.tbl_row_id
WHERE wpr.field_id = '28'
AND wp.guid LIKE '%/$downloadfile'
SELECT wp_posts.ID, wp_pods_rel.pod_id, wp_pods_rel.tbl_row_id
FROM wp_posts
JOIN wp_pods_rel ON wp_posts.ID = wp_pods_rel.tbl_row_id
WHERE wp_posts.guid LIKE '%/$downloadfile' AND wp_pods_rel.field_id = '28'

Categories