Link to home
Start Free TrialLog in
Avatar of MaybeItsJeremy
MaybeItsJeremy

asked on

Smarty: Several foreach loops within loops based on division of a given variable

The title probably doesn't make any sense at all, so I'll explain it like this:

I am going to be retrieving entires from my database and I want to format them so only 5 entires can go into each cell. Each row will have two cells, and like I said, 5 entires in each cell.

So, an example of the output would be:

_____________________       _____________________
|         Entry 1               |      |         Entry 6               |
|         Entry 2               |      |         Entry 7               |
|         Entry 3               |      |         Entry 8               |
|         Entry 4               |      |         Entry 9               |
|         Entry 5               |      |         Entry 10             |
_____________________      _____________________

_____________________       _____________________
|         Entry 11              |      |         Entry 16             |
|         Entry 12              |      |         Entry 17             |
|         Entry 13              |      |         Entry 18             |
|         Entry 14              |      |         Entry 19             |
|         Entry 15              |      |         Entry 20             |
_____________________      _____________________

..... etc...

And of course, I need it to show a cell with   if there is an uneven number of cells. And naturally, if the last cell has only say... 3 entires, I don't want the script to mess up... I would just need it to show those 3 if that's all there is.

I would prefer using the foreach Smarty function, rather than section (foreach uses much less code when the template is compiled)

Any help is greatly appreciated! :)
Avatar of fulscher
fulscher

I'm not familiar with smarty, but using standard PHP you'd do something like the following: (sorry, not tested, I'm in a hurry, but you'll see the idea):

/* We want to display the data in the following structure:
<table>
  <tr>
        <!-- first column>
    <td>
          <table>
                <tr><td>VALUE1</tr></td>
                <tr><td>VALUE2</tr></td>
                <!-- etc., always 5 rows, use blank fields if table is empty -->
          <table>
    </td>
        <!-- second column, always present, even if there are no more records>
    <td>
          <table>
                <tr><td>VALUE1</tr></td>
                <tr><td>VALUE2</tr></td>
                <!-- etc., always 5 rows, use blank fields if table is empty -->
          <table>
    </td>
  </tr>
</table>

-- then next table with the same structure
*/


<?php
$result = mysql_query("SELECT * FROM tablename") or die("Sql error: " . mysql_error());

echo "<table>";
$recordpos = 0;
$recordcount = 0;
$row = TRUE;

while ($row)
{
      // create a new outer table and create first column
      echo "<table><tr><td>"
      // create new inner table
      echo "<table>";
  // create rows
  for ($i = 0; $i < 5; $i++)
  {
        $row = mysql_fetch_array($result); $value = ($row ? $row['field']; "");
        echo "<tr><td>";
        echo $value;
        echo "</td></tr>";
  }      
  // close table and first column
  echo "</table></td>";
  // create second column and inner table
      echo "<td><table>";
  // create rows
  for ($i = 0; $i < 5; $i++)
  {
        $row = mysql_fetch_array($result); $value = ($row ? $row['field']; "");
        echo "<tr><td>";
        echo $value;
        echo "</td></tr>";
  }      
  // close table and second column and outer table
  echo "</table></td></tr></table>";
}
?>
Avatar of MaybeItsJeremy

ASKER

That doesn't exactly work.... It reproduces the same row 10 times before going to the new set... Sorta like this:

1          1
1          1
1          1
1          1
1          1

2          2
2          2
2          2
2          2
2          2

The same content is in both cells and it just repeats...... Thanks for your help so far though!
hi MaybeItsJeremy,

This is a PHP only example at the moment, i will convert it to Smarty syntax once i know that it gives you the expected output....

------------------------------------------------------------

<table cellpadding="5" cellspacing="5">
<?php
$query = mysql_query('SELECT fieldname FROM tablename') or die(mysql_error());
while ($row = mysql_fetch_array($query)) $data[] = $row[0];

$i = 0;
$flag = 1;

while ($i < count($data)) {
 
 if ($flag == 1) echo "<tr>\n";
 
 echo "<td>\n";
 for ($j=0;$j<5;$j++) {
  echo (empty($data[$i])) ? "&nbsp;<br>\n" : "{$data[$i]}<br>\n";
  $i++;
 }
 echo "</td>\n";
 
 $flag = ($flag == 1) ? 0 : 1;
 if ($flag == 1) echo "</tr>\n";

}
?>
</table>

------------------------------------------------------------

Diablo84
Sorry - I was a bit too hurried. Again - tested and a bit shorter, still easy to understand:

  // connect to the mysql database server.
  $link_id = mysql_connect ($dbhost, $dbusername, $dbuserpass);

  // select the specific database name we want to access.
  // $dbname=$dbusername."_".$dbname;
  if (!mysql_select_db($dbname)) die(mysql_error());    


  $result = mysql_query("SELECT * FROM ee") or die("Sql error: " . mysql_error());
 
  echo "<table>";
  $recordpos = 0;
  $recordcount = 0;
  $row = TRUE;
 
  while ($row)
  {
         // create a new outer table and create first column
         echo '<table><tr><td><table>';
        
         for ($i = 0; $i < 10; $i++)
         {
                     if ($i == 5)
                              echo '</table></td><td><table>'; // close left-hand, open right-hand table
      
                        $row = mysql_fetch_array($result);
                        $value = ($row ? $row['Field1'] : "&nbsp;");
                        echo '<tr><td>' . $value . '</td></tr>';
              }
     echo "</table></td>";
  }
?>
... and of course, you can leave away the statements
  $recordpos = 0;
  $recordcount = 0;
they aren't necessary any more.
fulscher,

Why have you followed up with this post?

This question is based around smarty which you have said you are not familiar with.

Further more i have already posted a working PHP only solution above, i fail to see the benefit of posting a script with output that features no less then 7 tables! with the sample data when there is only need for one.

Diablo84
Excuse me?

MaybeItsJeremy indicated that my solution did not work, which was true, so I sent an updated version which does work as intended.

You're solution is a good one, agreed, but it's not very easy to understand. Adapting it to MaybeItsJeremy's needs will be complicated because of the extremly dense code. You need to read in all data into a temporary array which is much more expensive on the server side than spitting out the data as it comes. You have yet to show that your solution is better than mine.

Let MaybeItsJeremy decide what he likes best and what satisfies his needs best.
The output of your code speaks for itself:

<table><table><tr><td><table><tr><td>testdata</td></tr><tr><td>testdata</td></tr><tr><td>testdata</td>
</tr><tr><td>testdata</td></tr><tr><td>testdata</td></tr></table></td><td><table><tr><td>testdata</td>
</tr><tr><td>testdata</td></tr><tr><td>testdata</td></tr><tr><td>testdata</td></tr><tr><td>testdata</td>
</tr></table></td><table><tr><td><table><tr><td>testdata</td></tr><tr><td>testdata</td></tr><tr>
<td>testdata</td></tr><tr><td>testdata</td></tr><tr><td>testdata</td></tr></table></td><td><table>
<tr><td>testdata</td></tr><tr><td>testdata</td></tr><tr><td>testdata</td></tr><tr><td>&nbsp;</td>
</tr><tr><td>&nbsp;</td></tr></table></td>

Line breaks added by yours truly to avoid causing problems with the EE page width.

And you are still missing the point, you have posted in a question regarding Smarty when you have said you do not know what Smarty is. My point was, what were your plans when it comes to converting the code to Smarty syntax?

Diablo84
Thanks for pointing it out: The most outer "<table>"s were a bit messy. So, my last entry in what turns into some kind of beauty contest is:

  $result = mysql_query("SELECT * FROM ee") or die("Sql error: " . mysql_error());
  $row = TRUE;
  while ($row)
  {
      echo "\n<table><tr><td>\n<table>";
        
      for ($i = 0; $i < 10; $i++)
      {
      if ($i == 5)
            echo "</table></td>\n<td><table>"; // close left-hand, open right-hand table
      
      $row = mysql_fetch_array($result);
      $value = ($row ? $row['Field1'] : "&nbsp;");
      echo "\n\t<tr><td>" . $value . '</td></tr>';
    }
     echo "\n</table></td>";
  }
  echo "</table>";
?>

I've added some newlines to make you happy.

Diablo84 - what's the problem? I was the first to post something on the Q because I had an idea how to solve a part of the problem. Maybe somebody else would add another bit, so we would end up with a functioning solution.

Unfortunately, I had to hurry, so my post wasn't working as expected. MaybeItsJeremy pointed this out and I fixed my post. You pointed out another problem and I fixed this again. What are you worried about? I'm quite sure that MaybeItsJeremy will assign you the points if and when you've earned them.

You STILL miss the point. This question is regarding Smarty, which does not use standard syntax.

So, AGAIN you have posted in a question about something you are not familiar with... and to top it all off, you post another snippet of code which still unnecessarily uses nested tables.

My concern is filling the PAQ with good answers, not the points. Instead you have now managed to post three poor standard snippets of code which do not address the question.

Diablo84
Ok, tried using:

<table cellpadding="5" cellspacing="5">
<?php
$query = $sql->execute('SELECT name FROM se_custom_profile_fields');
while ($row = $sql->fetch($query)) $data[] = $row[0];

$i = 0;
$flag = 1;

while ($i < count($data)) {
 
 if ($flag == 1) echo "<tr>\n";
 
 echo "<td>\n";
 for ($j=0;$j<5;$j++) {
  echo (empty($data[$i])) ? "&nbsp;<br>\n" : "{$data[$i]}<br>\n";
  $i++;
 }
 echo "</td>\n";
 
 $flag = ($flag == 1) ? 0 : 1;
 if ($flag == 1) echo "</tr>\n";

}
?>
</table>


And all I get is the &nbsp; in the cell.... and in addition to that, right now I have 12 rows in the database, the result is something along the lines of:

&nbsp;      &nbsp;
&nbsp;      &nbsp;
&nbsp;      &nbsp;
&nbsp;      &nbsp;
&nbsp;      &nbsp;


&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;


There's no second column on the second row. When something like that happens, I need to at least have the cell with one &nbsp; in it, so it doesn't mess up the design.


And if it's worth meantioning, I am using mysqli for this. The database class I am using above executes the query, and the fetch function uses mysqli_fetch_array().
Does your class return an associative array?

If so you would use:

while ($row = $sql->fetch($query)) $data[] = $row['name'];

instead of:

while ($row = $sql->fetch($query)) $data[] = $row[0];

Diablo84
Ok, that got it to work. Now if we could just get the second column on the second row working.... Basically, there always must be two cells on each row. Even if one has nothing to display, it can have &nbsp; for it's content.
Adding:

$count = count($data);
$cells = floor($count/5);
if ($count%5 > 0) $cells++;

if ($cells%2 == 1) echo "<td>&nbsp;</td>\n</tr>\n";

just after the closing } should fix that for now.

Diablo84
Ok, that's working fine now. One question I have though is how could I get this to work for multiple fields in the DB table? So, instead of "SELECT name FROM se_custom_profile_fields", I'd like to use "SELECT id, name FROM se_custom_profile_fields"

And then in the table cell loop, use something like:

<a href="http://linkto/{$row['id']}">{$row['name']</a>

If I need to edit my DB class file to do so, I will.... Here's what the fetch function currently looks like:

    function fetch($query_id = "") {
   
          if ($query_id == "")
          {
                $query_id = $this->query_id;
          }
          
        $this->record_row = mysqli_fetch_array($query_id, MYSQLI_ASSOC);
       
        return $this->record_row;
       
    }
Ok, nevermind that last comment... Got it working:

<table cellpadding="5" cellspacing="5">
<?php
$query = $sql->execute('SELECT * FROM se_custom_profile_fields');
while ($row = $sql->fetch($query)) $data[] = $row;

$i = 0;
$flag = 1;

while ($i < count($data)) {
 
 if ($flag == 1) echo "<tr>\n";
 
 echo "<td>\n";
 for ($j=0;$j<5;$j++) {
  echo (empty($data[$i])) ? "&nbsp;<br>\n" : "{$data[$i]['name']}<br>\n";
  $i++;
 }
 echo "</td>\n";
 
 $flag = ($flag == 1) ? 0 : 1;
 if ($flag == 1) echo "</tr>\n";

}

$count = count($data);
$cells = floor($count/5);
if ($count%5 > 0) $cells++;

if ($cells%2 == 1) echo "<td>&nbsp;</td>\n</tr>\n";

?>
</table>


Now if I can get it to work with Smarty, I'll be all set. :)
Ok excellent, il work on the Smarty conversion a little later. I have a few other tasks i have to work on first then il get on it.

Diablo84
ASKER CERTIFIED SOLUTION
Avatar of Diablo84
Diablo84

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Awesome! Works perfect, Diablo! Thank you again! :)
No problem once again :)

Diablo84