Converting a PHP array into HTML form inputs is duplicating items - php

I am attempting to take an array of values and build a php form from those values.
The array is at the bottom to keep the question clear. The array structure is:
- Item
- Item
- Item with Child
-Item
-Item
- Item with Child
-Item
-Item
Here is what I want to output each item but if the item has a child, just output the name of the parent and create fields for the children.
I created this:
function renderTest2(array $data)
{
$html = '<ul>';
foreach ($data as $item) {
$html .= '<li>';
foreach ($item as $key => $value) {
if (is_array($value)) {
$html .= renderTest2($value);
} else {
if (array_key_exists('children', $item)) {
$html .= $item['name'];
} else {
$html .= $item['name'] . "<input type=\"text\" value=\"\"> <br/>";
}
}
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
Which gave me this output:
But I don't understand why it is duplicating items. What am I doing wrong?
Here is the test array I used:
$aFullArray = array();
$aFullArray[] = array("name" => "Adam", "address" => "123 main", "phone" => "000-000-0000");
$aFullArray[] = array("name" => "Beth", "address" => "123 main", "phone" => "000-000-0000");
$aChildren = array();
$aChildren [] = array("name" => "Mike", "address" => "123 main", "phone" => "000-000-0000");
$aChildren[] = array("name" => "Nancy", "address" => "123 main", "phone" => "000-000-0000");
$subChild = array();
$subChild [] = array("name" => "Peter", "address" => "123 main", "phone" => "000-000-0000");
$subChild [] = array("name" => "Paul", "address" => "123 main", "phone" => "000-000-0000");
$aChildren [] = array("name" => "Oscar", "address" => "123 main", "phone" => "000-000-0000",
"children" => $subChild);
$aFullArray[] = array("name" => "Charlie", "address" => "123 main", "phone" => "000-000-0000",
"children" => $aChildren);
$aFullArray[] = array("name" => "Danny", "address" => "123 main", "phone" => "000-000-0000");

function renderTest2(array $data)
{
$html = '<ul>';
foreach ($data as $item) {
$html .= '<li>';
if (array_key_exists('children', $item)) {
$html .= $item['name'];
$html .= renderTest2($item['children']);
} else {
$html .= $item['name'] . "<input type='text' value=''> <br/>";
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
you are looping two times which is not required and if it has children pass children array only
Explanation:
Loop through an array and if it has children key do recursion
If not found generate li element

Looking at the code i saw the following mistake:
foreach() do foreach() so a multiple foreach() loop would be the mistake you've made.
try this code:
by calling foreach() only once and using
if (array_key_exists('children', $item)) {
$html .= $item['name'];
$html .= renderTest2($item['children']);
}
together in one foreach() the double loop isn't needed and recursion is avoided
The full code then would be:
<?php
$aFullArray = array();
$aFullArray[] = array("name" => "Adam", "address" => "123 main", "phone" => "000-000-0000");
$aFullArray[] = array("name" => "Beth", "address" => "123 main", "phone" => "000-000-0000");
$aChildren = array();
$aChildren [] = array("name" => "Mike", "address" => "123 main", "phone" => "000-000-0000");
$aChildren[] = array("name" => "Nancy", "address" => "123 main", "phone" => "000-000-0000");
$subChild = array();
$subChild [] = array("name" => "Peter", "address" => "123 main", "phone" => "000-000-0000");
$subChild [] = array("name" => "Paul", "address" => "123 main", "phone" => "000-000-0000");
$aChildren [] = array("name" => "Oscar", "address" => "123 main", "phone" => "000-000-0000",
"children" => $subChild);
$aFullArray[] = array("name" => "Charlie", "address" => "123 main", "phone" => "000-000-0000",
"children" => $aChildren);
$aFullArray[] = array("name" => "Danny", "address" => "123 main", "phone" => "000-000-0000");
function renderTest2(array $data)
{
$html = '<ul>';
foreach ($data as $item) {
$html .= '<li>';
if (array_key_exists('children', $item)) {
$html .= $item['name'];
$html .= renderTest2($item['children']);
} else {
$html .= $item['name'] . "<input type='text' value=''> <br/>";
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
echo renderTest2($aFullArray);
Hope this helps!

As the original code was not making use of various elements within the source arrays I simplified for testing porpoises. Hopefully the following makes sense, it seems to generate the list in the desired manner.
$html = $family = $children_family_1 = $children_family_2 = array();
$family[] = array("name" => "Adam");
$family[] = array("name" => "Beth");
$family[] = array("name" => "Danny");
$children_family_2[] = array("name" => "Peter");
$children_family_2[] = array("name" => "Paul");
$children_family_1[] = array("name" => "Mike");
$children_family_1[] = array("name" => "Nancy");
$children_family_1[] = array("name" => "Oscar", "children" => $children_family_2 );
$family[] = array("name" => "Charlie", "children" => $children_family_1 );
function familytree( $input=array(),&$html ){
$html[]='<ul>';
foreach( $input as $index => $arr ){
if( array_key_exists( 'children', $arr ) && is_array( $arr['children'] ) ){
$html[]="<li>Parent: {$arr['name']}</li>";
$html[]="<li>";
/* recurse array to repeat structure */
familytree( $arr['children'], &$html );
$html[]="</li>";
} else {
$html[]="<li><input type='text' name='name[]' value='{$arr['name']}' /></li>";
}
}
$html[]='</ul>';
return implode( PHP_EOL, $html );
}
echo familytree( $family, $html );
The generated html:
<ul>
<li><input type="text" name="name[]" value="Adam"></li>
<li><input type="text" name="name[]" value="Beth"></li>
<li><input type="text" name="name[]" value="Danny"></li>
<li>Parent: Charlie</li>
<li>
<ul>
<li><input type="text" name="name[]" value="Mike"></li>
<li><input type="text" name="name[]" value="Nancy"></li>
<li>Parent: Oscar</li>
<li>
<ul>
<li><input type="text" name="name[]" value="Peter"></li>
<li><input type="text" name="name[]" value="Paul"></li>
</ul>
</li>
</ul>
</li>
</ul>

Related

Group rows on one column and form nested subarray with other column

Here is the thing I trying deal with
I have array which looks like this and have duplicates
$products = [
[
"product_name" => "Adidas1",
"address" => "street 2"
],
[
"product_name" => "Adidas2",
"address" => "street 2"
],
[
"product_name" => "Adidas3",
"address" => "street 2"
],
[
"product_name" => "Adidas4",
"address" => "street 2"
],
[
"product_name" => "Nike1",
"address" => "street name1"
],
[
"product_name" => "Nike2",
"address" => "street name1"
]];
Result that I need to get is below .
I did try different ways to do it but still can bring it to the finel result that have to come up
$final_result = [
[
"address" => "street 2",
"products" => [
"addidas1",
"addidas2",
"addidas3",
"addidas4",
]
],
[
"address" => "street name1",
"products" => [
"Nike1",
"Nike2",
]
]
any suggestion how to do it ?
here is my best solution that I tried
$stor_sorted = array();
foreach ($products as $product) {
if (array_count_values($product) > 1) {
$stor_sorted[] = ["address" => $product['address'], "items" => [$product['product_name']]];
}
}
try this code
$products = [
[
"product_name" => "Adidas1",
"address" => "street 2"
],
[
"product_name" => "Adidas2",
"address" => "street 2"
],
[
"product_name" => "Adidas3",
"address" => "street 2"
],
[
"product_name" => "Adidas4",
"address" => "street 2"
],
[
"product_name" => "Nike1",
"address" => "street name1"
],
[
"product_name" => "Nike2",
"address" => "street name1"
]];
$final_result = [];
foreach ($products as $pr){
$original_key = array_search($pr['address'], array_column($final_result, 'address'), true);
if($original_key === false){
$temp_array['address'] = $pr['address'];
$temp_array['products'] = [$pr['product_name']];
$final_result[] =$temp_array;
}else{
$final_result[$original_key]['products'][] = $pr['product_name'];
}
}
your result will be in final_result array
Use address values as temporary keys in your result array.
When an address is encountered for the first time, cast the product name as an array within the row and store the row.
On subsequent encounters, merely push the product name into the group's subarray.
When finished, re-index the result with array_values().
Code: (Demo)
$result = [];
foreach ($products as $row) {
if (!isset($result[$row['address']])) {
$row['product_name'] = (array)$row['product_name'];
$result[$row['address']] = $row;
} else {
$result[$row['address']]['product_name'][] = $row['product_name'];
}
}
var_export(array_values($result));
Same output with a body-less foreach() using array destructuring: (Demo)
$result = [];
foreach (
$products
as
[
'address' => $key,
'address' => $result[$key]['address'],
'product_name' => $result[$key]['product_name'][]
]
);
var_export(array_values($result));
Same output with functional style programming and no new globally-scoped variables: (Demo)
var_export(
array_values(
array_reduce(
$products,
function($result, $row) {
$result[$row['address']]['product_name'] = $row['product_name'];
$result[$row['address']]['address'][] = $row['address'];
return $result;
}
)
)
);

Merging data of common keys in a same array

so I have an array like this :-
$headers = array();
$headers[] = array("country" => "Netherlands", "city" => "Amsterdam");
$headers[] = array("country" => "Netherlands", "city" => "Tillsburg");
$headers[] = array("country" => "Sweden", "city" => "Stockholm");
I need it like :-
array("country" => "Netherlands", "city" => "Amsterdam,Tillsburg");
array("country" => "Sweden", "city" => "Stockholm");
How do I merge the values?
Here's what I have tried till now, but it doesn't seems to be working.
function merge($headers) {
$final = [];
foreach($headers as $current) {
if(!in_array($current['country'], $final)) {
$final[] = $current['country'];
}
}
foreach($headers as $current) {
$final[$current['country']]['city'] = $current['city'];
}
return $final;
}
Any help would be appreciated.
Use country values as temporary associative keys to determine if concatenation is necessary.
Code: (Demo)
$headers[] = array("country" => "Netherlands", "city" => "Amsterdam");
$headers[] = array("country" => "Netherlands", "city" => "Tillsburg");
$headers[] = array("country" => "Sweden", "city" => "Stockholm");
foreach ($headers as $row) {
if (!isset($result[$row['country']])) {
$result[$row['country']] = $row; // store the whole row
} else {
$result[$row['country']]['city'] .= ",{$row['city']}"; // concatenate
}
}
var_export(array_values($result)); // reindex the output array
Output:
array (
0 =>
array (
'country' => 'Netherlands',
'city' => 'Amsterdam,Tillsburg',
),
1 =>
array (
'country' => 'Sweden',
'city' => 'Stockholm',
),
)
Maybe this is not the best solution, but I test it, it works.
function merge($headers) {
$final = array();
foreach ($headers as $current) {
if( !isset( $final[ $current['country'] ] ) ) {
$final[$current['country']] = [
'country' => $current['country'],
'city' => $current['city']
];
continue;
}
$final[ $current['country'] ]['city'] = $final[ $current['country'] ]['city'] . ', ' . $current['city'];
}
return $final;
}
Output
array(2) { ["Netherlands"]=> array(2) { ["country"]=> string(11) "Netherlands" ["city"]=> string(20) "Amsterdam, Tillsburg" } ["Sweden"]=> array(2) { ["country"]=> string(6) "Sweden" ["city"]=> string(9) "Stockholm" } }
You can clear keys of result array if you want adding
$final = array_values($final);
before return statement
Demo
$headers = array();
$headers[] = array("country" => "Netherlands", "city" => "Amsterdam");
$headers[] = array("country" => "Netherlands", "city" => "Tillsburg");
$headers[] = array("country" => "Sweden", "city" => "Stockholm");
$result = array();
foreach($headers as $key => $value) {
$result[$value['country']][] = $value['city'];
}
$finalArray = array();
foreach($result as $k => $v) {
$finalArray[] = array('country' => $k, 'city' => join(',', $v));
}
Create another array with country name as key
<?php
$headers = array();
$headers[] = array("country" => "Netherlands", "city" => "Amsterdam");
$headers[] = array("country" => "Netherlands", "city" => "Tillsburg");
$headers[] = array("country" => "Sweden", "city" => "Stockholm");
$countries = array_unique(array_column($headers,"country"));
$newHeaders = array();
foreach($headers as $header){
$newHeaders[$header["country"]]["city"][] = $header["city"];
}
print_r($newHeaders);
foreach($newHeaders as $key=>$headers){
echo $key." City : ".implode(",",$headers['city'])."\n";
}
?>
Live Demo Link
Output would be like
Netherlands City : Amsterdam,Tillsburg
Sweden City : Stockholm

Preg match array keys

I have it like this:
$data = array(
"City_0" => "London",
"City_1" => "Paris",
"City_2" => "Lisbon",
"City_3" => "Berlin"
);
plus some other data in that same array.
User will select only one of these and what I need is:
Check with preg_match to get all keys that starts with "city_"
find key which has value (it is not empty), take that value
assign it to new key
remove all "city_" keys
add new key to array with the name "chosen_city" which will contain that value
What I tried:
foreach ($data as $key => $value) {
$matches = preg_match('/city_/i', $key);
if ($value != "") {
$newValue = $value;
break;
}
}
$data['chosen_city'] = $newValue;
print_r($data);
This works partially, how can I remove all previous "city_" keys from array in that if statement?
NOTE:
I have other keys in array, and I don't want to remove them as well.
Input array:
$data = array(
"City_0" => "London",
"City_1" => "Paris",
"City_2" => "Lisbon",
"City_3" => "Berlin",
"distance" => "5 km",
"days" => "7",
"tickets" => "2",
"discount" => "10%",
);
Expected output:
$data = array(
"chosen_city" => "Berlin",
"distance" => "5 km",
"days" => "7",
"tickets" => "2",
"discount" => "10%",
);
Thanks.
Please put unset for example code :
$data = array( "City_0" => "London", "City_1" => "Paris", "City_2" => "Lisbon", "City_3" => "Berlin");
foreach($data as $key => $value){
$matches = preg_match('/city_/i', $key);
if($matches && $value != ""){
$newValue = $value;
unset($data[$key]);
}elseif($matches){
unset($data[$key]);
}
}
$data['chosen_city'] = $newValue;
preg_* is somewhat overkill in this instance - you could use strpos and it'd work just as well
However, the question is 'how to I remove the city_* keys', so to do that, just use unset():
foreach($data as $key => $value){
$matches = preg_match('/city_/i', $key);
if($value != ""){
$newValue = $value;
unset($data[$key]); //Remove this item from the array
break;
}
}
$data['chosen_city'] = $newValue;
print_r($data);
$data = array(
"City_0" => "London",
"City_1" => "Paris",
"City_2" => "Lisbon",
"City_3" => "Berlin",
"distance" => "5 km",
"days" => "7",
"tickets" => "2",
"discount" => "10%",
);
$value = 'Berlin';
if (array_search($value, $data)) {
$data['chosen_city'] = $value;
foreach ($data as $key=>$val) {
if (stripos($key, 'city_')===0) {
unset($data[$key]);
}
}
}
result:
array(5) {
'distance' =>
string(4) "5 km"
'days' =>
string(1) "7"
'tickets' =>
string(1) "2"
'discount' =>
string(3) "10%"
'chosen_city' =>
string(6) "Berlin"
}
If you use PHP >=5.6, probably you can use (I didn't tested this code)
$city = array_search($value, $data);
if ($city) {
$data['chosen_city'] = $value;
$data = array_filter($data,function($key,$val){return stripos($key,'city_')===false;},ARRAY_FILTER_USE_BOTH);
}

How i can print Arrays with for each loop

<?php
$students = array(
"student1" => array(
"age" => 36,
"gender" => "male",
"qualification" => "Master",
),
"student2" => array(
"age" => 25,
"gender" => "male",
"qualification" => "BA",
),
"student3" => array(
"age" => 26,
"gender" => "male",
"qualification" => "BA",
),
"student4" => array(
"age" => 25,
"gender" => "male",
"qualification" => "BA",
),
"student5" => array(
"age" => 20,
"gender" => "male",
"qualification" => "Master",
),
"student6" => array(
"age" => 20,
"gender" => "male",
"qualification" => "F.A",
),
);
?>
And i need result like this.
Hello Student1
Your age is 36 and
Your gender is male and
Your qualification is Master.
Hello Student2
Your age is 25 and
Your gender is male and
Your qualification is BA.
I have try like this.
foreach($students as $key=>$value)
{
echo "Mr".$key."<br />";
foreach($value as $key=>$value)
{
echo" Your $key is $value and <br />";
}
}
And my result like this.
Hello Student1
Your age is 36 and
Your gender is male and
Your qualification is Master and
Hello Student2
Your age is 25 and
Your gender is male and
Your qualification is BA and
No need for that other foreach inside, you can just use one. Each copy of the sub array ($info), you will just have to call its indices.
foreach ($students as $name => $info) {
echo "
Hello $name, <br/>
Your age is: $info[age] <br/>
Your gender is: $info[gender] <br/>
Your qualification is: $info[qualification] <hr/>
";
}
But if you really want to go that two foreach route, yes you could add a condition in the second loop to prevent it from adding the superfluous and:
foreach ($students as $name => $info) {
echo "Hello $name ";
foreach($info as $att => $val) {
echo "Your $att is: $val ", (end($info) != $val) ? ' and ' : '<br/>';
}
}
Try with -
foreach($students as $key=>$value)
{
echo "Mr".$key."";
$count = 1;
foreach($value as $key=>$val)
{
echo" Your $key is $val";
if ($count != count($val)) {
echo " and ";
}
}
}
Try this code:
foreach($students as $key => $value) {
echo 'Hello ', $key, ' Your age is ', $value['age'], ' gender is ' . $value['gender'], ' and Your qualification is ', $value['qualification']
}
You can concat string with echo, but coma will be better for performance.

Empty arrays error

i have a set of php arrays, and i am trying to retrieve those details and echo. however i get errors such as Warning: Invalid argument supplied for foreach().
how can i rectify such errors from appearing?
this problem occurs when i echo all cakes from all users.
I have tried so far to eliminate possible errors from the code and also used validation statements such as if empty then do this, however the problem still persists.
<?php
//USERS ARRAYS
$users = array();
$users["john"] = array(
"first name" => "John",
"last name" => "Smith",
"address" => "London");
$users["jade"] = array(
"first name" => "Jade",
"last name" => "Anthony",
"address" => "Essex");
$users["clement"] = array(
"first name" => "Clement",
"last name" => "Smith",
"address" => "Essex");
//CAKES ARRAY
$cakes = array();
$cakes = array(
"john" => array(
"Chocolate Cake" => array(
"ingredients" => "chocolate, flour, eggs",
"cooking time" => "20 minutes"),
),
"jade" => array(
"Lemon Cheesecake" => array(
"ingredients" => "lemons, flour, eggs",
"cooking time" => "30 minutes")),
"clement" => NULL,
);
?>
<?php $user_name = 'john';?>
<h1>Name</h1>
<p><?php echo $users["first name"]; ?></p>
<h1>Cakes Made</h1>
<?php
foreach($cakes[$user_name] as $key => $val)
{ echo $key . " <strong>Ingredients: </strong>" . $val["ingredients"] . "<br>"; }
?>
<h1>All cakes from all users</h1>
<?php foreach($cakes as $cake) { ?>
<?php if(is_array($cake)) {
foreach($cake as $cakemade => $newval)
if(empty($cakemade)) { echo "";} else
{ echo $cakemade . "<strong>" . $newval['ingredients'] ."</strong> <br>"; }
?>
<?php }} ?>
your input is welcome. :)
edit: Just to be clear the code error relates to the second part of the code in which it displays all cakes from all users.
You can test if the variable in want use in foreach is set
if(isset($cakes[$user_name]) && count($cakes[$user_name]) > 0)
foreach($cakes[$user_name] as $key => $val) {}
Missing "s for the keys.Your array should be -
$cakes = array(
"john" => array(
"Chocolate Cake" => array(
"ingredients" => "chocolate, flour, eggs",
"cooking time" => "20 minutes"),
)
"jade" => array(
"Lemon Cheesecake" => array(
"ingredients" => "lemons, flour, eggs",
"cooking time" => "30 minutes"),
"clement" => NULL,
);
if(is_array($variable) && count($variable) > 0) {
foreach($variable as $key => $value) {
//Your code
}
)
You have many syntax errors in your pasted code. also use is_array() to check an array.
also you have defined $username = "john" and passing in foreach with $user_name
try
<?php
//USERS ARRAYS
$users = array();
$users["john"] = array(
"first name" => "John",
"last name" => "Smith",
"address" => "London");
$users["jade"] = array(
"first name" => "Jade",
"last name" => "Anthony",
"address" => "Essex");
$users["clement"] = array(
"first name" => "Clement",
"last name" => "Smith",
"address" => "Essex");
//CAKES ARRAY
$cakes = array();
$cakes = array(
"john" => array(
"Chocolate Cake" => array(
"ingredients" => "chocolate, flour, eggs",
"cooking time" => "20 minutes"),
),
"jade" => array(
"Lemon Cheesecake" => array(
"ingredients" => "lemons, flour, eggs",
"cooking time" => "30 minutes")),
"clement" => NULL,
);
?>
<?php $user_name = 'john';?>
<h1>Name</h1>
<p><?php echo $users["first name"]; ?></p>
<h1>Cakes Made</h1>
<?php
foreach($cakes[$user_name] as $key => $val)
{ echo $key . " <strong>Ingredients: </strong>" . $val["ingredients"] . "<br>"; }
?>
<h1>All cakes from all users</h1>
<?php foreach($cakes as $cake) { ?>
<?php if(is_array($cake)) {
foreach($cake as $cakemade => $newval)
if(empty($cakemade)) { echo "";} else
{ echo $cakemade . "<strong>" . $newval['ingredients'] ."</strong> <br>"; }
?>
<?php }} ?>
Probably the best way would be to check if the variable is an array and then check if it's empty.
As you have made clear if the variable is array and it's not empty, then you should waste processor time to iterate over an array.
So the code would look like this:
if(!empty($var) && is_array($var)) {
foreach($var as $key => $value) {
echo $key . ' => ' . $value;
}
}

Categories