Loop with a while - php

Very basic question.. but I'm missing the point.. I have this data on my table:
ID SITEID SECTION
1 1 posts
2 2 posts
3 1 aboutme
4 1 contact
5 2 questions
The output is an array. I can't change it.
I want to make this output on php with a single for loop with that array:
<h1> sections for site 1 </h1>
posts
aboutme
contact
<h1>sections for site 2 </h1>
posts
questions
I'm trying to do something like this, where $sectionsArray is my output. And I want to check if siteid is the same, then make a loop..
for ($j = 0; $j < sizeof($sectionsArray); $j++) {
while (siteid == 1) {
echo '<h1>' . $sectionsArray['siteid'] . '</h1>';
}
echo "' . $sectionsArray['section'] . ';
}
But I don't get the logic of "grouping" the results with a while.. INSIDE a loop. Any light will be welcome.
Thanks

You can't really do this with just 1 loop, assuming you can't change the query. As you for loop through $sectionsArray, you have to deal with each row as you encounter it. It doesn't matter if you only want sections for site 1, you'll still encounter sections for site 2, 3, etc & either ignore them or deal with them.
If you can change your query, have it order by SITEID, then ID. That'll group all sections by site (note: this is not the same as using the SQL GROUP BY statement).
If you can't change your query, use your for loop to iterate through $sectionsArray once. In that loop, build a second array with the different sections ordered by site id. Iterate through that second array to output all the sections which are now in site id order.

Quick and dirty ;)
<?php
$arr = array(
array('id' => 1, 'site_id' => '1', 'section' => 'posts'),
array('id' => 2, 'site_id' => '2', 'section' => 'posts'),
array('id' => 3, 'site_id' => '1', 'section' => 'aboutme'),
array('id' => 4, 'site_id' => '1', 'section' => 'contact'),
array('id' => 5, 'site_id' => '2', 'section' => 'questions')
);
$htmlStrings = array();
$curr_site_id = '0';
foreach($arr as $item)
{
if ( $item['site_id'] != $curr_site_id )
{
$curr_site_id = $item['site_id'];
if ( !isset($htmlStrings[$curr_site_id]) ) $htmlStrings[$curr_site_id]['header'] = '<h' . $curr_site_id . '>Sections for site ' . $curr_site_id . '</h' . $curr_site_id . '>';
$htmlStrings[$curr_site_id]['content'] .= '<br />' . $item['section'];
}
else
{
$htmlStrings[$curr_site_id]['content'] .= '<br />' . $item['section'];
}
}
foreach($htmlStrings as $section)
{
echo $section['header'];
echo $section['content'];
}

If you want to do one pass on the array, first sort (technically, that's also a pass!) and then check for a change in siteid as you loop through it. Here's how you can sort the array by siteid before looping through it:
$sections = array(
array('id'=>1, 'siteid'=>1, 'section'=>'posts'),
array('id'=>2, 'siteid'=>2, 'section'=>'posts'),
array('id'=>3, 'siteid'=>1, 'section'=>'aboutme'),
array('id'=>4, 'siteid'=>1, 'section'=>'contact'),
array('id'=>5, 'siteid'=>2, 'section'=>'questions'),
);
usort($sections, 'sortBySiteId');
function sortBySiteId($a, $b)
{
if ($a['siteid'] == $b['siteid']) {
return 0;
}
return ($a['siteid'] < $b['siteid']) ? -1 : 1;
}

thanks.. but I ended up doing this:
for ($j=0;$j<sizeof($sectionArray);$j++) {
$section_id = $sectionArray[$j]['id'];
$section_name = $sectionArray[$j]['secao'];
echo '<div id="menu">';
echo '<div class="section">'.$section_name.'</div>';
$categoryArray = $objectCategory->listCategory($section_id); // return my array from db
for ($ii=0;$ii<sizeof($categoryArray);$ii++) {
$categoryId = $categoryArray[$ii]['id'];
$categoryName = $categoryArray[$ii]['category'];
echo "<div class=\"item\">";
echo "$categoryName";
echo "</div>";
}
echo '</div>';
}
Is that ok? I mean, I have some problems with arrays... :(
But thanks anyway

Related

Using the array_unique() function to remove the duplicated MYSQLI records without relying on SQL to do that

I know this is a strange question but I need to do this for personal reasons so I converted MYSQLI records into an array but I want to use PHP array_unique() function on the array that contains the MYSQLI
records to remove any duplicated values in that array without relying on any SQL commands to remove the duplicated records.
I tried many times on how I can do this and I failed many times. The code example below has no errors because I removed my failed attempts.
This is my code
<?php
$db_servername_1='localhost';
$db_username_1= 'jd';
$db_password_1= '1234';
$db_name_1= 'test';
$db_connect_1= new mysqli($db_servername_1,$db_username_1,$db_password_1,$db_name_1);
$db_query_1= "SELECT*FROM records ORDER BY id DESC LIMIT 4";
$db_result_1= $db_connect_1->query($db_query_1);
while($db_row_1= $db_result_1->fetch_assoc()){
$items[] = $db_row_1;
}
$items = array_reverse($items ,true);
foreach($items as $item){ ?>
<h1><?php echo $item['id']; ?></h1>
<?php
}
?>
and this is the output 101,102,103,103.
if I find a way on how I can do this then the array output will look like this
instead 101,102,103 so how can I do this?
Use array_column in conjunction with array_unique to get unique IDs.
$items =
[
['id' => 1, 'text' => 'foo'],
['id' => 10, 'text' => 'bar'],
['id' => 10, 'text' => 'bar2'],
['id' => 3, 'text' => 'baz'],
];
foreach(array_unique(array_column($items, 'id')) as $k=>$id)
echo $id, ' => ', $items[$k]['text'], PHP_EOL
;
output
1 => foo
10 => bar
3 => baz
Two options for you here.
First, if what you've shown is all you're doing with the $items array, then only store the IDs in there, and then array_unique will work for you:
while($db_row_1= $db_result_1->fetch_assoc()){
$items[] = $db_row_1['id'];
}
$items = array_reverse(array_unique($items));
If you go on to do other things with the $items, then only put unique items into that array:
while($db_row_1= $db_result_1->fetch_assoc()){
if (!array_key_exists($db_row_1['id'], $items)) {
$items[$db_row_1['id']] = $db_row_1;
}
}
Try this:
<?php
$query = "your query here";
$resultset = $db_connect_1->query($query);
$data_array = array();
while($current = $resultset->fetch_array()){
array_push($data_array, $current['id']);
}
$non_duplicates_array = array_unique($data_array);
foreach ($non_duplicates_array as $current_id) {
echo $current_id;
}

PHP array output just first value

I am trying to write data from MySQL to PHP-Array (to generate a XML file with the PHP library FluidXML ). When I echo the array, I only get the first value of it, but when I echo a variable with the same data as the array I get correct output with all the information. Let me explain more exactly:
The query to get data:
$sql = sprintf("select b.nPosID, b.nAmount, b.sName, .......");
$result = mysql_query($sql);
Then I loop trough the results:
$msg = "";
$orderArticles = [];
$orderSubArticles = [];
while($data = mysql_fetch_array($result))
{
if($data['sChange'] != null) {
$msg .= ' * ' . $data['sChange'] . ' ' . number_format($data['nAmount'] * $data['nPriceChange'], 2) . "\r\n";
$orderSubArticles[] = ['SubArticle' => [
'ArticleNo' => '0',
'ArticleName' => $data['sChange'],
'Count' => $data['nAmount'],
'Price' => $data['nPriceChange']
],];
}
if ($nPosID != $data['nPosID']) {
$msg .= " \r\n" . $data['nAmount'] . ' x ' . $data['sName'] . ' ' . number_format($data['nAmount'] * $data['nPrice'], 2) . "\r\n";
$orderArticles[] = ['Article' => [
'ArticleNo' => '0',
'ArticleName' => $data['sName'],
'ArticleSize' => '0',
'Count' => $data['nAmount'],
'Price' => $data['nPrice'],
'Tax' => '10',
'SubArticleList' => [
$orderSubArticles
]],];
}
}
Let's assume, from the SQL query I get the following correct output:
Pizza
+ extra cheese
+ extra tonno
When I echo $msg variable, I get the same correct result. But when I echo the array, I only get the first value:
Pizza
+ extra cheese
To be exactly, the output which was generated with the values from the array:
<ArticleList>
<Article>
<ArticleName>Pizza</ArticleName>
<Count>1</Count>
<Price>12.9</Price>
<SubArticleList>
<SubArticle>
<ArticleName>Extra cheese</ArticleName>
<Count>1</Count>
<Price>3</Price>
</SubArticle>
</SubArticleList>
</Article>
</ArticleList>
So the second <SubArticle> is missing (extra tonno).
Without knowing how your resultset really looks like, I am doubting your assumption is correct, that a result/row in the set really contains both subarticles. That would lastly mean all results have two subarticles and that's supposingly not the case, because then it would need to return something like sChange1, sChange2 ...
Even if the results would look something like that and contain two or more sub articles, your code only assigns one of them to the subArticles-array per result.

Gravity Forms get field entries

A logged in user fills out a form several times. From his entries, I'm attempting to get all of his inputs for a specific field and put them into a PHP array.
For the sake of simplicity, assume the form has ID 10 with the first field called 'SomeField' and the user was logged in (and is still logged in) for all entries.
Here's my best attempt at creating an array of all SomeField entries from the user:
get_currentuserinfo();
$searchCriteria = array(
array(
'key' => 'created_by',
'value' => $current_user->user_login
),
array(
'key' => '1',
'value' => 'SomeField'
),
);
$form = GFAPI::get_entries( 10, $searchCriteria );
echo print_r($form);
Unfortunately, this print_r appears to display an empty array. I believe my searchCriteria is somehow incorrect.
I found it's easier to omit the second parameter ($searchCriteria) and simply use $form[0]['1'] for example which will display the first field of the first entry of the specified form.
I found with user23058230 great solution in the second answer I always got the latest form created, which worked well for new signups but not later on.
Assuming here that the form ID is number 1, you can search it with a for loop using the entry_id which is available in the user's login array as
$current_user->entry_id
No search query is needed other than the form you want returned - in this case form #1.
You can search other items using the keys you can see from your array dump.
Great solution which with the addition of this code solved my problem.
$form = GFAPI::get_entries( 1, '');
$what_i_want = 0;
for( $i = 0; $i < count($form); $i++ ){
if( $form[$i]['id'] == $current_user->entry_id ){
// the item I want
$what_i_want = $form[$i]['22'];
//echo " I " . $form[$i]['id'] . " F " . $form[$i]['22'] . " i " . $i . " T " . $what_i_want . '<br />';
break;
}
}

How to split an array into two table rows "<tr>" within one foreach on template side

Due to working with a restricted working environment, I need to put half of this array into one table row and another half into another .
This is the array (already sorted in order of what I need):
Array
(
[product] => KFE-1221
[description] => Classic Blue
[current_stock] => 630
[purchase_order] =>
[total_sales] => 0
[avail_to_sell] => 630
[size_run1] => 15
[size_run2] => 62
[size_run3] => 122
[size_run4] => 113
[size_run5] => 102
[size_run6] => 92
[size_run7] => 63
[size_run8] => 61
[size_run9] => 0
[size_run10] => 0
)
I need to split the array at "size_run1" - "size_run10" into a separate table row.
Previously, I had this to display the array into a table (standard foreach) when I didn't need the size_run. Due to request I am adding it in. (And yes I am using deprecated php)
<?php
while($data = mssql_fetch_assoc($result_ats)) {
if ($data['avail_to_sell'] <= 0){
echo '<tr class="error">';
}
else {
echo '<tr>';
}
foreach($data as $k => $v){
echo '<td>'.$v.'</td>';
echo '</tr>';
}
}
?>
The reason I want to keep it as one array is because I am using one query for all the information, and with the huge database that I'm working with, it makes more sense for me to split this up on template side rather than have separate arrays and add a process of matching the product to the size_run.
What is the best way of doing this without having the split the array up into different arrays?
My desired output, which is to split up array '$v' into two separate tables like below:
<tr>
<th>product</th>
<th>description</th>
<th>current_stock</th>
<th>purchase_order</th>
<th>total_sales</th>
<th>avail_to_sell</th>
</tr>
<tr>
<th>size_run1</th>
<th>size_run2</th>
<th>size_run3</th>
<th>size_run4</th>
<th>size_run5</th>
<th>size_run6</th>
<th>size_run7</th>
<th>size_run8</th>
<th>size_run9</th>
<th>size_run10</th>
</tr>
Something like this:
$firstRow = array('product', 'description', 'current_stock', 'purchase_order', ... );
$secondRow = array('size_run1', 'size_run2', 'size_run3', ... );
while($data = mssql_fetch_assoc($result_ats)) {
echo '<tr>';
foreach($firstRow as $key){
echo '<td>' . $data[$key] . '</td>';
}
echo '</tr>';
echo '<tr>';
foreach($secondRow as $key){
echo '<td>' . $data[$key] . '</td>';
}
echo '</tr>';
}
Still maintainable if you want to change the keys.
I would still make a new array and then destroy it if you don't need it.
$newArray = array();
foreach($array as $key=>$value){
$pos = strpos($key, "size_run");
if($pos!==false){
$newArray[$key] = $value;
}
}

Adjacency tree from single table

I've read a lot of people discussing nested lists, but I was wondering how to iterate through an adjacancy list/tree in PHP.
I have a table with: id, title, parent_id
And I've selected all records out into an array called $pages.
Then using this php:
function makeList($pages, $used) {
if (count($pages)) {
echo "<ul>";
foreach ($pages as $page) {
echo "<li>".$page['pag_title'];
$par_id = $page['pag_id'];
$subsql("SELECT * FROM pages WHERE pag_parent = ".$par_id."");
// running the new sql through an abstraction layer
$childpages = $dbch->fetchAll();
makeList($childpages, $used, $lastused);
echo "</li>";
}
echo "</ul>";
}
}
This sort of works but I end up with any sub menu being repeated e.g.
HomeNewsSub-newsArticlesArticleNewsSub-newsArticlesArticleSub-newsArticle
I've tried adding the current id into an array that gets passed through the function, and then using in_array to check if it's there, but I have had no joy doing that.
Any help would be much appreciated.
I need to parse the whole tree so choosing parent as 0 isn't an option
Since it already does the SQL, you dont have to do it outside before the first function call.
function makeList($par_id = 0) {
//your sql code here
$subsql("SELECT * FROM pages WHERE pag_parent = $par_id");
$pages = $dbch->fetchAll();
if (count($pages)) {
echo '<ul>';
foreach ($pages as $page) {
echo '<li>', $page['pag_title'];
makeList($page['pag_id']);
echo '</li>';
}
echo '</ul>';
}
}
For storing it more tree like you might want to look at this site: Storing Hierarchical Data in a Database.
If you create an array of pages grouped by parent id it is quite easy to recursively build the list. This will only require one database query.
<?php
//example data
$items = array(
array('id'=>1, 'title'=>'Home', 'parent_id'=>0),
array('id'=>2, 'title'=>'News', 'parent_id'=>1),
array('id'=>3, 'title'=>'Sub News', 'parent_id'=>2),
array('id'=>4, 'title'=>'Articles', 'parent_id'=>0),
array('id'=>5, 'title'=>'Article', 'parent_id'=>4),
array('id'=>6, 'title'=>'Article2', 'parent_id'=>4)
);
//create new list grouped by parent id
$itemsByParent = array();
foreach ($items as $item) {
if (!isset($itemsByParent[$item['parent_id']])) {
$itemsByParent[$item['parent_id']] = array();
}
$itemsByParent[$item['parent_id']][] = $item;
}
//print list recursively
function printList($items, $parentId = 0) {
echo '<ul>';
foreach ($items[$parentId] as $item) {
echo '<li>';
echo $item['title'];
$curId = $item['id'];
//if there are children
if (!empty($items[$curId])) {
makeList($items, $curId);
}
echo '</li>';
}
echo '</ul>';
}
printList($itemsByParent);
Where is $page coming from? You might have an sql injection vulnerability in your code if you're not escaping it or using a prepared statement.
Also the SELECT statement inside a for loop jumps out as a bad practice. If the table is not that big, then select the contents of the entire table and then iterate through the result set in PHP to build the tree data structure. This could take up to n*(n-1)/2 iterations in the pathological case of your tree being a linked list. Stop when all nodes have been added to the tree, or the number of remaining nodes remains the same from one iteration to the next - this means the remaining nodes are not children of your root node.
Alternatively, if your database supports recursive SQL queries, you can use that, and it will only select the nodes that are children of your parent node. You will still have to build the tree object yourself in PHP. The form of the query would be something like:
WITH temptable(id, title, parent_id) AS (
SELECT id, title, parent_id FROM pages WHERE id = ?
UNION ALL
SELECT a.id, a.title, a.parent_id FROM pages a, temptable t
WHERE t.parent_id = a.id
) SELECT * FROM temptable
Substitute the '?' on the second line with the starting page ID.
The simplest fix would just be, when you are doing the initial select to set $pages (which you don't show), add a WHERE clause like:
WHERE pag_parent = 0
(or IS NULL, depending how you're storing "top level" pages).
That way you won't select all the children initially.
When that table gets large, recursion can get unwieldy. I wrote an blog post about a recursion-less method: http://www.alandelevie.com/2008/07/12/recursion-less-storage-of-hierarchical-data-in-a-relational-database/
Finding top parent, all parents, and all children of a node (enhancements for Tom Haigh's answer):
<?php
//sample data (can be pulled from mysql)
$items = array(
array('id'=>1, 'title'=>'Home', 'parent_id'=>0),
array('id'=>2, 'title'=>'News', 'parent_id'=>1),
array('id'=>3, 'title'=>'Sub News', 'parent_id'=>2),
array('id'=>4, 'title'=>'Articles', 'parent_id'=>0),
array('id'=>5, 'title'=>'Article', 'parent_id'=>4),
array('id'=>6, 'title'=>'Article2', 'parent_id'=>4)
);
//create new list grouped by parent id
$itemsByParent = array();
foreach ($items as $item) {
if (!isset($itemsByParent[$item['parent_id']])) {
$itemsByParent[$item['parent_id']] = array();
}
$itemsByParent[$item['parent_id']][] = $item;
}
//print list recursively
function printList($items, $parentId = 0) {
echo '<ul>';
foreach ($items[$parentId] as $item) {
echo '<li>';
echo $item['title'];
$curId = $item['id'];
//if there are children
if (!empty($items[$curId])) {
printList($items, $curId);
}
echo '</li>';
}
echo '</ul>';
}
printList($itemsByParent);
/***************Extra Functionality 1****************/
function findTopParent($id,$ibp){
foreach($ibp as $parentID=>$children){
foreach($children as $child){
if($child['id']==$id){
if($child['parent_id']!=0){
//echo $child['parent_id'];
return findTopParent($child['parent_id'],$ibp);
}else{ return $child['title'];}
}
}
}
}
$itemID=7;
$TopParent= findTopParent($itemID,$itemsByParent);
/***************Extra Functionality 2****************/
function getAllParents($id,$ibp){ //full path
foreach($ibp as $parentID=>$nodes){
foreach($nodes as $node){
if($node['id']==$id){
if($node['parent_id']!=0){
$a=getAllParents($node['parent_id'],$ibp);
array_push($a,$node['parent_id']);
return $a;
}else{
return array();
}
}
}
}
}
$FullPath= getAllParents(3,$itemsByParent);
print_r($FullPath);
/*
Array
(
[0] => 1
[1] => 2
)
*/
/***************Extra Functionality 3****************/
//this function gets all offspring(subnodes); children, grand children, etc...
function getAllDescendancy($id,$ibp){
if(array_key_exists($id,$ibp)){
$kids=array();
foreach($ibp[$id] as $child){
array_push($kids,$child['id']);
if(array_key_exists($child['id'],$ibp))
$kids=array_merge($kids,getAllDescendancy($child['id'],$ibp));
}
return $kids;
}else{
return array();//supplied $id has no kids
}
}
print_r(getAllDescendancy(1,$itemsByParent));
/*
Array
(
[0] => 2
[1] => 3
)
*/
print_r(getAllDescendancy(4,$itemsByParent));
/*
Array
(
[0] => 5
[1] => 6
)
*/
print_r(getAllDescendancy(0,$itemsByParent));
/*
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
)
*/
?>

Categories