PHP nth iteration [duplicate] - php

This question already has answers here:
PHP: How do you determine every Nth iteration of a loop?
(8 answers)
Closed 9 years ago.
So I am trying to use PHP to generate some content with the criteria of the nth loop needs to either open or close a div element. So my goal is to display 8 elements on the page and on the 9th element, I would like to close the div for the 8th element and open a new one for the 9th if there are any more image. Here is my code.
$images; // object
$i = 1;
echo '<div class="outer-container">';
while ( $images->have_images() ) {
if ( $i === 1 ) {
echo '<div class="inner-container">';
}
echo 'content here';
if ( $i === 8 || $images->total === $images->current + 1 ) {
echo '</div><!--.inner-container-->';
}
$i++;
}
echo '</div><!--.outer-container-->';
End result should look something like this:
<div class="outer-container">
<div class="inner-container">
content here
content here
content here
content here
content here
content here
content here
content here
</div><!--.inner-container-->
<div class="inner-container">
content here
content here
content here
</div><!--.inner-container-->
</div><!--.outer-container-->
I searched around and came to a conclusion that I have to probably use modulus but I am not certain how I can incorporate that into my code.
Thanks for looking.

if ( $i % 8 == 0) {
echo '</div><!--.container--><div class="container">';
}
Mod operator returns the remainder. You can simply state $i % 8 or $i % 8 == 0 or $i % 8 === 0 as john stated
But you will need to also open the next div in your conditional depending on how you structure this. An example:
<div class="outer-container">
<div class="inner-container">
<?php
$images; // object
$i = 1;
while ( $images->have_images() ) {
echo 'content here';
//print_r($i % 8);
if ( $i % 8 == 0 && $images->total > 8) {
echo '</div><!--.inner-container--><div class="inner-container">';
}
$i++;
}
?>
</div>
</div>
Added conditional in case your images total happens to be 8 it won't create a rogue empty div.
I'm trying to understand your comment. Are you saying you have an outer container, then an inner container, and inside this inner container you want the loop you defined in the question where each group of 8 is contained in a container div?
I added a print r in the loop you can uncomment to verify $i is doing what you want it to. By this code and the fact that $i begins at 1 you should not experience the closing div conditional prematurely.

Modulus is indeed what you're looking for:
if ( $i % 8 === 0 ) {
echo '</div><!--.container-->';
}

You forgot to open a new div
modify the following code:
if ( $i === 8 || $images->total === $images->current + 1 ) {
echo '</div><!--.container-->';
echo '<div class="container">'; //ADD THIS LINE!!!
}
and after you get out of the while add the closing </div> tag

Related

why Bootstrap grid positioning leaves empty columns?

I am trying to create a Bootstrap positioning grid, generated by a PHP loop. The grid would contain 11 imgs, and the loop iterates 11 times. When the grid is created I don't understand why 2 columns always get skipped
this is the code I am using, I have uploaded a pictured of the resultenter image description here generated by my code
<style>
</style>
<?php
$counter = 11;
echo '<div class="row " >';
for ($i = 1; $i < $counter; $i++) {
echo "<div class=col-md-4 > ciao <img src=pictures/venue$i.jpg alt=Flowers class=img-fluid> </div>";
if (($i+1) % 4 == 0)
echo '</div><div class="row" id=my-row>';
}
echo '</div>';
?>
<?php
$counter = 11;
echo '<div class="row">';
for ($i = 0; $i <= $counter; $i++) {
$x = $i + 1; // for venue images starting at 1
echo '<div class="col-md-4"> ciao <img src="pictures/venue' . $x . '.jpg" alt="Flowers" class="img-fluid"> </div>';
if ( ( $x ) % 3 == 0 && $i != $counter) //added $i != $counter to make sure on the last iteration an extra row isn't added and changed modulus to 3 not 4
echo '</div><div class="row" id="my-row-' . $x . '">';
}
echo '</div>';
Bootstrap runs off 12 columns. You have a few problems with your code:
You are starting your counter at 1 causing the first block to display 3 but your next block to display 4 etc. col-md-4 takes 4 of the 12 columns so you can only fit 3 of these in a row.
You need to make sure you wrap your attributes in quotes, some browsers will still parse this and display as intended, others won't.
To display what you want properly (grid of 3 images along, 4 rows) you need 12 images or you will always be missing 1.
Each element that is provided an ID must be a unique ID you are repeating my-row
Change this line :
if (($i+1) % 4 == 0)
To this :
if (($i) % 3 == 0)
Because the former will split to three only on the first block, and the rest block are splitted to four.

More elegant solution to this nested loop, anyone?

I have a php procedure that scans a directory where its content is thumbnail images of pdf files. The thumbnails are then displayed in a table, and included in an iframe of a parent web page. Each thumbnail is itself a hyperlink when clicked will open the actual pdf file. To avoid having a horizontal scroll bar, 9 images in a table row is perfect. I wrote a nested loop that in effect acts like a word wrap, where it displays 9 images and then begins another row. The actual code is much more entailed, so I have it pared down to a bare minimum example. It seems almost counter intuitive on first glance, decrementing $i on the second line of the outer loop, but it works. I wonder if anyone has a more elegant solution?
$ary = array(1,2,3,4,5,6,7,8,9,10);
for ($i=1; $i<(count($ary)+1); $i++) {
$i = $i-1;
for($j=0; $j<9; $j++) {
if ($i === count($ary)) break;
echo ($ary[$i].", ");
$i+=1;
}
echo "<br>";
}
The completed code now where $ndx is the count of the array, $dir is the scanned directory containing the png images, and $rtDir is the directory where the pdf's are saved:
if ($ndx > 0) {
$tbl = '<div id="draggable" class="ui-widget-content">
<ul>
<table><tr>';
/* place 9 images on one row */
foreach ($myfiles as $index => $image) {
$pdf = basename($image, ".png");
$pdf = $pdf . ".pdf";
$pdf = $rtDir.$pdf;
$tbl .= '<td>
<span class="zoom">
<a href="'.$pdf.'" target="_blank">
<li><img id="pdfthumb'.$index.'" class="myPhotos" alt="pdf'.$index.'" src="'.$dir.$image.'" ></li>
</a>
</span>
</td>';
if ($index % 9 == 8) {
/* end the current row and start a new one */
$tbl.= "</tr></table><br><br><table style='margin-top:-40px'><tr>";
}
}
$tbl .= "</tr></table></ul></div>";
printf($tbl);
unset($myfiles);
}
Thanks everyone for your suggestions.
So you want 9 images on each row? There are usually two logical choices:
Alternative 1: You use array_chunk(), e.g. like this:
$chunks = array_chunk($images, 9);
foreach ($chunks as $chunk) {
foreach ($chunk as $image) {
// image printing goes here
}
echo '<br'>;
}
Alternative 2: You use the modulo operator, e.g. like this:
foreach ($images as $index => $image) {
// images printing goes here
if ($index % 9 == 0) { // or 8, since it's a 0-index array... I don't remember
echo '<br>';
}
}
I mostly use the second version, myself, if I have to - or I ask one of our designers to make it fit to a proper width through css. Do note also that the second version won't work if your images array is associative.
$b = count( $ary ) - 1 ;
for( $i = 0 ; $i <= $b ; $i++ ) :
echo $ary[$i] ;
if( ( $i + 1 ) % 9 == 0 ) :
echo "<br>" ;
endif ;
endfor ;
like the above comment i like modulus but i also prefer the for loop, hope this helps.

Different css styling for last element of a php array

When looping through an array how can I create a different css div style for the last element to be output in my array.
for($i=0;$i<=count($productid);$i++){if($productrank[$i]>0 ){
<? if (($productid[$i] % 2 ) && !( last element of array){ echo '<div class="centerBoxContentsFeatured centeredContent back vLine " style="width:50%;">';}
else { echo '<div class="centerBoxContentsFeatured centeredContent back " style="width:50%;">';} ?>
Just check if it is the last $productid
for(...)
{
if ($i === (count ($productid) - 1))
// Last one -> special CSS
}
}
Also, DO NOT use count() in a FOR loop if you don't really have to.
Just assign a value BEFORE and use it :
$count_temp = count ($productid);
for ($i = 0; $i < $count_temp; ++$i)
And use this $count_temp again if the IF statement to check if it's the last element
Answer to comment :
How would this same method get the first element?
if ($i === 0)
Or
// Special CSS for $i = 0
// Start loop at 1 instead of 0
for ($i = 1; $i < $count_temp; ++$i)
You can do this purely with CSS using :last-child. It is supported by all modern browsers.
div.centerBoxContentsFeatured:last-child {
/* special styles for last */
}
See it in action: http://jsfiddle.net/9y93j/1/
Like this:
if($productid[$i] == $productid[count($productid)-1]){
//last element code here
} elseif (($productid[$i] % 2 ){
//even row code here
} else {
//odd row code here
}

Foreach break and continue in PHP

I am facing an problem. I have built a foreach loop in PHP:
<?php $show = false; ?>
<?php foreach ($this->items as $item) : ?>
But I want to echo the first 20 items and continue with the following 16 items.
I have managed to make it to do a break after 20 items but I am not getting the following 16 items ( starting from nr 21 ).
This is what I have so far:
<?php $show = false; ?>
<?php $i = $item->id = 1; ?>
<?php foreach ($this->items as $item) : ?>
<?php if(++$i > 20) break; ?>
If I set $i to '21' it still echos item 1 and so on.
Solution ## Thanks to #dhavald
<?php $show = false; ?>
<?php foreach (array_slice ($this->items, 0, 20) as $item) : ?>
By placing an array_slice in the foreach you can control the items you want show.
So on the next div i want to show item 21 to 36, the only thing i had to change was the 0 and 20 into , 20, 36
To clarify what I am looking for, I have three divs where I want to echo some items onto it. If an user collapse a div on the first there will appear the first 20 items and if a user clicks div2 the next 16 items will appear.
How can I correct this code to make that happen?
As i forgotten to mention, the solutions you bring on helped me really to understand the process but as i used a component generator for Joomla 3.1 there is one row of code that make it a little bit more complex to call the first 20 and second 16 items.
Directly after the foreach loop there is this line of code
if($item->state == 1 || ($item->state == 0 && JFactory::getUser()>authorise('core.edit.own',' com_ncitycatemus.vraagantwoordtoevoegen.'.$item->id))):
$show = true;
How can i manage it than with the loop ? Or do you suggest another way?
Thanks in advance! Really helped me to understand the loop!!
break breaks out of and stops a loop. continue skips the rest of the code in the loop, and jumps to the next iteration.
Using break and continue is in my opinion the wrong approach here. I'd simply use two for loops:
$keys = array_keys($this->items);
$keysLength = count($keys);
echo '<div id="div1">';
for ($i = 0; $i < min($keysLength, 20); $i++) {
echo $this->items[$keys[$i]];
}
echo '</div>';
if ($keysLength >= 20) {
echo '<div id="div2">';
for ($i = 20; $i < min($keysLength, 36); $i++) { //36 being 20 + 16
echo $this->items[$keys[$i]];
}
echo '</div>';
}
Note: This will work with any amount of items in $this->items. If it's under 20, it'll simply skip the next 16, and if it's above 36, it'll simply ignore the rest.
you can use array_slice to get a part of $this->items array and assign it into 3 different variables and loop over them separately.
$itemsDiv1 = array_slice($this->items, 0, 20); // gives first 20 items
$itemsDiv2 = array_slice($this->items, 20, 16); // gives next 16 items
and so on..
Don't use break; use continue;
<?php $i = 0; ?>
<!-- first group -->
<div>
<?php foreach ($this->items as $item) : ?>
<?php
/**
* Check if count divided by 20 has no remainder
*/
if ( (++$i % 20) == 0 ): ?>
</div>
<!-- start new group -->
<div>
<?php endif ?>
<?php endforeach ?>
<!-- end last group -->
</div>
$stockNotNull = StockDetail::where('sku', 10101001)
->where('stock_quantity', '>', 0)->get('stock_id', 'stock_quantity');
$toSell = 14;
// decrements just once for each $stockNotNull
foreach ($stockNotNull as $product) {
if ($toSell < 1) {
return;
}
$product->decrement('stock_quantity');
// $product->stock_quantity--; returns with a null
// dump($product->stock_quantity);
$product->save();
$toSell--;
// dump($toSell);
if($product->stock_quantity === 0) {
continue;
}
}
This is what I got so far, decrementing in the usual manner i.e $variable-- gives me a null value, $product->decrement('stock_quantity') subtracts 1 on each run, even if the stock_quantity field is far greater than the $toSell variable. The logic is there in my head, I'm just having trouble taking the quantity from the current item and moving on to the next only when the stock_quantity is 0.

set every 1st and fourth element with a class

I have a jquery carousel set to 620px wide. I am using the grid 960 to place the images inside. I show 4 images at a time.
In order to do that I set the every first image class to 'grid_2 alpha' and every fourth to 'grid_2 omega' in the group of 4 shown while all in between I set to just grid_2.
This gives me the 620px I need. I am pulling from the database and I am trying to set the class dynamically but cant quite get every first and fourth in the group with the classes.
<?php $loopIndex = 1; ?>
<?php foreach ($pub_values as $v) {
if($v['pub_of_the_month'] == 1)
{
?>
<?php if ($loopIndex == 1 || $grid_class=="grid_2 omega") $grid_class="grid_2 alpha";
else if($loopIndex%4 == 0) $grid_class="grid_2 omega";
else $grid_class="grid_2";
$filename = "images/pub_images/120x160/".$v['id'].".jpg";
if (!file_exists($filename)) $filename = "images/pub_images/120x160/blank.gif";
?>
<div class="<?php echo $grid_class?>">
<a href="#">
<img src="<?=$filename;?>" alt="<?=$v['name'];?>" width="120" height="160" />
<?=$v['name'];?>
</a>
</div>
<?php $loopIndex = $loopIndex + 1; } }?>
The above code is my best attempt of achieving the following.
Images
1 - grid_2 alpha
2 - grid_2
3 - grid_2
4 - grid_2 omega
5 - grid_2 alpha
6 - grid_2
7 - grid_2
8 - grid_2 omega
9 - grid_2 alpha
Simple math, dividing with a remainder.
Maybe you can figure out by looking a this code:
for($i = 1; $i <= 9; $i++){
echo "\n $i ";
if($i % 4 == 1){
echo " alpha";
}elseif($i % 4 == 0){
echo " omega";
}
}
Live example: http://codepad.org/LIepxlJm
maybe you should just use a for-loop:
for ($i = 0; $i< sizeof($pub_values); $i++) {
$classes =['grid_2'];
if($i%4 == 0) $classes[] = 'alpha';
if($i%4 == 3) $classes[] = 'omega';
}
edit: this is just trying to show an approach, not trying to be syntactically correct.
in the end, you want to join (or implode in php) your classes to get the string.... (not implemented for you either)

Categories