Jump to content

PHP Puzzler - foreach? do loop?


daniel-not-dan
 Share

Recommended Posts

Hi everyone! Got a puzzle here for you, and if you're able to solve it - I'm all ears!

I'm trying to create a grid using PHP that looks roughly like this:

<div class = "row">
    <div class = "6-columns">
        <div>Product</div>
    </div>
    <div class = "6-columns">
        <div>Product</div>
    </div>
</div>
<div class = "row">
    <div class = "6-columns">
        <div>Product</div>
    </div>
    <div class = "6-columns">
        <div>Product</div>
    </div>
</div> 

The Products here are being collected from a group of pages. I'm able to get them to display, but here's the problem... I need to Loop thru them two-at-a-time so I can add a new "row" before each new group of two 6-column divs.

Here's what I have so far (in overly-simplified form):

echo "<div class = 'row'>";
foreach ($productList as $product) {
    echo "<div class = '6-columns'><div>$product</div></div>";
}
echo "</div>" 

See my issue? The output from this is something like:

<div class = "row">
    <div class = "6-columns">
        <div>Product</div>
    </div>
    <div class = "6-columns">
        <div>Product</div>
    </div>
    <div class = "6-columns">
        <div>Product</div>
    </div>
    <div class = "6-columns">
        <div>Product</div>
    </div>
</div> 

I'm sure I need some kind of do while loop or something in there, but I can't seem to get the sequence right of what should go where so I can do ONE row, then TWO products, then ONE row, then TWO products, etc.

So, no, this is not really a PW issue, but I thought someone here might like a crack at helping me solve this!

All the best,
Daniel

Link to comment
Share on other sites

I'm on mobile, so i will try to help without code.

In your example, inside the foreach, check if the item is even (%=0) and not the last. If true, echo a closing row div and open a new one. For checking this you can use a counter or the api. Look on he cheatsheet for the array methods getItemKey() and last().

Link to comment
Share on other sites

Awesome. I'm a PHP noob, so some of that made sense... enough of it so that I was able to get it to work anyway!

Here's the basic outline of it:

$lastProduct = $productList->last();
$counter = 1;
foreach ($productList as $product) {
    if($counter % 2 != 0) { 
        echo "<div class = 'row'>"; //item is odd, so open the div.row
    }
        //echo the product
        echo "<div class = '6-columns'>";
            echo "<div>$product</div>";
        echo "</div>";        
    if($counter % 2 == 0) || $product == $lastProduct {
        echo "</div>" ; //item is even (or list is complete), so close the div.row
    }    
    $counter = $count + 1;
}
 

I wasn't sure how to use the getItemKey() method, so if anyone feels like elaborating on that, I'm once again all ears!

Thanks so much, diogo!

Link to comment
Share on other sites

You could use getItemKey() like this:

if($a->getItemKey($i) % 2 != 0)

But thinking better, this does the same and it's simpler:

foreach ($productList as $key => $product){
    if($key % 2 != 0) { 
        // echo
    }
...
  • Like 1
Link to comment
Share on other sites

That worked, too - and yes, it's simpler.

So, the $key is basically just a counter? I had it print the $key for each product next to the title and it just looked like sequential integers going up from 0. Is that the basic idea?

Yes - in this example the key acts like a counter. However, this depends on your array.

In PHP, you can have arrays with numbers and strings as keys in any order - then the counter wouldn't work anymore.

Some examples of arrays and keys:

//Array without keys (indexes are given implicit started by 0)
$array1 = array('hi', 'how', 'are', 'you?');

//Array with defined integer keys
$array2 = array(0 => 'good', 245 => 'thanks');

//Associative array
$array3 = array(
  'firstKey' => 'firstValue',
  'secondKey' => 'secondValue',
);

//Now the loops 
foreach ($array1 as $k => $v) {
  echo $k; //Prints 0, 1, 2, 3
}

foreach ($array2 as $k => $v) {
  echo $k; //Prints 0, 245
}

foreach ($array3 as $k => $v) {
  echo $k; //Prints firstKey, secondKey
}
Link to comment
Share on other sites


<?php

$lastProduct = $productList->last();

$counter = 1;

foreach ($productList as $product) {

    if(!$counter % 2) echo "<div class = 'row'>"; //item is odd, so open the div.row

      

        echo "<div class = '6-columns'>

                <div>$product</div>

              </div>

             ";

               

    if ( $counter % 2 || $product == $lastProduct )

        echo "</div>" ; //item is even (or list is complete), so close the div.row

    

    $counter++;

}

?>

Link to comment
Share on other sites

Like Wanze said, in this case it can be used as a counter. Strangely the same doesn't happen with multiple image fields, where the key returns the name of the image. Ryan, if you are reading this, why is it?

Link to comment
Share on other sites

So after everyone's help on this, I wanted to go a little further and make the number of columns within the div.row variable to some degree. I'd like the option to display the products either two-across (which we've already accomplished) or three-across, which hurt my brain as soon as I tried to tackle it using the method above. So instead, here's what I came up with which should work for any number of columns across a 12-column grid setup.


$numColumns = "4-columns"; // For a 3-across layout, given a 12-column grid.
$magicNumber = 12 / $numColumns; //This will be the magic number at which the row closes itself.

$lastProduct = $productList->last();

$counter = 1

foreach ($productList as $product) {

    if ($counter == 1) {
        echo "<div class = 'row'>"; //This is the first one, so open the div.row
    }
    
    echo "<div class = '$numColumns'>$product</div>";
    
    if ($counter == $magicNumber || $product == $lastProduct) {
        echo "</div>" //This is the last one in the row, so close the div.row
        $counter = 0 //Reset to 0, knowing the next step will set it back to 1, so that the new row will open.
    }
    
    $counter++;

}
 

This allows me to pass in a variable ($numColumns) that says "I want these products to display thismany across."

For my money, this seems like the simplest solution. Anyone think of any improvements?

Link to comment
Share on other sites

You should change this:

if ($counter == $magicNumber || $product == $lastProduct)

to this:

if ($counter % $magicNumber == 0 || $product == $lastProduct)
Link to comment
Share on other sites

Like Wanze said, in this case it can be used as a counter. Strangely the same doesn't happen with multiple image fields, where the key returns the name of the image. Ryan, if you are reading this, why is it?

On a file system, you can't have two of the same filename in the same directory. Filenames as keys ensure that same remains true in memory. 

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...