Adding arrays together if duplicate values are found? - php

Okay so I just had a massive long discussion on here trying to get this code to work as it should... I am trying to display a "status" system on my site. So users can post on other users profiles and then comment on these statuses. Finally, we managed to get the 3 databases combined. I will explain the code first, and show the errors below...
Users
Statuses
Comments
Users contains the standard...
userid
username
first_name
last_name
photo
Statuses contains any information about a main status posted from each user, these statuses are displayed on the users profiles. So user 1 could post a status on user2's profile. Here is the statuses table design...
status_id (auto-i)
user_id (The users ID whos profile the post was added too)
sender_id (The user who sent the post or wrote it)
date (Date/Time was sent)
rate (This doesn't matter for a moment)
comments (This will count all the comments and display the number)
status (The actual status written out)
These tables worked fine added together in my script which connected both tables and displayed the users information (the one who posted the status) such as their profile photo and name etc... Here is my current script which has no issues at all, this combines the third table now (comments)...
//// GET STATUSES
$user_id = $profile_data['userid'];
$data = mysql_query("
SELECT -- added alias to your tables so its easier to read
s.status_id,
s.user_id,
s.sender_id,
s.status,
s.date,
u.first_name,
u.last_name,
u.photo,
u.username,
u.userid as uid,
o.userid as oid,
o.first_name as ofn,
c.comment,
c.status_id as csi
FROM statuses s
LEFT JOIN users u ON s.sender_id=u.userid
left JOIN comments c ON c.user_id = u.userid AND c.status_id = s.status_id
left join users o on o.userid = c.sender_id
where s.user_id = {$profile_data['userid']}
ORDER BY c.date DESC, s.date DESC") or die(mysql_error());
while($status = mysql_fetch_array( $data ))//added this
{
$statusid = $status['status_id'];
$date = $status['date'];
$rate = $status['rate'];
$comments = $status['comments'];
$userid = $profile_data['userid'];
$senderid = $status['uid'];
$statusbody = $status['status'];
$username = $status['username'];
$firstname = $status['first_name'];
$lastname = $status['last_name'];
$photo = $status['photo'];
$comment = $status['comment'];
$name = $status['ofn'];
$csi = $status['csi'];
?>
<form action="" method="POST" role="form" enctype="multipart/form-data" id="statusupdate" class="facebook-share-box">
<div class="share">
<div class="panel panel-default">
<div class="panel-heading"><img alt="" align="left" hspace="20" height="70" width="70" src="<? echo 'http://basecentre.co.uk/userimages/',$status["photo"]; ?>"> <font size="+2"><i class="icon icon-comment-o"></i></font> <font size="+2"><?php echo $status['first_name']; ?> <?php echo $status['last_name'] ; ?></font> | <i class="icon icon-clock-o"></i> <a rel="tooltip" href="#" data-original-title="<? echo "". date('F j, Y, g:i a', strtotime($status['date']) + 60*60) .""; ?>"><?php echo "<strong>". date('j F', strtotime($status['date']) + 60*60) ."</strong>"; if ($status['sender_id'] == $_SESSION['userid'] || $status['user_id'] == $_SESSION['userid']){
echo '<form name="deletestatus" action="" method="POST">
<input type="hidden" name="statusid" value="'.$status['status_id'].'" />
<td><input type="submit" value="Delete" onclick="return checkDelete()" class="btn btn-danger btn-xs" name="deletestatus" ></td>
</form>';
} else
echo "";?></a></div>
<div class="panel-body">
<div class="">
<?php echo $status['status']; ?>
</div>
</div>
<div class="panel-footer">
<div class="row">
<div class="col-md-7">
<? echo "".$status['comment']."".$status['ofn']."".$status['csi'].""; ?>
</div>
</div>
</div>
</div>
</div>
</form>
</br>
<?
}
?>
Here is the information and database for "Comments" table.
comment_id (auto-i)
status_id (added depending on which status you comment on. If the comment is on status id #5, the same number will be sent to this to connect the comments with the correct statuses)
sender_id (the id of the user who is sending the comment which would be $_session['userid'];
date (date the comment was sent)
rate (Doesn't matter yet)
comment (the actual comment written out).
MY ISSUE:
The problem I currently have which I am trying to work out is that "statuses" with more than ONE comment come up twice? So you'll have the same status repeated with a different comment below? I need to get all the comments on the same status where the status_id is the same.
In my last discussion we were talking about checking for duplicates and then if the comments table is found to have more than one comment for the same status_id, it should be added to a separate array?
I thought this was a bit off subject for my last post and I have no idea of how I would go about doing this? Would anyone be able to help me out here ? Or even give me some advice on where I would start? Thank you.

You'll probably have to iterate through your results in some way, obviously according to how your arrays are structured. An example would be:
Ex.1, if $results is an associate array with the the keys as the status id.
$data = array();
foreach ($results as $k =>$v)
{
// $k could be a status, for example "status_1"
// if it doesn't yet exist in the data array as a key
// we create an array that will hold comments for that status
if (!isset($data[$k])
{
$data[$k] = array();
}
// this status is already a key in our final data set $data, so we add
// add the comments to the array
else
{
$data[$k][] = <another_comment>
}
}
Ex.2, If $results is not an associative array.
$data = array();
foreach ($results as $v)
{
$status_id = $v['status_id];
// if it doesn't yet exist in the data array as a key
// we create an array that will hold comments for that status
if (!isset($data[$status_id])
{
$data[$status_id] = array();
}
// this status is already a key in our final data set $data, so we add
// add the comments to the array
else
{
$data[$status_id][] = $v['the_comment'];
}
}
Either way, your final array would look something like:
array(
status_1 => array(
[0] => 'some string 1',
[1] => 'some string 2,
)
)

Related

How would I select and display the most recently added rows from a SQL table?

I am making an extremely basic posting system, and I cant seem to figure out how to get the most recent rows from a certain table. I have tried other solutions offered here, but my posts were randomly placed. How would I accomplish this? My code is below.
function load_posts(){
$posts_sql = "SELECT * FROM posts";
$posts_result = Phoenix\Database\Database::$database->query($posts_sql);
while($row = $posts_result->fetch_assoc()){
$posts_display = '
<div class = "card" style = "width:500px">
<div class = "card-body">
<div class = "card-title">'. $row['username'] .'</div>
<p>'. $row['content'] .'</p>
</div>
</div>
';
echo $posts_display;
}
}
Again, I want the posts to be displayed from most recent, to old.
You need to have information in each row that captures this information. The most common suspects are:
an auto-incrementing id
a creation date
Then you just ask the database to sort the results. For instance, if post_id is an auto-incremented id:
select p.*
from posts p
order by p.post_id;
SELECT * FROM TableName ORDER BY id DESC
// order by should be with primary key

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

CodeIgniter - Enter data into textbox and check for matching record from database on submit

I have a CodeIgniter application where I need to add some information in a form in my view page named meal_add.php. Here is the form:
<div id="content" class="box">
<form action="<?php echo base_url(); ?>index.php/admin_logins/meal2" method="post">
<fieldset>
<legend id="add_employee_legend">
Add Meal Information
</legend>
<div>
<label id= "emp_id_add_label">Employee ID:</label>
<input type="text" name="emp_id" id = "employee_id_add" placeholder="Employee ID" required="1"/>
</div>
<br>
<div>
<label id= "is_guest_add_label">Guests?</label>
<input type="checkbox" name ="is_guest_checkbox" class ="guestcheck" value="1" onchange="valueChanged()"/>
</div>
<br>
<div id = "guestnum" hidden = "true">
<label id= "num_of_guest_add_label">No. of Guests:</label>
<input type="text" name="num_of_guest" id = "num_of_guest_add" placeholder='0'/>
</div>
<div>
<label id= "remarks_add_label">Remarks:</label>
<textarea rows="1" cols="20" style="margin-left: 35px"></textarea>
</div>
<input type="submit" name="submit" id = "meal_info_submit" value="Save Meal Information"/>
<button id = "cancel_button" onclick="location.href='<?php echo base_url(); ?>index.php/admin_logins/meal'">
Cancel
</button>
</fieldset>
</form>
My controller method for add -
function meal2()
{
if($_POST)
{
date_default_timezone_set('Asia/Dacca');
$mdata['emp_id'] = $this->input->post('emp_id');
$mdata['entry_date'] = date('Y-m-d');
$mdata['is_guest'] = $this->input->post('is_guest_checkbox');
$mdata['num_of_guest'] = $this->input->post('num_of_guest');
$mdata['remarks'] = $this->input->post('remarks');
$res = $this->meal_model->insert_meal($mdata);
if($res)
{
$this->session->set_flashdata('message','Meal information added successfully');
redirect("admin_logins/meal");
}
}
else
{
$this->load->view('admin_logins/meal_add');
}
}
And my model method -
public function insert_meal($data)
{
return $this->db->insert('meal', $data);
}
I have a table named employee, the structure is as follows:
column data type
id int PK
emp_id varchar(15)
emp_name varchar(50)
emp_mobile_no varchar(15)
I have another table named meal, structure is as follows:
column data type
id int PK
emp_id varchar(15)
entry_date date
is_guest int
num_of_guest int
remarks text
What I need to do is: whenever I'll enter an ID in Employee ID textbox in my form meal_add.php page, system will determine whether my entered id text matches with value of employee.emp_id. If a match is found, then data will be successfully saved in the meal table as meal.emp_id, and the value that will be saved is the corresponding employee.id(the value in the primary key column of employee table). If no match is found, a php flash message will be displayed that says ID doesn't exist on top of my meal_add.php view page. I know that a JOIN query is needed, but the text matching part seems very difficult to me and I can't figure out how to organize my code and where to put them. Please help me out.
My Database is MySQL.
EDIT - 1:
I've done this in my controller method -
$temp = $this->input->post('emp_id');
$sql = "SELECT e.id FROM employee AS e WHERE e.emp_id = ?";
$mdata['emp_id'] = $this->db->query($sql, $temp)->emp_id;
if($mdata['emp_id'] == '')
{
$this->session->set_flashdata('message','Employee ID does\'nt exist');
redirect("admin_logins/meal");
}
No matter what value I'm providing in $temp, I always get the flash message and get redirected.
I've done this as well-
echo "<pre>";
print_r($mdata);
die();
And after doing echo and print_r(), I got this -
A PHP Error was encountered
Severity: Notice
Message: Undefined property: CI_DB_mysql_result::$emp_id
Filename: controllers/admin_logins.php
Line Number: 150
Array
(
[emp_id] =>
)
I think what you are after is $this->db->insert_id()
Docs here: https://ellislab.com/codeigniter/user-guide/database/helpers.html
Also look at proper form validation for codeigniter.
UPDATE
Sorry I misread when glancing at the question. Please look at generating query results.
$q = $this->db->query($sql, $temp);
if ($q->num_rows() > 0) {
// having a match means the emp_id is valid
$row = $q->row();
// you can now use $row->emp_id to insert to other table
$ID = $row->emp_id;
} else {
$this->session->set_flashdata('message','Employee ID does\'nt exist');
redirect("admin_logins/meal");
}
Why is emp_id a varchar on the meal table? If it is foreign key, it would help if the types match and int is a lot faster when matching (joining tables).
Made some massive changes:
Controller -
function meal2()
{
if($_POST)
{
date_default_timezone_set('Asia/Dacca');
$temp = $this->input->post('emp_id');
$query = $this->db->query("SELECT id FROM employee WHERE emp_id = '$temp' ")->result_array();
$mdata['emp_id'] = $query[0]['id'];
if($mdata['emp_id'] == '')
{
$this->session->set_flashdata('message','Employee ID doesn\'t exist');
redirect("admin_logins/meal");
}
$mdata['entry_date'] = date('Y-m-d');
$mdata['is_guest'] = $this->input->post('is_guest_checkbox');
$mdata['num_of_guest'] = $this->input->post('num_of_guest');
$mdata['remarks'] = $this->input->post('remarks');
$res = $this->meal_model->insert_meal($mdata);
if($res)
{
$this->session->set_flashdata('message','Meal information added successfully');
redirect("admin_logins/meal");
}
}
else
{
$this->load->view('admin_logins/meal_add');
}
}
Also in another method named meal() in controller -
$data['myQuery'] = $special_query = $this->db->query("SELECT m.id, e.emp_id, m.entry_Date, m.is_guest, m.num_of_guest, m.remarks FROM meal m LEFT JOIN employee e ON e.id = m.emp_id")->result_array();
Had to use a LEFT JOIN (my favorite) to retrieve the related information.

Categories