Situation: I made a script which reads data from a database and renders it so that it can be manipulated by jQuery UI into tabs.
The Code:
function renderTabs(){
$_db = array(
'host' => MYSQL_HOST,
'user' => MYSQL_USER,
'password' => '',
'database' => DB
);
$_channels = array(
'chan1' => 'db1',
'chan2' => 'db2',
'chan3' =>'db3',
'chan4' => 'db4'
);
$html = '';
$conn = new mysqli($_db['host'],$_db['user'],$_db['password'],$_db['database']);
$html .= '<div id="tabs">
<ul>';
foreach ($_channels as $i => $channel){
while($chan = current($_channels)){
echo $tab = array_search($chan,array_values($_channels));
$html .= '<li><a href="#tabs-'.$tab.'">'.array_keys($_channels)[$tab].'</a></li>';
next($_channels);}
$html .= '</ul>';
$n_tab = array_search($i,array_keys($_channels));
$n_tab++;
$results = $conn->query('SELECT * FROM table_test WHERE date BETWEEN (CURDATE() - INTERVAL 7 DAY) AND CURDATE() AND channel = \''.$channel.'\' GROUP BY id ORDER BY total DESC LIMIT 10');
$html .= '<div id="tabs-'.$n_tab.'">
<table style="width:100%">
<tr><td>TEST</td>
<td>TEST COL1</td>
<td>TEST COL2</td>
<td>TEST COL3</td>
<td>TEST COL4</td></tr>';
foreach($results as $row){
$html .= '<tr><td><a href="'.$row['url'].'">'.$row['title'].'</a></td>
<td>'.$row['data1'].'</td>
<td>'.$row['data2'].'</td>
<td>'.$row['data3'].'</td>
<td>'.$row['data4'].'</td></tr>';
}
$html .= '</table></div>';
}
$html .= '</div>';
return $html;
}
The HTML structure that jQuery UI needs to render the tabs:
<div id="tabs">
<ul>
<li><a href="#tabs-1">tab1_title</a></li>
<li><a href="#tabs-2">tab2_title</a></li>
<li><a href="#tabs-3">tab3_title</a></li>
</ul>
<div id="tabs-1">
<p>content1</p>
</div>
<div id="tabs-2">
<p>content2</p>
</div>
<div id="tabs-3">
<p>content3</p>
</div>
</div>
The Questions: I have one problem and one doubt. The problem is that only 3 out of 4 tabs are rendered (while all four contents are correctly generated) and i don't know why.
I also tried using each() like this:
while($chan = each($_channels)){
echo $chan[1];
print_r(array_values($_channels));
echo $tab = array_search($chan[1],array_values($_channels));
$html .= '<li><a href="#tabs-'.$tab.'">'.array_keys($_channels)[$tab].'</a></li>';}
But to no avail.
The doubt: I did the above trying to avoid cycling through the array again, and also because i want to be able to add or remove tabs (along with their generated content) only by adding elements to the $_channels array. Is there any convinient way to achieve this without having to iterate twice?
Thanks for your support in advance.
EDIT: I might have found the problem, seems the foreach shifts the internal pointer of $_channels by one, and that's why current() loop returns 3 elements instead of 4. I know about reset(), but it's useless here..
EDIT2: It really is a PHP problem, Manual says:
Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
So, how can i reset the pointer without breaking the rest of the code?
To be tested, but here's a way that might work for you :
The trick is to split the formatting and the data gathering. Split your 2 sections into 2 arrays and make then whole once you've recovered everything.
function renderTabs(){
$_db = array(
'host' => MYSQL_HOST,
'user' => MYSQL_USER,
'password' => '',
'database' => DB
);
$_channels = array(
'chan1' => 'db1',
'chan2' => 'db2',
'chan3' =>'db3',
'chan4' => 'db4'
);
$html = '';
$ul = array();
$tabs = array();
$tab = 0;
$conn = new mysqli($_db['host'],$_db['user'],$_db['password'],$_db['database']);
foreach ($_channels as $i => $channel){
$ul[] = '<li><a href="#tabs-'.++$tab.'">'.$channel.'</a></li>';
$results = $conn->query('SELECT * FROM table_test WHERE date BETWEEN (CURDATE() - INTERVAL 7 DAY) AND CURDATE() AND channel = \''.$channel.'\' GROUP BY id ORDER BY total DESC LIMIT 10');
foreach($results as $row){
$tabs[] = '<div id="tabs-'.$tab.'">
<table style="width:100%">
<tr><td>TEST</td>
<td>TEST COL1</td>
<td>TEST COL2</td>
<td>TEST COL3</td>
<td>TEST COL4</td></tr>
<tr><td><a href="'.$row['url'].'">'.$row['title'].'</a></td>
<td>'.$row['data1'].'</td>
<td>'.$row['data2'].'</td>
<td>'.$row['data3'].'</td>
<td>'.$row['data4'].'</td></tr>
</table></div>';
}
}
$html .= '<div id="tabs">';
$html .= "<ul>" . implode($ul). "</ul>";
$html .= implode($tabs);
$html .= '</div>';
return $html;
}