Foreach break and continue in PHP - 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.

Related

Take count of one loop, output the amount that's left

I have a set of 12 circles, some will be blank, some will have an icons (this is driven by Wordpress whether they have an icon or not).
I then have a standard Wordpress loop looking for icons, if an icon is present then it will output. It also iterates the $counter variable starting at 1.
How can I take the count of that - then create a new loop to create blank circles?
So for instance, if 5 circles have icons then I would need 7 blank circles.
This is my attempt, at the moment it's creating an infinite loop. So from the example this needs to output 7, with the class name outputting the numbers 7, 8, 9 etc up to 12 to fill in the blanks.
Where am I going wrong?
<?php $final = 12 - $counter;
for($count = 1; $count <= $final; $count++) { ?>
<a class="research-circle blank-circle rs-<?php echo $final; ?>" href="#"></a>
<?php $final++; } ?>
It's infinite because you're increasing both values simultaneously.
Try this:
for($count = 1; $count <= $final; $count++) { ?>
<a class="research-circle blank-circle rs-<?php echo ($final + $count); ?>" href="#">
</a>
<?php }
?>
Look inside your loop condition: You tell PHP to loop until $count is greater than $final.
But in your loop, you increase both $count and $final value. $count will never be greater than $final.

Is there a better way to deal with certain iterations rather than if statement?

I am trying to achieve a fairly complex layout. I've managed to do it but cant help think that the IF statement is a little lacking in refinement.
I have a for loop which loops through grid items, the first item and every 5th one are larger and every second large item is floated to the right rather than the left. There are four small items to every large one in a row (so the large is the same size as the four small).
I just think my IF isnt particularly elegant and also restricts the size of the grid.
$i = 0;
foreach ($items as $item) {
if ($i % 5 == 0) { ?>
<article <?php if ($i == 5 || $i == 15 || $i == 25 || $i == 35 || $i == 45 || $i == 55) { ?>style="float:right;" <?php } ?>>
//do big item
</article>
} else {
<article>
//do small item
</article>
}
$i++;
}
Im also trying to work out how I can wrap every row of 5 items in another div to help with sizing? I was thinking another block of if ($i % 5 == 0) { may help with this but Im conscious of loading times and best practice too.
As always any help greatly appreciated!
Just introduce a second mod operator. eg.
if ($i % 5 == 0){
if ( ($i-5) % 10 == 0 ){
// so this will work for values of %i = 5, 15, 25, 35 ...
// big article
}else{
// small article
}
$i++ ; // as previous comment #javad pointed out. You are not incrementing i

How can I loop through an array, starting at an offset and looping round again?

Newb question: I'm using a foreach loop to get items from an array.
I need to start looping at an offset number- (I'm using a $i variable to do this, no problem).
But when my foreach reaches the end of the array I want it to start going through the array again until it reaches the offset number.
I need to do this so I can have a user open any image in an artist's portfolio and have this image used as the first image presented in a grid of thumbnail icons , with all the other images subsequently populating the rest of the grid.
Any ideas?
Please bear in mind I'm new to PHP! :)
See below for an example of my current code...
$i=0;
$limit=50;// install this in the if conditional with the offset in it (below) to limit the number of thumbnails added to the page.
$offset=$any_arbitrary_link_dependant_integer;
foreach($portfolio_image_array as $k=>$image_obj){//$k = an integer counter, $image_obj = one of the many stored imageObject arrays.
$i++;
if ($i > $offset && $i < $limit) {// ignore all portfolio_array items below the offset number.
if ($img_obj->boolean_test_thing===true) {// OK as a way to test equivalency?
// do something
} else if ($img_obj->boolean_test_thing===false) { // Now add all the non-see_more small thumbnails:
// do something else
} else {
// error handler will go here.
}
} // end of offset conditional
}// end of add boolean_test_thing thumbnails foreach loop.
};// end of add thumbnails loop.
$i = 0;
$limit = 50;
$offset = $any_arbitrary_link_dependant_integer;
$count = count($portfolio_image_array);
foreach($portfolio_image_array as $k=>$image_obj){//$k = an integer counter, $image_obj = one of the many stored imageObject arrays.
$i++;
if ($i > $offset && $i < $limit && $i < ($count - $offset)) {// ignore all portfolio_array items below the offset number.
if ($img_obj->boolean_test_thing===true) {// OK as a way to test equivalency?
// do something
} else if ($img_obj->boolean_test_thing===false) { // Now add all the non-see_more small thumbnails:
// do something else
} else {
// error handler will go here.
}
} // end of offset conditional
}// end of add boolean_test_thing thumbnails foreach loop.
};
Only thing I added was a $count variable.
Edit: If your array starts at 0 I would suggest you put the $i++; at the end of your foreach loop.
A simple method is to use two separate numeric for loops, the first going from offset to end, and the second going from beginning to offset.
<?php
// Create an example array - ignore this line
$example = array(1,2,3,4,5,6);
$offset = 3;
// Standard loop stuff
$count = count($example);
for($i = $offset; $i < $count; $i++)
{
echo $example[$i]."<br />";
}
for($i = 0; $i < $offset; $i++)
{
echo $example[$i]."<br />";
}
?>
This is also almost certainly cheaper than doing multiple checks on every single element in the array, and it expresses exactly what you are trying to do to other programmers who look at this code - including yourself in 2 weeks time.
Edit: depending on the nature of the array, in order to use numeric keys you may first need to do $example = array_values($portfolio_image_array);.
Using Answer Question to force StackOverflow to let me post a decent length of text!
OK #Mark Walet et al, not sure how to post correctly on this forum yet but here goes. I got the issue sorted as follows:
$i=0;
$offset=$image_to_display_number;
$array_length = count($portfolio_image_array);
// FIRST HALF LOOP:
foreach($portfolio_image_array as $k=>$img_obj){// go through array from offset (chosen image) to end.
if ($i >= $offset && $i <= $array_length) {
echo write_thumbnails_fun($type_of_thumbnail, $image_path, $k, $i, $portfolio_image_array, $title, $image_original);
$t_total++;// update thumbnail total count.
}
$i++;
}// end of foreach loop 1.
$looped=true;// Just FYI.
$i=0;// Reset.
// SECOND HALF LOOP:
foreach($portfolio_image_array as $k=>$img_obj){// go through array from beginning to offset.
if ($i < $offset) {
echo write_thumbnails_fun($type_of_thumbnail, $image_path, $k, $i, $portfolio_image_array, $title, $image_original);
}
$i++;
}// end of foreach loop 2.
Thankyou so much for all the help!
:)
as #arkascha suggested use modulo operator
<?php
$example = array(1,2,3,4,5,6);
$count = count($example);
$offset = 3;
for($i = 0; $i < $count; $i++) {
$idx = ($offset + $i) % count
echo $example[$idx]."<br />";
}
?>

PHP Explode function. If function

Could someone help suggest in below php explode function, we are displaying script after 5th listing. How is it possible to display script exactly after 5th listing and 10th listing on a page which has more than 10 listings
We tried using
if ($i == 5 & $i== 10)
but it does not work
Below is original code - which displays script after 5th listing
<?php
$listings = explode("<hr/>", $list);
$numberOfListings = count($listings);
for($i = 0; $i < $numberOfListings; ++$i)
{
if ($i == 5)
{ ?>
<script> </script>
<?php }
echo $listings[$i] . "<hr/>";
}
?>
Edit
How is it like - if have to display a separate script on $i==9, could you advise.
Because $i starts at 0 (0 to 9 is 10, whilst 0 to 10 is 11). Try if ($i == 4 || $i== 9), with an or operator.
Also I would not use the && (the and operator), because it is unlikely $i will ever equal both 4 and 9. I'd suggest you read into Truth Tables (and maybe Propositional Calculus) because from seeing what you had tried originally, it would be helpful to understand how a truth table works.
(source: wlc.edu)
You can use the contine, continue is used within looping structures to skip the rest of the current loop iteration and continue execution at the condition evaluation and then the beginning of the next iteration.
$arr = range(0,9);
foreach($arr as $number) {
if($number < 5) {
continue;
}
print $number;
}
Ref: http://php.net/manual/en/control-structures.continue.php
Try using modulus operator
$listings = explode("<hr/>", $list);
$numberOfListings = count($listings);
for($i = 1; $i < $numberOfListings; ++$i)
{
if ($i%5 == 0)
{
echo "in";
?>
<script> </script>
<?php
}
echo $listings[$i-1] . "<hr/>";
}
Here we are looping from 1 and there for $i <= $numberOfListings
and while listing we will use $listings[$i-1]
DEMO CODE AT http://codepad.viper-7.com/lrTOgP

show a divider at bottom of loop except for last item

So I know this is simple but I've been banging my head against the wall for a while trying to figure it out. I want to show a ruler at the bottom of my loop on each one except the last one. I can get it to work if I have the exact number of records but not if I have less. For example if the max number to show is 10 but there are only 5 records I want the divider after the 4th record. Likewise, if there are 20 results but max is 10 I want it after the 9th.
<?php $subscriberIDs = ba_getUsersByRole( 'subscriber' );
// Loop through each user
$i=0;
$max = 10; //max number of results
$total_users =count($subscriberIDs); //total number of records
foreach($subscriberIDs as $user) :
if($i<=$max) : ?>
<li>
<?echo $user['data'];?>
</li>
<?php
if(($i < $total_user-1 && $max >= $total_users) || ($i < max-1 && $total_users <= $max)){echo "<hr>";}
$i++;
endif;
endforeach; ?
// <hr> goes in every spot, but not on the last item, up to 10
$position = min($max-1, count($subscriberIDs)-1);
$i = 0;
foreach($subscriberIDs as $user){
echo '<li>' . $user['data'] . '</li>';
if($i != $position){
echo '<hr>';
}
$i++;
}
This takes the lesser of either $max-1 or count($subscriberIDs)-1, which by definition is will be the last item you'll iterate over. If you have more than $max items, then this will be $max-1, if you have less than $max items, then this will be count(.)-1.
Then, during the iteration, the if statement prints an <hr> so long as the current item is not the last item.

Categories