Change order of elements in query results array - php

[edited] I need to display posts from database sorted in a kinda specific way.
There is a page which at set time interval query database via ajax to pull 180 latest post. Each post in db has column "source" which can be "instagram" or "twitter". Ajax returns 30 sets (or less) x 6 posts each (less if there is not enough posts). Than with help of js all sets are hidden and only one set (6 posts) is displayed at a time. After few seconds set is hidden and next one is shown. Think of it like a typical slideshow but with posts instead of images on infinite loop.
At the begining it wasn't important what kind of post were in sets. It could be all 6 posts from twitter or instagram or mixed. But as usual when project was scheduled to finish, I was asked to change the way sets are generated. Now client wants to have only 2 types of sets with posts in particular order (described below).
So my question is how change this (simplified example from my ajax file):
DB details for ref.: table POSTS: id / source / user / date etc.
$sql="SELECT * FROM posts ORDER BY id DESC LIMIT 180";
...
$stmt->setFetchMode(PDO::FETCH_OBJ);
$set=1;
while($row = $stmt->fetch()) {
if($set==1){
echo '<!--start set--><div class="set">';
}
if($row->source="twitter"){
echo '<div class="post twitter">';
echo '{all stuff related to this twitter post}';
echo '</div>';
} else if($row->source="instagram") {
echo '<div class="post instagram">';
echo '{all stuff related to this instagram post}';
echo '</div>';
}
if($set==6) {
echo '</div> <!--//END set-->';
$set=0;
}
}
$set++
}
into something what let me generate those 30 sets but with posts distributed among them using this pattern:
<!--First set should has post in order: --
<div class="set>
<div class="post twitter">{stuff}</div> {instagram post} {instagram post}
{instagram post}{instagram post}{twitter post}
</div> <!--//END set-->
<!--Second set order:-->
<div class="set">
{instagram} {instagram} {twitter}
{twitter} {instagram} {instagram}
</div>
etc.
Of course there is no guarantee that there would be enough post to create all 30 sets with those patterns so I need to create as many sets following those two patterns and leftovers put in sets as before simply in order they are pulled from db.
Thats all.
Thanks in advance for any suggestions / ready solutions ;) etc.

You could try something with a split between the two kind of posts using array_filter.
$posts = $stmt->fetchAll();
$twitterPosts = array_filter($posts, function($post){
return $post->source == "twitter";
});
$instagramPosts = array_filter($posts, function($post){
return $post->source == "instagram";
});
$set=1;
while(!empty($twitterPosts) && !empty($instagramPosts))
{
if($set%2 == 1)
{
$instagramPost1 = array_shift($instagramPosts);
$instagramPost2 = array_shift($instagramPosts);
$twitterPost1 = array_shift($twitterPosts);
}
else
{
$instagramPost1 = array_shift($instagramPosts);
$twitterPost1 = array_shift($twitterPosts);
$twitterPost2 = array_shift($twitterPosts);
}
/* display them */
if($set==6) {//your condition
echo '</div> <!--//END set-->';
$set=0;
}
$set++;
}
/* now one of them is empty, you can just display the other one */
if(!empty($twitterPosts))
/* Display all remaining twitter posts */
elseif(!empty($instagramPosts))
/* Display all remaining instagram posts */
Of course you should add validation that there is still something in the array between 2 array_shift.
I hope this helps !
EDIT : sorry I missed the condition for only 3 item per row, adding it now.

Related

How to enable onclick type events with the output of a mysqli_fetch_array($result))

I have been trying to get my head around how to approach this problem. I am writing a web page book library with the categories ('nodes') as MySQL records. I want to print the list of categories at each level, starting at the highest level, and then allow the user to select a category to travel deeper into the library. The PHP codes runs a saved procedure in MySQL:
//loop the result set
while ($row = mysqli_fetch_array($result)) {
if ($row[1] <> 0) {
echo $row[0];
echo "<br />";
} else { // the first row is just the heading
"</strong>Category: ";
echo $row[0];
echo " : <br />";
}}
Because there are only two test categories, this produces output:
Books :
Nature
Children's Books
However, I want to be able to create an onclick event over 'Nature' and 'Children's Books' so the user can select a category and drill down t the next level via a php function. I can convert the php output into html eg:
<?= "<p>{$row[0]}</p>" ?>
but I can't see how I can identify the row in an onclick event to pass a parameter to the function. Perhaps I need to have a completely different approach?
Add an onclick attribute to the element that calls a JavaScript function that does what you want.
<?= "<p onclick='someFunc({$row['id']})'>{$row[0]}</p>" ?>
Replace id with the actual name of the column containing the ID of the row in the table. someFunc() can use that ID to look up information in an array or object, or send an AJAX request.

Conditional display links based upon the login status PHP

I have a small site which has 200 members. Below is code for the login/logout links which display a "Change Password", "Report" and "Logout" link when logged in. While not logged in, the "Login" and "Forgot password" links are displayed.
Recently we ran a competition which had 14 winners and what I am trying to achieve is to put a link into the code that only the 14 winners can see and not the remaining members.
I'm not quite sure where to start, is it possible to put a condition in this code for the 14 user ids/email addresses or would I be better off putting a new field into the user's database? Any help or push in the right direction would be appreciated!
<?php # loginnav.php>
// Display links based upon the login status.
// Show LOGIN links if this is the LOGOUT page.
if (isset($_SESSION['user_id'])
AND (substr($_SERVER['PHP_SELF'], -10)
!='logout.php'))
{ echo
'<li>Logout</li>
<li>Change Password</li>
<li>Report</li>
'; } else {
// Not logged in.
echo
' <li>Login</li>
<li>Forgot Password?</li>
'; } ?>
$winners_array = array('userid1', 'userid2', 'userid3', 'userid4', ...);
// This array contains users IDs who are winners
// You can write it manualy right intj the login file,
//include it from external file or form from your Data Base
if (isset($_SESSION['user_id'])
AND (substr($_SERVER['PHP_SELF'], -10)
!='logout.php'))
{
echo
'<li>Logout</li>
<li>Change Password</li>
<li>Report</li>
';
if(in_array($_SESSION['user_id'], $winners_array)){
// If current ID is in winners list we add special link for him
echo '<li>Winner link</li>';
}
} else {
// Not logged in.
echo
' <li>Login</li>
<li>Forgot Password?</li>
'; } ?>
you can simply put the winners' id in an array, then check if the user id is in that array for showing the link.
$winners = array(1, 2, 3, 4, 5);
if (in_array($id, $winners))
{
echo "link";
}
One option is to add a conditional check of the user id and if it matches your list of ids, add the link. The downside of this block of code is that it is hardcoded, and can become a maintenance issue if you plan more contests or other links unique to certain members in the future. (You would end up with several of these blocks of code)
First set your winner ids into an array, like so:
$winningIds = array(1,2,3,4,5,6,7,8,...);
Then in the echo block where you are printing the links do this:
if (in_array($_SESSION['user_id'], $winningIds))
{
echo '<li>New Link</li> ';
}
Edit: I realized I didn't mention the other option I was thinking, which is to store a list of 'unique' links in the database for each user. Then after your echo block, you'd print the unique links for each user.
I envision this as two additional tables. Table 1 would be 'links' and would have three columns - id, link and display text. Table 2 would be 'user_links' and would contain two columns - linkId and userId.
You'd join the tables and have the links (which is your href) and display text display that are associated in the user_links table.

Display personal messages list

I have a personal message system in my website done simply with php/sql. Actually I am facing the trouble to display them using jquery. The db has as fields: message_id, message_from, message_to, message_topic, message_subject and message_status. The way I am showing the message_topic is repeating eight times the following:
echo '<table><tr><td>';
retrieve_msg_topic($result);
echo '</td></tr>'; //of course I won't make 8 tables!!!
the function called is:
function retrieve_msg_topic($result)
{
if($row = mysql_fetch_assoc($result))
{
echo $row['usernombre'];
$message_topic = stripslashes($row['message_topic']);
echo '<div id="msg'.$row['message_id'].'">';
echo $message_topic;
echo '</div>';
//this will return: <div id="msgN">message topic (title, commonly subject)</div>
}
} //end function retrieve msg topic
So far I have a list on a table with the last eight messages sent to the user. The following row is reserved for pagination (next/prior page) and, after that, another row showing the message I select from the list presented, like we see in Outlook. Here is my headache. My approach is to call another function (8 times) and have all of them hidden until I click on one of the messages, like this:
echo '<tr><td>';
retrieve_msg_content($result);
retrieve_msg_content($result); //repeat 8 times
echo '</td></tr></table>';
the function this time would be something like this:
function retrieve_msg_content($result)
{
if($row = mysql_fetch_assoc($result))
{
echo '<script type="text/javascript">
$(document).ready(function(){
$("#msg'.$row['message_id'].'").click(function(){
    $(".msgs").hide(1000);
$("#'.$row['message_id'].'").show(1000);
});
});
</script>';
echo '<div class="msgs" id="'.$row['message_id'].'" style="display: none">'
.$row['message_subject'].
'</div>';
}
/* This function returns:
// <script type="text/javascript">
// $(document).ready(function(){
// $("#msgN").click(function(){
// $(".msgs").hide(1000);
// $("#N").show(1000);
// });
// });
// </script>
// <div class="msgs" id="N" style="display: none">Message subject (body of message)</div>
*/
} //end function retrieve msg content/subject
I could simply explain that the problem is that it doesn't work and it is because I do if($row = mysql_fetch_assoc($result)) twice, so for the second time it doesn't have any more values!
The other approach I had was to call both the message_topic and message_subject in the same function but I end up with a sort of accordion which is not what I want.
I hope I was clear enough.
The easiest way to fix your troubles would be to copy the results of the MySQL query into an array
while($row = mysql_fetch_assoc($result)) {
$yourArray[] = $row;
}
And then use that to build your tables.
edit: What I meant was more along the lines of this:
while($row = mysql_fetch_assoc($result)) {
$yourArray[] = $row;
}
echo '<table>';
foreach($yourArray as $i) {
retrieve_msg_topic($i);
}
echo '<tr><td>';
foreach($yourArray as $i) {
retrieve_msg_content($i);
}
echo '</tr></td></table>';
And then removing everything to do with the SQL query from those functions, like this:
function retrieve_msg_topic($result) {
echo '<tr></td>'$result['usernombre'];
echo '<div id="msg'.$result['message_id'].'">';
echo stripslashes($result['message_topic']);
echo '</div><td></tr>';
}
Right now you're doing some weird key mojo with ret[0] being the topic and $ret[1] being the message, which isn't a good practise. Also, I don't see the declaration of $i anywhere in that code.
The error suggests that the result is empty or the query is malformed. I can't be sure from the code I've seen.
A few other notes: it seems weird that you're using stripslashes() on data that's directly from the DB. Are you sure you're not escaping stuff twice when inserting content into the DB?
Always use loops instead of writing something out x times (like the 8 times you said in your question). Think of a situation where you have to change something about the function call (the name, the parameters, whatever). With loops you have to edit 1 place. Without, you need to edit 8 different places.
BTW, another solution to this problem would be using AJAX to load content into the last cell. If you're curious, I could show you how.
more edits:
For AJAX, build your message list as usual and leave the target td empty. Then, add a jQuery AJAX call:
$('MSG_LIST_ELEMENT').click(function() {
var msgId = $(this).attr('id').replace('msg','');
$.get(AJAX_URL+'?msgID='+msgId,function(data) {
$('TARGET_TD').html(data);
})
});
Replace the capitalized variables with the ones you need. As for the PHP, just echo out the contents of the message with the ID $_GET['msgID'].
However, make sure you authenticate the user before echoing out any messages, so that someone else can't read someone's messages by switching the id number. Not sure how authentication works on your site, but this can be done by using session variables.

Friends List Pagination

I have got a feature on my website called 'View friends' that displays a hidden div containing a users friends. The only problem so far is I would like it so that it would show 7 members on each row for 3 rows so a total of 21 members on each page. I know I will have to round up NumOfMembers/21 giving me the pages needed. I just need some advice in how I should set up the pagination from when thee SQL query gets the total amount of friends. Any ideas?
The SQL-query should use the limit and offset parameters for pagination, depending on the page n you are on, like this:
SELECT .... LIMIT 21 OFFSET n*21
When handling the results, simply use the modulo operator for determining the lines and rows your current result has to be put in:
// where $i is the result number
$row = $i % 7;
$line = $i % 3;
You have 2 options:
First you can load everything from the php in one query and put all users in an array(content), and just display in pages!
content = [];
max = 21;
function handlePaginationClick(page, pagination_container) {
$('#MyContentArea').empty();
for(var i=0;i<max;i++) {
if(null!=content[(page*max)+i]) $('#MyContentArea').append(content[(page*max)+i]);
}
return false;
}
$("#News-Pagination").pagination(content.length, {
items_per_page:max,
callback:handlePaginationClick
});
you can use Jquery Pagination: https://github.com/gbirke/jquery_pagination#readme
for that.
Another approach is still using jquery pagination, but not load everything at once! then you must have same ajax call in the method 'handlePaginationClick' to pull all page information.

Something is making my page perform an Ajax call multiple times... [read: I've never been more frustrated with something so 'simple' in my life]

NOTE: This is a long question. I've explained all the 'basics' at the top and then there's some further (optional) information for if you need it.
Hi folks
Basically last night this started happening at about 9PM whilst I was trying to restructure my code to make it a bit nicer for the designer to add a few bits to. I tried to fix it until 2AM at which point I gave up. Came back to it this morning, still baffled.
I'll be honest with you, I'm a pretty bad Javascript developer. Since starting this project Javascript has been completely new to me and I've just learn as I went along. So please forgive me if my code structure is really bad (perhaps give a couple of pointers on how to improve it?).
So, to the problem: to reproduce it, visit http://furnace.howcode.com (it's far from complete). This problem is a little confusing but I'd really appreciate the help.
So in the second column you'll see three tabs
The 'Newest' tab is selected by default. Scroll to the bottom, and 3 further results should be dynamically fetched via Ajax.
Now click on the 'Top Rated' tab. You'll see all the results, but ordered by rating
Scroll to the bottom of 'Top Rated'. You'll see SIX results returned.
This is where it goes wrong. Only a further three should be returned (there are 18 entries in total). If you're observant you'll notice two 'blocks' of 3 returned.
The first 'block' is the second page of results from the 'Newest' tab. The second block is what I just want returned.
Did that make any sense? Never mind!
So basically I checked this out in Firebug. What happens is, from a 'Clean' page (first load, nothing done) it calls ONE POST request to http://furnace.howcode.com/code/loadmore .
But every time you load a new one of the tabs, it makes an ADDITIONAL POST request each time where there should normally only be ONE.
So, can you help me? I'd really appreciate it! At this point you could start independent investigation or read on for a little further (optional) information.
Thanks!
Jack
Further Info (may be irrelevant but here for reference):
It's almost like there's some Javascript code or something being left behind that duplicates it each time. I thought it might be this code that I use to detect when the browser is scrolled to the bottom:
var col = $('#col2');
col.scroll(function(){
if (col.outerHeight() == (col.get(0).scrollHeight - col.scrollTop()))
loadMore(1);
});
So what I thought was that code was left behind, and so every time you scroll #col2 (which contains different data for each tab) it detected that and added it for #newest as well. So, I made each tab click give #col2 a dynamic class - either .newestcol, .featuredcol, or .topratedcol. And then I changed the var col=$('.newestcol');dynamically so it would only detect it individually for each tab (makin' any sense?!). But hey, that didn't do anything.
Another useful tidbit: here's the PHP for http://furnace.howcode.com/code/loadmore:
$kind = $this->input->post('kind');
if ($kind == 1){ // kind is 1 - newest
$start = $this->input->post('currentpage');
$data['query'] = "SELECT code.id AS codeid, code.title AS codetitle, code.summary AS codesummary, code.author AS codeauthor, code.rating AS rating, code.date,
code_tags.*,
tags.*,
users.firstname AS authorname,
users.id AS authorid,
GROUP_CONCAT(tags.tag SEPARATOR ', ') AS taggroup
FROM code, code_tags, tags, users
WHERE users.id = code.author AND code_tags.code_id = code.id AND tags.id = code_tags.tag_id
GROUP BY code_id
ORDER BY date DESC
LIMIT $start, 15 ";
$this->load->view('code/ajaxlist',$data);
} elseif ($kind == 2) { // kind is 2 - featured
So my jQuery code sends a variable 'kind'. If it's 1, it runs the query for Newest, etc. etc.
The PHP code for furnace.howcode.com/code/ajaxlist is:
<?php // Our query base
// SELECT * FROM code ORDER BY date DESC
$query = $this->db->query($query);
foreach($query->result() as $row) {
?>
<script type="text/javascript">
$('#title-<?php echo $row->codeid;?>').click(function() {
var form_data = {
id: <?php echo $row->codeid; ?>
};
$('#col3').fadeOut('slow', function() {
$.ajax({
url: "<?php echo site_url('code/viewajax');?>",
type: 'POST',
data: form_data,
success: function(msg) {
$('#col3').html(msg);
$('#col3').fadeIn('fast');
}
});
});
});
</script>
<div class="result">
<div class="resulttext">
<div id="title-<?php echo $row->codeid; ?>" class="title">
<?php echo anchor('#',$row->codetitle); ?>
</div>
<div class="summary">
<?php echo $row->codesummary; ?>
</div>
<!-- Now insert the 5-star rating system -->
<?php include($_SERVER['DOCUMENT_ROOT']."/fivestars/5star.php");?>
<div class="bottom">
<div class="author">
Submitted by <?php echo anchor('auth/profile/'.$row->authorid,''.$row->authorname);?>
</div>
<?php
// Now we need to take the GROUP_CONCATted tags and split them using the magic of PHP into seperate tags
$tagarray = explode(", ", $row->taggroup);
foreach ($tagarray as $tag) {
?>
<div class="tagbutton" href="#">
<span><?php echo $tag; ?></span>
</div>
<?php } ?>
</div>
</div>
</div>
<?php }
echo " ";?>
<script type="text/javascript">
var newpage = <?php echo $this->input->post('currentpage') + 15;?>;
</script>
So that's everything in PHP. The rest you should be able to view with Firebug or by viewing the Source code. I've put all the Tab/clicking/Ajaxloading bits in the tags at the very bottom. There's a comment before it all kicks off.
Thanks so much for your help!
I think you're right to suspect this code block:
var col = $('#col2');
col.scroll(function(){
if (col.outerHeight() == (col.get(0).scrollHeight - col.scrollTop()))
loadMore(1);
});
My take on this is that you keep adding additional event handlers (duplicates, essentially) each time you run this code. You need to remove (unbind) the existing event handlers with every tab click so that you can be sure that it's only firing once:
$('#col2').unbind();
var col = $('#col2');
col.scroll(function(){
if (col.outerHeight() == (col.get(0).scrollHeight - col.scrollTop()))
loadMore(1);
});
Or some such thing. See http://api.jquery.com/unbind/
$('.featurecol'); , $('.topratedcol'); and $('.newestcol'); all refer to the same column and division (<div>). As such, whenever you switch pages, you need to unbind the old scroll before rebinding the new scroll handler. (Or else you'll be appending another scroll handler and getting multiple requests sent, like now)
You can do this by adding an unbind as follows:
var col = $('.newestcol');
col.unbind('scroll');
col.scroll(function(){
if (col.outerHeight() == (col.get(0).scrollHeight - col.scrollTop()))
loadMore(1);
});
You need to do this for all of the columns as they load (code/newest, code/toprated and code/featured).
It could also be
$('#col3').fadeOut('slow', function() {
as the ajax loads there... n number of times as it fades out it calls another ajax request.
not saying its the defenet answer but something looking into...

Categories