How to refactor similar foreach loops to follow DRY approach - php

If you have foreach loops of multiple arrays, and you need to run one of them inside another - Is it possible to refactor the following code to only have one loop to stop duplicating code:
<?php
$apples = array(
'red',
);
$bananas = array(
'yellow',
);
foreach ( $apples => $apple ) {
echo '<div class="apple">' . $apple . '</div>';
}
foreach ( $bananas => $banana ) {
echo '<div class="banana">';
echo $banana;
echo '<div class="child">';
foreach ( $apples => $apple ) {
echo '<div class="apple">' . $apple . '</div>';
}
echo '</div>';
echo '</div>';
}
/*
output:
<div class="apple">red</div>
<div class="banana">
yellow
<div class="child">
<div class="apple">red</div>
</div>
</div>
*/
This code logic that is duplicate is the one that outputs the <div class="apple">red</div>:
foreach ( $apples => $apple ) {
echo '<div class="apple">' . $apple . '</div>';
}

I'm not sure if it's much improvement without being given better context, but using a function for generating the list should help reduce duplicate code.
<?php
$apples = array(
'red',
);
$bananas = array(
'yellow',
);
function getFruitListHTML(array $fruitList, string $class, string $child = ''): string {
$out = '';
foreach ( $fruitList as $fruitItem ) {
$out .= "<div class=\"$class\">";
$out .= $fruitItem;
$out .= $child;
$out .= '</div>';
}
return $out;
}
$applesHTML = getFruitListHTML($apples, 'apple');
echo $applesHTML;
echo getFruitListHTML($bananas, 'banana', "<div class=\"child\">$applesHTML</div>");

Related

How to remove first element of an array using loop

I have very little experience with PHP, but I'm taking a class that has PHP review exercises. One of them is to create a function that uses a loop to return all values of an array except the first value in an unordered list. I'm assuming there's a way to do this using a foreach loop but cannot figure out how. This is what I had but I feel like I am far off:
<?php
$array = array('myName' => 'Becca', 'favColor' => 'violet', 'favMovie' => 'Empire Strikes Back', 'favBook' => 'Lullaby', 'favWeb' => 'twitter.com');
$myName = $array['myName'];
$favColor = $array['favColor'];
$favMovie = $array['favMovie'];
$favBook = $array['favBook'];
$favWeb = $array['favWeb'];
echo '<h1>' . $myName . '</h1>';
function my_function() {
foreach($array == $myName){
echo '<ul>'
. '<li>' . $favColor . '</li>'
. '<li>' . $favMovie . '</li>'
. '<li>' . $favBook . '</li>'
. '<li>' . $favWeb . '</li>'
. '</ul>';
}
}
my_function();
?>
The correct syntax of foreach is
foreach (array_expression as $key => $value)
instead of
foreach($array == $myName){
function that uses a loop to return all values of an array except the
first value
I'm not sure, what exactly you mean by except the first value. If you are trying to remove first element from the array. Then you could have used array_shift
If you are supposed to use loop then
$count = 0;
foreach ($array as $key => $value)
{
if ($count!=0)
{
// your code
}
$count++;
}
Change the code to following
<?php
$array = array('myName' => 'Becca', 'favColor' => 'violet', 'favMovie' => 'Empire Strikes Back', 'favBook' => 'Lullaby', 'favWeb' => 'twitter.com');
$myName = $array['myName'];
echo '<h1>' . $myName . '</h1>';
function my_function($array)
{
$count = 0;
echo "<ul>";
foreach($array as $key => $value)
{
if($key != "myName")
{
echo "<li>".$value."</li>";
}
}
echo "</ul>";
}
my_function($array);

How to loop an array in array (dynamic navigation)

I have an array with some items. Each array could have (or not) an subarray, also with some items.
How can I call the subarray in a loop? It is difficult to describe, here is the code. I know the code/syntax is not correct, but the syntax should clarify my problem:
<?php
$subitemsA = array(
'subA1' => array('num'=>65, 'text'=>'Labor', 'url'=>'#'),
'subA2' => array('num'=>44, 'text'=>'Rare', 'url'=>'#'),
);
$subitemsB = array(
'subB1' => array('num'=>0, 'text'=>'subB1', 'url'=>'#'),
'subB2' => array('num'=>0, 'text'=>'subB2', 'url'=>'#'),
'subB3' => array('num'=>0, 'text'=>'subB3', 'url'=>'#')
);
$navArray = array(
'Home' => array('num'=>0, 'text'=>'Home', 'url'=>'#'),
'Info' => array('num'=>0, 'text'=>'Info', 'url'=>'#', 'subArray'=>$subitemsA),
'Sport' => array('num'=>0, 'text'=>'Sport', 'url'=>'#', 'subArray'=>$subitemsB),
);
$html = '';
foreach($navArray as $item) {
$html .= "<li>";
$html .= "<a href='{$item['url']}'><i class='abc'></i>{$item['text']}</a>\n";
if (count($navArray) > 3) {
foreach($navArray.subArray as $subitem) {
$html .= "<li>";
$html .= "<a href='{$subitem['url']}'>{$subitem['text']}</a>\n";
$html .= "</li>";
}
}
$html .= "</li>";
}
The first foreach loop works. But how can I access the subArray of Info and Sport?
You need a three level foreach for this to work -
foreach($navArray as $key => $item) {
$html .= "<li>";
$html .= "<a href='{$item['url']}'><i class='abc'></i>{$item['text']}</a>\n";
foreach ($item as $itemkey => $value) {
if (is_array($value)) { //Now Check if $value is an array
foreach($value as $valuekey => $subitem) { //Loop through $value
$html .= "<li>";
$html .= "<a href='{$subitem['url']}'>{$subitem['text']}</a>\n";
$html .= "</li>";
}
}
}
$html .= "</li>";
}
This is an answer to your question in more general way: How to deal with multi-level nested array using recursion and template.
function parseArray(array $navArray, &$html, $depth = 0) {
foreach ($navArray as $item) {
$html .= "<li>";
// this function use template to create html
$html .= toHtml($item['url'], $item['text'], $depth);
foreach ($item as $subItem) {
if (is_array($subItem)) {
// use recursion to parse deeper level of subarray
parseArray($item, $html, $depth + 1);
}
}
$html .= "</li>";
}
}
function toHtml($url, $text, $depth)
{
$template = '';
if ($depth == 0) {
$template = '<a href=\'{{url}}\'><i class=\'abc\'></i>{{text}}</a>\n';
} elseif ($depth >= 1) {
$template = '<a href=\'{{url}}\'>{{text}}</a>\n';
}
// define more template for deeper level here if you want
$template = str_replace('{{url}}', $url, $template);
$template = str_replace('{{text}}', $text, $template);
return $template;
}
$html = '';
parseArray($navArray, $html);
Just hurrily forge this code out of mind, haven't test it yet. Hope it help.
Regards,

Iterate through a foreach loop in PHP and replace a counter placeholder with str_replace

This is vaguely WordPress related, but it's purely PHP question.
I have a function that gets all the images in a post and the function lets me control what comes before and after the images i.e. <figure> and </figure>.
I have a function like this:
function get_some_images( $args = "" ) {
$defaults = array(
'before_img' => '<figure>',
'after_img' => '</figure>',
);
$args = wp_parse_args( $args, $defaults );
extract( $args, EXTR_SKIP );
// $images is an array of images from the curren post
$i = 1;
foreach($images as $image) {
// Pseudocode
$output .= $before_img . $image . $after_img;
$i++;
}
return $output;
}
Usage:
$args = array(
'before_img' => '<div class="img">',
'after_img' => '</div>',
);
echo get_some_images($args);
All fine so far. But what if I want to add an iteration counter to the before_img, I'm using %d as a placeholder:
$args = array(
// Here's the difference, note the %d placeholder for iteration count
'before_img' => '<div class="img-%d">',
'after_img' => '</div>',
);
get_some_images($args);
I tried something like this:
$i = 1;
foreach($images as $image) {
// Here's the tricky bit
$before_img = str_replace('%d', $i, $before_img);
$output .= $before_img . $image . $after_img;
$i++;
}
But it won't iterate the counter, outputs same number for all the iterations:
<div class="img-1"><img></div>
<div class="img-1"><img></div>
<div class="img-1"><img></div>
...
If I echo the $i out, it's iterated normally:
$i = 1;
foreach($images as $image) {
echo $i . ', ';
$i++;
}
// Outputs: 1, 2, 3...
I tried some nested loops also, but with little luck.
I tried this for checking purpose :
<?php
function get_some_images( $args = "" ) {
$images=[1,2,3];
// $images is an array of images from the curren post
$i = 1;
foreach($images as $image) {
$before_img='<div class="img-%d">';
$after_img='</div>';
// Here's the tricky bit
$before_img = str_replace('%d', $i, $before_img);
$output .= $before_img . $image . $after_img;
$i++;
}
var_dump($output);
return $output;
}
get_some_images($args);
?>
and it yields this :
<div class="img-1">1</div>
<div class="img-2">2</div>
<div class="img-3">3</div>
you can go to : http://www.compileonline.com/execute_php_online.php and then after excuting this piece of code (with in php tags) ... inspecting the output will show u this div structure .. Hope it helps .. Cheers!

Php Multidimensional array for navigation

Needed Navigation Html
Home
Pages
About
Services
Products
Contact
FAQs
Sitemap
Privacy Policy
Column Layouts
1 Column
2 Column (Left Sidebar)
2 Column (Right Sidebar)
3 Column
4 Column
I want to use php arrays and foreach loops to output the needed html.
The php code I have thus far is:
<?php
$data = array("navigation");
$data['navigation']['Home'] = base_url();
$data['navigation']['Pages'] = base_url('pages');
$data['navigation']['Pages']['About'] = base_url('pages/about');
echo '<ul>';
foreach($data as $nav) {
foreach($nav as $subNavKey => $subNavHref) {
echo "<li><a href='$subNavHref'>$subNavKey</a>";
}
}
echo '</ul>';
?>
I was thinking I would need three foreach loops nested but php warnings/errors are generated when the third loop is reached on lines such as:
$data['navigation']['Home'] = base_url();
$data['navigation']['Pages'] = base_url('pages');
I'm not quite sure how to test for 3rd level depths such as:
$data['navigation']['Pages']['About'] = base_url('pages/about');
Also, outputting the needed li and ul tags in the proper positions has given me trouble aswell.
Use recursion
$data['navigation']['Home'] = base_url();
$data['navigation']['Pages'] = base_url('pages');
$data['navigation']['Pages']['About'] = base_url('pages/about');
$data['navigation']['Pages']['About']['Team'] = base_url('pages/team');
$data['navigation']['Pages']['About']['Team']['Nate'] = base_url('pages/nate');
echo "<ul>"
print_list($data);
echo "</ul>"
function print_list($menu) {
foreach($menu as $key=>$item) {
echo "<li>";
if(is_array($item)) {
echo "<ul>";
print_list($item);
echo "</ul>";
} else {
echo "<a href='{$val}'>$key</a>";
}
echo "</li>";
}
}
<?php
function nav($data) {
$html = '<ul>';
foreach ($data as $k => $v) {
if (is_array($v)) {
$html .= "<li>$k" . nav($v) . "</li>";
}
else {
$html .= "<li><a href='$k'>$v</a>";
}
}
$html .= '</ul>';
return $html;
}
echo nav($data);
A recursive function can get the job done:
$items = array(
"Home",
"Pages" => array(
"About",
"Services",
"Products",
"Contact",
"FAQs",
"Sitemap",
"Privacy Policy",
"Column Layouts" => array(
"1 Column",
"2 Column (Left Sidebar)",
"2 Column (Right Sidebar)",
"3 Column",
"4 Column"
)
)
);
function getMenu($array) {
foreach($array as $key => $value) {
if(is_array($value)) {
echo "<li>" . $key . "</li>";
echo "<ul>";
getMenu($value);
echo "</ul>";
} else {
echo "<li>" . $value . "</li>";
}
}
}
echo "<ul>";
getMenu($items);
echo "</ul>";
Output:
You should use a recursive function, for example (Working Demo):
function makeMenu($array)
{
$menu = '';
foreach($array as $key => $value) {
if(is_array($value)) {
$menu .= '<li>' . $key . '<ul>' . makeMenu($value) . '</ul></li>';
}
else {
$menu .= "<li><a href='". $value ."'>" . $value ."</a></li>";
}
}
return $menu;
}
Then call it like:
$data = array(
"Home",
"Pages" => array("About", "Services"),
"Column Layouts" => array("1 Column", "2 Column (Left Sidebar)")
);
echo '<ul>' . makeMenu($data) . '</ul>';

Make a list with php order by user and date

I want to make this, a list with all the items of a user, divide by users..
<div id="news-block">
<h3 id="news-title">USER NAME</h3>
<ul id="news-content">
<li>ITEM 1</li>
<li>ITEM 2</li>
<li>ITEM 3</li>
</ul>
I have this php, my problem is with the title:
<div id="news-block">
<?php
echo "<ul id='news-content'>";
$username=null;
foreach ($programas as $programa) {
if ($programa->username!= $username) {
$nombre = $programa->username;
echo "<h3 id='news-title'>".$programa->username."</h3>";
}
echo "<li>".$programa->titulo."</li>";
}
echo "</ul>";
?>
Obviously this code is wrong, because i can't repeat the name of the user..
Try this code:
<?php
$list = "<ul id=\"news-content\">";
$h3 = "<h3 id=\"news-title\">";
$username=null;
foreach ($programas as $programa) {
if ($username == null) {
$username = $programa->username;
$h3 .= $username . "</h3>";
}
$list .= "<li>" . $programa->titulo . "</li>";
}
$list .= "</ul";
echo $h3 . $list;
?>
Or do you want a list like:
- Name
-- 1
-- 2
-- 4
- Name
-- 1
-- 2
-- 3
this?
If so, we need the structure of your array $programas.
I think $programas is something like:
$programas = array(
"UserOne" => array("prog1", "prog2", "prog3"),
"UserTwo" => array("prog1", "prog2", "prog3")
);
So the code should be:
$users = array_keys($programas);
$i = 0;
foreach($programas as &$user) {
$h3 = "<h3 id=\"news-title\">" . $users[$i] . "</h3>";
$list = "<ul id=\"news-content\">";
foreach($user as &$programa) {
$list .= "<li>$programa</li>";
}
echo $h3 . $list . "</ul>";
$i = $i + 1;
}
Now tested, it works
Try this, I didn't test this code, but it should works!
<?php
$users = array(
'user1' => array(
'name' => 'Tom',
'items' => array( 'item1', 'item2', 'item3' )
),
'user2' => array(
'name' => 'John',
'items' => array( 'item1', 'item2', 'item3' )
)
);
foreach($users as $user)
{
echo '<h3 id="news-title">'.$user['name'].'</h3>';
echo '<ul>';
foreach($user['items'] as $item )
{
echo '<li>'.$item.'</li>';
}
echo '</ul>';
}
?>

Categories