Showing the right records - php

I am making a sort of forum for myself to see how everything works. Its build in PHP (PDO) and now I got the problem. I can't figure out how I make sure when someone clicks on a record out of the board that it will only show the items with the topic_id that is set to that board
This is the topic database
This is the boards database
The code too show the board(s):
<section class="col-md-8 connectedSortable">
<div class="box box-info">
<div class="panel panel-default">
<div class="panel-heading main-color-bg">
<h3 class="panel-title">Boards</h3>
</div>
<div class="panel-body">
<?php
$boardss = $app->get_boards();
foreach($boardss as $board){
echo '<div class="col-md-6">';
echo '<div class="well dash-box">';
echo '<h3>'.$board['topic'].'</h3><br>';
echo '' .$board['omschrijving'].'';
echo '</div>';
echo '</div>';
}
?>
</div>
</div>
</div><!-- /.box -->
</section><!-- right col -->
The functions I use:
public function get_boards(){
$getBoards = $this->database->query("SELECT * FROM boards ORDER BY id DESC");
$boards = $this->database->resultset();
return $boards;
}
public function get_topics(){
$getTopic = $this->database->query("
SELECT topics.*, klanten.foto, klanten.voornaam, klanten.achternaam FROM topics
LEFT JOIN klanten ON topics.klant_id=klanten.id
ORDER BY id ASC");
$topics = $this->database->resultset();
return $topics;
}

When generating the link to the board page, you need to specify which board is actually called. Your current code looks like this:
echo '' . $board['omschrijving'] . '
As you can see, the call itself, which is in the href attribute, does not contain any information. Instead, you should add the primary key of the board there:
echo '' . $board['omschrijving'].'
If that is done, you can get the current board on the boards page via $_GET:
$currentBoard = $_GET['board'];
if (!is_numeric($currentBoard)) {
die('Not a valid board id');
}
$currentBoard = (int)$currentBoard;
With that information, you can then can specify the topic for the board, by adding it to your query in get_topics() and adding the board is as parameter to the function. (get_topics($currentBoard))
SELECT
topics.*,
klanten.foto,
klanten.voornaam,
klanten.achternaam
FROM
topics
LEFT JOIN klanten ON topics.klant_id=klanten.id
WHERE
topics.board_id = :board
ORDER BY id ASC
That statement uses the parameter :board, which you can replace in a prepared statement with the variable $currentBoard. I would highly encourage you to use prepared statments in that case.

Add parameter $board_id to get_topics(), then add a WHERE clause for the passed $board_id, so that only topics of that board will be fetched.
Updated Function:
public function get_topics($board_id){
$getTopic = $this->database->query("
SELECT topics.*, klanten.foto, klanten.voornaam, klanten.achternaam FROM topics
LEFT JOIN klanten ON topics.klant_id=klanten.id
WHERE topics.board_id = '$board_id'
ORDER BY id ASC");
$topics = $this->database->resultset();
return $topics;
}

Related

Another SQL query in a loop (row) query

I am struggling with my code. I try to make a News Feed.
The news feed is working well but now I want to add a avatar picture on each news row to have a picture from the author. The avatar picture path is in a different table (users).
That means I need to get in the loop the specific user ID ($row['uid']) and with that uid I need to get the related path from the user's avatar in the user table.
If I try to use a query in my loop it shows me only one result instead of 6 as specified in my query.
Do you have any suggestion or advise how I can solve that issue?
Many thanks for your support!
This is my attempt for the moment:
<div class="timeline p-4 block mb-4">
<?php
// Getting the user id and the feedmessage from Table "activity_feed"
$statement = $pdo->prepare("SELECT feed_message, uid FROM activity_feed WHERE cid = :cid ORDER BY id DESC LIMIT 6");
$result = $statement->execute(array('cid' => $cid));
$count = 1;
while($row = $statement->fetch())
{
// Starting the News feed Loop
?>
<?php
// This will repeat now X times as defined in the query above by = LIMIT ?
// Getting the avatar path from the user table
$statement = $pdo->prepare("SELECT avatar FROM users WHERE id = :id");
$result = $statement->execute(array('id' => $row['uid']));
$user_avatar = $statement->fetch();
?>
<style>
#circle_feed {
height:50px;
width:50px;
border-radius:50%;
/* Including the avatar path from query above*/
background-image: url("<?php echo $user_avatar['avatar']; ?>");
background-position:center;
background-size:cover;
}
</style>
<div class="tl-item ">
<div class="tl-dot"><a class="tl-author" href="#" data-abc="true">
<!-- Including the Avatar circle here-->
<span class="w-40 avatar circle gd-warning border" id="circle_feed"></span></a>
</div>
<div class="tl-content">
<div class=""><?php echo $row['feed_message']; ?></div>
<div class="tl-date text-muted mt-1">DATE</div>
</div>
</div>
<?php
// News Feed Loop is ending here
}
?>
</div>
</div>
There is no need to loop. SQL is a set-based language that can give your the results that you want in a single query, using the join syntax:
SELECT
af.feed_message,
af.uid,
u.avatar
FROM activity_feed af
INNER JOIN users u ON u.id = af.uid
WHERE af.cid = :cid
ORDER BY af.id DESC
LIMIT 6
This is much more efficient than running 7 queries (one for the activity feed, then one for each row returned by the first query, in a PHP loop).
You can then fetch the rows of the resultset and use this directly in your application.

Getting linked data from multiple tables into seperate bootstrap cards

I very recently (as in, this week) started learning PHP and am doing a practice task.
(Therefore, apologies in advance, if I sound like I don't know what I'm talking about, that is true)
Here is a crude schematic of my tables:
I have a main table products, and there are 3 planned product types (book, disc, furniture), and each type has a special attribute, with their own tables. (size for discs, weight for books etc.)
So far through testing, I've managed to query out the object from my products table each into their separate bootstrap card components. What I am trying to accomplish now is to add the special attributes to their respective object cards.
This is where i've reached a dead end. The idea I have is to first create a seperate array $printtocard, then call all the products table records by type, then run a foreach through all the found records, and then run a switch inside the foreach where i check the product types and run cases based on type, which create new objects based on the linked table data, and add each of them to the $printtocard array.
Afterwards the plan is to call the array in the code that later outputs the objects.
Here is my code so far:
Main php code
class products {
var $arrayy;
var $sql;
var $typepr;
protected function get_prod($conn1){
$printtocard = array();
$call_type = 'SELECT type FROM products ORDER BY id';
$type_res = mysqli_query($conn1, $call_type);
$type_arr = mysqli_fetch_all($type_res, MYSQLI_ASSOC);
$this->typepr = $type_arr;
return $this->typepr;
foreach($typepr as $xxx){
switch($xxx){
case "disc":
/* $disc_ */$sql = 'SELECT p.sku, p.name, p.price, a.value FROM products AS p INNER JOIN attr_size AS a ON p.id = a.product_id;';
$val_res = mysqli_query($conn1, $sql);
$val_arr = mysqli_fetch_all($val_res, MYSQLI_ASSOC);
$printtocard[] = $val_arr;
return $this->printtocard;
break;
case "book":
/* $book_ */$sql = 'SELECT p.sku, p.name, p.price, a.value FROM products AS p INNER JOIN attr_weight AS a ON p.id = a.product_id;';
$val_res = mysqli_query($conn1, $sql);
$val_arr = mysqli_fetch_all($val_res, MYSQLI_ASSOC);
$printtocard[] = $val_arr;
return $this->printtocard;
break;
case "furniture":
/* $furniture_ */$sql = 'SELECT p.sku, p.name, p.price, a.height, a.width, a.length, FROM products AS p INNER JOIN attr_dims AS a ON p.id = a.product_id';
$val_res = mysqli_query($conn1, $sql);
$val_arr = mysqli_fetch_all($val_res, MYSQLI_ASSOC);
$printtocard[] = $val_arr;
return $this->printtocard;
break;
}
}
//$sql = 'SELECT p.sku, p.name, p.price, a.value FROM products AS p INNER JOIN attr_size AS a ON p.id = a.product_id;';
//$call2 = 'SELECT sku, name, price FROM products ORDER BY id';
//$val_res = mysqli_query($conn1, $sql);
//$val_arr = mysqli_fetch_all($val_res, MYSQLI_ASSOC);
$this->arrayy = $printtocard;
return $this->arrayy;
}
public function get_prod2($conn1)
{
$this->get_prod($conn1);
}
}
$fff= new products;
$fff->get_prod2($conn);
$sss= $fff->arrayy;
Snippet of the webpage code where I autogenerate the cards:
<div class="container">
<div class="row">
<?php
foreach($sss as $value){ ?>
<div class="col s6 md2">
<div class="card cardstyle z-depth-0">
<div class="card-content center">
<?php echo htmlspecialchars($value['sku']); ?>
<div>
<?php echo htmlspecialchars($value['name']); ?>
</div>
<div>
<?php echo htmlspecialchars($value['price']); ?>
</div>
<div>
<?php echo htmlspecialchars($value['value']); ?>
</div>
</div>
<div class="card-action right-align">
<a class="brand-text" href="#"> more info </a>
</div>
</div>
</div>
<?php } ?>
</div>
</div>
The error message I currently get:
Warning
: Invalid argument supplied for foreach() in
C:\xampp\htdocs\uzdevumi\scandi_uzdevumi_kristianskonters\productlist\productlist.php
on line
108
A number of pointers
1. Its better to define your variables at the top depending on your intentions later (protected, private or public)
protected $arrayy;
protected $sql;
protected $typepr;
The return just before your "foreach" loop renders your loop pointless because it stops your function there and returns what you have.
return $this->typepr;
In connection to my previous point, you seem to think that "return" does some concatenation for you as shown by each "case" you have in your switch. No it does not it exits your function back to the calling scope.
return $this->printtocard;
The warning you have at the end means what it says, you are providing the "foreach" loop with an invalid argument. In other words it does not exist, thankfully its php (dynamically typed). But the problem is its undefined (has not value). Maybe its a typo and you wanted to loop through the array variable you got from sql calls.
foreach($typepr as $xxx)
Cross check typos and I did not get to check your html.

Why is my query returning incorrect results?

I recently asked a similar question to this about two weeks ago, but I have had no look in getting my problem working the way I need it to.
I have a query that is selecting from 2 tables; tickets and replies. I'm selecting the information from the ticket table, and I'm selecting the information from the replies table which has the ticket id stored in there. Which now comes to my problem.
My query is only displaying tickets that have more than 0 replies, but I need it to display the ticket information even if it doesn't have any replies.
I would like to know (if possible) if there is any way to fix my problem, and if there is a way to make it simpler than I currently have it.
It's a bit messy right now, but here is my is code to query and display the tickets and replies.
if(isset($_GET['id']) && is_numeric($_GET['id'])) {
$id = trim($_GET['id']);
$i = "";
$ticket = $db->conn->query("
SELECT * FROM tickets
INNER JOIN replies ON tickets.id = '$id'") or die(mysqli_error($db->conn));
while($rows = $ticket->fetch_assoc()) {
$i++;
if($_SESSION['ticket_username'] == $rows['client']) {
if($i <= 1) {
$status = $rows['status'];
echo '
<h3>'.$rows['subject'].'</h3><hr>
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title"><small>Created by '.$rows['client'].', '.$timeAgo->inWords($rows['created_at']).'</small></h3>
</div>
<div class="panel-body">'.nl2br($rows['message']).'</div>
</div>
';
}
echo '
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title"><small>Reply from '.$rows['reply_username'].', '.$timeAgo->inWords($rows['reply_time']).'</small></h3>
</div>
<div class="panel-body">'.nl2br($rows['reply_message']).'</div>
</div>
';
} else {
header("Location: index");
}
}
} else {
header("Location: index");
}
Change the query.
Use a LEFT JOIN instead of an INNER JOIN
$ticket = $db->conn->query("SELECT * FROM tickets
LEFT JOIN replies ON tickets.id = '$id'") or die(mysqli_error($db->conn));
Explanation:
Inner Join returns only those values for both the tables get the
match. This is a kind of intersection of two circles thing.
Left Join returns all the rows from left table irrespective
of whether it has any match on the right table.
In your case, if you use inner join, it was returning only those tickets who have replies.
Image Referred from here

Mysql query returning too many rows

so I have 3 tables all inner joined, I am trying to put discussions with the discussion topic on my main page, with the users name and the latest discussion message on the main page as well.
THE PROBLEM: The query is returning all messages attached to all the discussions.....I just need the last message associated with the discussion returned.
I have been at this all day and cant figure it out. I have tried group by but that just gave me an error on mysqli_fetch_array
Here is my code
$discussionquery = "SELECT discussion_messages.discussion_id, user_profile.first_name, user_profile.last_name, discussion_messages.message_text, case_discussion.discussion_title
FROM `user_profile`
INNER JOIN discussion_messages
ON (user_profile.user_id = discussion_messages.user_id)
INNER JOIN case_discussion
ON (case_discussion.discussion_id = discussion_messages.discussion_id)
WHERE discussion_messages.case_id = '$thecaseid'
ORDER BY discussion_messages.message_id DESC";
$discussionquerydata = mysqli_query($dbc, $discussionquery);
while ($row2 = mysqli_fetch_array($discussionquerydata)) {
$discussion_id = $row2['discussion_id'];
?>
<!-- Begin Recent Discussions -->
<div class="row">
<a href="discussion.php?newfact=$thecaseid'>">
<div class="col-xs-4 col-md-2">
<img src="img/client4.jpg" class="profile_picture img-rounded">
<?php echo '<h6 class="discussionname">' . $row2['first_name'] . ' ' . $row2['last_name'] . '</h6>';?>
</div>
</a>
<div class="col-xs-8 col-md-10 discussion_title">
<?php echo '<h5> '.$row2['discussion_title'].' -'. $row2['message_text'];?></h5>
<h6 class="pull-right">Dec. 25</h6>
</div>
</div>
<?php
};
You need logic to find the last message for each discussion. There is more than one way to write this condition.
The following does it using a not exists clause. This checks that there are no messages with a larger id for the discussion:
SELECT dm.discussion_id, up.first_name, up.last_name, dm.message_text, cd.discussion_title
FROM `user_profile` up INNER JOIN
discussion_messages dm
ON (user_profile.user_id = dm.user_id) INNER JOIN
case_discussion cd
ON (cd.discussion_id = dm.discussion_id)
WHERE dm.case_id = '$thecaseid' and
not exists (select 1
from discussion_messages dm2
where dm2.discussion_id = dm.discussion_id and
dm2.message_id > dm.message_id
)
ORDER BY dm.message_id DESC;
One suggestion, use table aliases. The amount of total code will be smaller and easier to understand. Use the limit clause to return 1 row.
$discussionquery = "
SELECT
m.discussion_id,
u.first_name,
u.last_name,
d.message_text,
c.discussion_title
FROM `user_profile` as u
INNER JOIN discussion_messages as m
ON (u.user_id = m.user_id)
INNER JOIN case_discussion c
ON (m.discussion_id = c.discussion_id)
WHERE
m.case_id = '$thecaseid'
ORDER BY
m.message_id DESC
LIMIT 1";

mysql recieve and compare data from multiple tables

the database tables for debat and comments are the same. it seems that $title and $date isnt working. how can i get the information from both, and order by date?
<?php
$showwall = mysql_query("(SELECT * FROM debat WHERE user='$user') UNION (SELECT * FROM comments WHERE user='$user') ORDER BY date LIMIT 0, 25");
$results = array();
while($wall = mysql_fetch_array($showwall, MYSQL_ASSOC)){ // Line 21
$results[] = $wall;
<li class="comment">
<div class="comment">
<div class="comment-author vcard user frame">
<?php echo "<img src=images/avatar/".$select['avatar']." class=avatar avatar-70 photo height=70 width=70 />"; ?>
</div>
<div class="message">
<span class="reply-link"><?php echo ""; ?> Edit </span>
<div class="info">
<h2><?php echo $wall['title']; ?></h2>
<span class="meta">
<?php
$date->setTimestamp($wall['date']);
echo "Dato: ";
echo $date->format('d-m-Y') . "\n";
echo "Kl: ";
echo $date->format('H:i:s') . "\n";
?>
</span>
</div>
<div class="comment-body ">
<p><?php echo $wall['comment']; ?></p>
</div>
</div>
</div>
</li>
<?php } ?>
I want to add another database to load from, it seems to leave a blank result.
$showwall = #mysql_query("(SELECT * FROM debat WHERE user='$user') UNION (SELECT * FROM comments WHERE user='$user') UNION (SELECT * FROM nyheder WHERE user='$user') ORDER BY date LIMIT 0, 25");
the database contains tables with the same names, but some have more fields than others. So this is isnt the right way to do it?
$showwall = #mysql_query("(SELECT * FROM debat WHERE user='$user') UNION (SELECT * FROM comments WHERE user='$user') UNION (SELECT * FROM nyheder WHERE user='$user') ORDER BY date LIMIT 0, 25")
As mentioned in the comments, the # will suppress error messages; those are there for a reason. You're also not checking the result - adding or die (mysql_error()) would give you the error message from the database.
In this case, the issue is because you're using UNIONs. That will only work if all tables have columns in the same order, and I suspect that that isn't the case. I think you just need a simple JOIN:
SELECT * FROM debat d
INNER JOIN comments c ON d.user=c.user
INNER JOIN nyheder n ON d.user=n.user
WHERE d.user='$user'
One final note - you're using mysql_* functions, which are being removed from PHP. You should look at moving to mysqli_* or PDO instead - they both make it easier for you to write safer code.

Categories