Log in

View Full Version : How to use next() and prev() on an array



kuau
05-22-2012, 12:37 AM
Does anyone know how to get next(), prev(), and current() to work properly? I have tried it on what seems like a simple application but no luck.

I have a table of art titles with title_id as the index. When someone clicks on a thumbnail it takes them to a detail page for that painting using the title_id in the query string. On the detail page I have NEXT and PREVIOUS arrows so people can browse to new paintings without returning to the thumbnail page. I want the array to be defined as

SELECT * FROM title WHERE artist_id=1 ORDER BY title
so that when they click NEXT it will take them to the next painting by that artist in alphabetical order by title. I haven't been able to get it to work so am currently using title_id + 1 and title_id -1, which is unsatisfactory. Seeing as the page is selected using the title_id, as in <a href="/php/art-detail.php?title_id=<?php echo $title_id +1;?>, how do I bring the array into it so next and prev work?

I have considered separating the artists into separate tables but that seems like settling for failure. I'd rather do it properly. This can't be that hard. I must be making some error I just can't see. Please put me out of my misery. Thanks! e :)

ApacheTech
05-22-2012, 01:01 AM
Can you give us an sample of the code you're currently using? It's the easiest way to debug the code to find out what you need.

traq
05-22-2012, 01:06 AM
honestly, I have never used next(), prev(), or current() in actual (production) code.

Since your links will only ever be for the next or previous page, the $id+1 or $id-1 is actually fairly efficient.

If you need to keep your search result (for this, or other, reasons), you might consider using $_SESSION. You could also cache the results (save it in a txt file) so they would be readily available when anyone made the same query.

kuau
05-22-2012, 01:08 AM
I tried various ways trying to get it to work. This is just the last one that didn't work in which I try using the image title in the query string...


$sql = "SELECT * FROM `title` WHERE `on` = 1 ORDER BY `filetag`";
$result2 = mysql_query($sql,$connection) or die("Couldn't execute $sql query. <br> mysql error: ".mysql_error());
$art = mysql_fetch_assoc($result2);
$current = current($art['filetag']);
$next = next($art['filetag']);
$prev = prev($art['filetag']);

<a href="/php/art-detail3.php?title=<?php echo $prev;?>"><<</a> &nbsp; &nbsp; <?php echo $art['title'];?> &nbsp; &nbsp; <a href="/php/art-detail3.php?title=<?php echo $next;?>">>></a>

traq
05-22-2012, 01:10 AM
$current = current($art['filetag']);
$next = next($art['filetag']);
$prev = prev($art['filetag']);

is $art['filetag'] an array?
(I would imagine it is a string)



Also, I'm not sure you have the right idea about these functions, anyway. They all deal with PHP's internal array pointer, which is a lot more similar to C's idea of traversal than what most PHP programmers do. observe:

<?php
$array = array( 'one','two','three' );
// since we just initialized the array, the pointer is at the beginning:
print current( $array );
// pointer doesn't move. prints "one".
print next( $array );
// pointer moves forward. prints "two".
print prev( $array );
// pointer moves back/ prints "one".

print next( $array[0] );
// this (similar to what you're doing) should actually throw an error:
// Warning: next() expects parameter 1 to be array ...
// and print nothing at all/

kuau
05-22-2012, 01:21 AM
Dear traq: Using +1 and -1 doesn't really work very well because I have no control over what is being presented. It jumps from one artist to another and then to sketches and calendars and things I don't really want displayed, all out of order. I want to be able to specifically define the array and then advance or rewind the pointer. I used to be able to do this in older database software.

I would have to reassign all the title_id's in sorted order with each artist in a separate table in order to accomplish what I want. I have considered this in exasperation, but I find it hard to believe that php cannot do this simple array advancing.

ApacheTech
05-22-2012, 01:26 AM
I'm not fully up on PHP syntax so please forgive any basic errors in this. This would be the best way I could see to achieve it, using next(), prev() and current().


<?php
mysql_connect("localhost", "mysql_user", "mysql_password") or
die("Could not connect: " . mysql_error());
mysql_select_db("mydb");

$sql = "SELECT * FROM title WHERE artist_id=1 ORDER BY title";
$res = mysql_query($sql);

function mysql_fetch_all($res) {
while($row=mysql_fetch_array($res, MYSQL_BOTH)) {
$return[] = $row;
}
return $return;
}

$art = mysql_fetch_all($res);
?>



<a href="/php/art-detail.php?title_id=<?php
if(current($art) != reset($art)) {
$prev = prev($art);
else
$prev = end($art);
}
echo $prev['title'];
?>">Previous</a>

<!-- code to display current($art) image here -->

<a href="/php/art-detail.php?title_id=<?php
if(current($art) != end($art)) {
$next= next($art);
else
$next= reset($art);
}
echo $next['title'];
?>">Next</a>

traq
05-22-2012, 01:33 AM
okay - so you're talking about doing this:
[result-set]
[row-1]
[title_id] // you're here
[whatever]
[row-2]
[title_id] // you want to go here next
[whatever]
// correct?

the first part of what Apache suggests is pretty much what I would suggest, if this assumption is correct.

The exception is that you can't use reset() and end() in the second part, because -well- they reset and end the array pointer when used.

kuau
05-22-2012, 01:43 AM
Not necessarily. The title_id's are assigned as new paintings are entered into inventory. The ones I started with are in alphabetical order but new paintings just get the next available number, so the title_id's in order do not present the titles in order. But that is not even that important. If someone is looking at a particular artist's art, they don't want to suddenly see another artist's work mixed in. Why can't I define an array that does not include the whole table?

ApacheTech
05-22-2012, 01:44 AM
reset() rewinds array's internal pointer to the first element and returns the value of the first array element.

end() advances array's internal pointer to the last element, and returns its value.

From http://www.php.net/manual/en/function.end.php

ApacheTech
05-22-2012, 01:52 AM
I take it your tblTitles table has fields as such:

title_id (AutoNumber)
artist_id (Lookup)
title (Text)

And is relationally joined to tblArtists so the artist_id matches up as a one-to-many relationship? (I'm assuming at least 3rd Normal Form)

Do you want your titles in alphabetical order, or in the order they appear in the database?


SELECT title, artist_id FROM tblTitles WHERE (artist_id = 1) ORDER BY title

Will return all titles by artist #1 in alphabetical order.


SELECT title_id, title, artist_id FROM tblTitles WHERE (artist_id = 1) ORDER BY title_id

Will return all titles by artist #1 in the order they appear in the database.

kuau
05-22-2012, 02:00 AM
Dear ApacheTech: Yes, here is my query...


SELECT * FROM title WHERE artist_id=1 ORDER BY title

It is a very simple array. I do NOT want them ordered by title_id, which is what I have been stuck with for the past year. I am not very conversant with functions so I am trying to follow your code, which appears to be on the right track. Please explain what this means exactly...

function mysql_fetch_all($res) {
while($row=mysql_fetch_array($res, MYSQL_BOTH)) {
$return[] = $row;
}
return $return;
}

$art = mysql_fetch_all($res);

Thanks :)

ApacheTech
05-22-2012, 02:10 AM
This example may explain it better. It's a much better way of achieving the same basic result.

While the mysql_fetch_all function creates a one dimensional array of each row as an object, this one deconstructs the whole (query) table into a multi-dimensional array.

I'm getting most of this from posts on the php.net site. I'm a .NET coder by trade, so little of this is second nature to me.



<?php

$query="select * from table_xyz";
$result = mysql_query($query) or die(mysql_error());
$arr_table_result=mysql_fetch_full_result_array($result);

function mysql_fetch_full_result_array($result)
{
$table_result=array();
$r=0;
while($row = mysql_fetch_assoc($result)){
$arr_row=array();
$c=0;
while ($c < mysql_num_fields($result)) {
$col = mysql_fetch_field($result, $c);
$arr_row[$col -> name] = $row[$col -> name];
$c++;
}
$table_result[$r] = $arr_row;
$r++;
}
return $table_result;
}

echo $arr_table_result[2]['id'];

?>


With your problem of ordering by the correct type, that's an issue with your SQL SELECT statement. The only thing I can think with that, is that you may be encountering a problem with your naming.


SELECT * FROM title WHERE artist_id=1 ORDER BY title
This looks like you're trying to order the data by the table name rather than a field name.

Can you give us a field list of the tables in the database, with the relations between the tables?

ApacheTech
05-22-2012, 02:22 AM
I would set the database up with the following tables:

tblArtists
artist_id (AutoNumber)
artist_name (Text)

tblTitles
title_id (Autonumber)
artist_id (Lookup = tblArtists.artist_id)
title (Text)
filename (Text)

With that set up, you can use:


SELECT T.artist_id, T.title, T.filename, A.artist_name
FROM tblArtists AS A, tblTitles AS T
WHERE (T.artist_id = "1")
ORDER BY T.title

To select all the information you need.

Next, use mysql_fetch_full_result_array($result) on the query to construct a multi-dimensional array of all the selected artist's work.

traq
05-22-2012, 02:25 AM
@kuau --
can you show us a sample of what your result set looks like? I think that would help clarify things.

About defining an array with only the rows you want, you certainly can do so. That's what Apache's first php block illustrates. As I mentioned, you can keep that array (instead of repeating the query on every request) by saving it to a session.

@ApacheTech --

right. so, say the pointer is currently at 0 (its starting position).
1. current( $art ) != reset( $art ) is FALSE.
2. skip to else{}, $prev = end( $art ). $prev will hold the last element of the array; that's what you wanted.

however, say the pointer is currently at 2 (maybe we used next() a few times).
1. current( $art ) != reset( $art ) is TRUE.
2. $prev = prev( $art ).
...*however*, reset() reset the pointer. when prev() is called, the pointer is at 0 again.
...$prev will hold FALSE, because you can't rewind the pointer past the beginning of the array.

to illustrate, try out these two variations:
$art = array( 1,2,3,4,5);
if(current($art) != reset($art)) {
$prev = prev($art);
}else{
$prev = end($art);
}
var_dump( $prev );
// int(5)

$art = array( 1,2,3,4,5);
next( $art ); // advance the pointer!
if(current($art) != reset($art)) {
$prev = prev($art);
}else{
$prev = end($art);
}
var_dump( $prev );
// bool(false)boy, this thread is moving fast! :)

ApacheTech
05-22-2012, 02:29 AM
Now you have your multi-dimensional array, you can traverse through it using next and prev.



<?php

$art = mysql_fetch_full_result_array($result);

$curr = current($art);

?>

<p><?php echo $curr['title']; ?> By <?php echo $curr['artist_name']; ?></p>
<img src="~/assets/images/<?php echo $curr['artist_name']; ?>/<?php echo $curr['filename']; ?>.jpg" title="<?php echo $curr['title']; ?>" alt="<?php echo $curr['title']; ?>" />

ApacheTech
05-22-2012, 02:33 AM
Traq, thanks for the clear up.

I was mainly using end and reet as a shortcut for looping back around the array to make it seamless and solve any stack-overflows / index falloffs. There are obviously other ways to do this.

How about:


$art = array( 1,2,3,4,5);
if($key(current($art)) != 0) {
$prev = prev($art);
}else{
$prev = end($art);
}
var_dump( $prev );
// int(5)

if($key(current($art)) != (count($art) - 1)) {
$next= next($art);
}else{
$next= reset($art);
}
var_dump( $next);
// int(1)

traq
05-22-2012, 03:02 AM
yup. Might do $last = count($art)-1 and save time in case you ever need to use it elsewhere.

kuau
05-26-2012, 12:06 AM
Dear Traq & ApacheTech: Just so you know I tried to thank you guys but there is a bug in the forum software due to an upgrade. And then I was taken away for awhile. Now I am back. To answer some of your questions...

1. In the `title` table `title` is the name of a field as well. An example of a title would be 'A Quiet Moment.'
2. Your table structures are correctly like mine.
3. $art['filetag'] is a string, eg. a-quiet-moment (it is the filename of the image without the .jpg)
4. The way you have described prev(), next(), current(), end(), reset() is exactly how I want it to work advancing the array pointer each time.

In your code...

<a href="/php/art-detail.php?title_id=<?php
if(current($art) != reset($art)) {
$prev = prev($art);
else
$prev = end($art);
}
echo $prev['title'];
?>">Previous</a>

<!-- code to display current($art) image here -->

<a href="/php/art-detail.php?title_id=<?php
if(current($art) != end($art)) {
$next= next($art);
else
$next= reset($art);
}
echo $next['title'];
?>">Next</a>

I'm not sure what values $art has. It would have to contain a title_id (eg. 102) for the page to change, as that is how I have defined the query string, but the next() would find the next title in alphabetical order for that artist and then use the title_id that goes with that title. Not sure how to keep that straight which is why I tried using the file_tag with next and prev. Maybe it will help to see one of the actual pages... a picture is worth a thousand words and all that...

http://www.costgallery.com/php/art-detail.php?title_id=2

ApacheTech
05-26-2012, 01:13 AM
$art is a multidimensional array of all the fields from your query.

I don't know if it would make any difference, but you could prefix your table with tbl to distinguish the table names from the field names. I've always used a watered down version of the Hungarian Naming Method when coding to distinguish between types. so you title table would become tblTitles, and so on.

kuau
05-26-2012, 01:34 AM
I don't have any problem confusing the table names with the field names. It would be a huge job renaming everything. It does not interfere with the functioning. Please try to bear with my conventions. I guess I could refer to it your way for the purposes of this thread.

Are you saying that current($art) is a list of field names? Perhaps I did not make myself clear. The NEXT and PREV buttons go to totally separate pages based on the title_id of the next and prev record in the array of title records from the tblTitle table that results from this command...


sql = "SELECT * FROM tblTitle WHERE artist_id='1' ORDER BY `title` ASC";

What is a multi-dimensional array?

djr33
05-26-2012, 01:50 AM
a multi-dimensional array is one with more than one layer. So it's not a list of strings, but a list of lists-- an array of arrays.

$a['b']['c'] -- two levels, or "two dimensions".