Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

stanhook's avatar

Using foreach and breaking out if it if a value is not found

I and new to PHP and Laravel and I think I am missing something basic. I have a foreach:

@foreach($features as $feature)
	@if( $feature->MapNum == $map->MapNum )
		{{ $feature->FeNum }} {{ $feature->FullFeType }}
		<br />
	@endif
@endforeach

So it loops through all the items and when it finds a match it shows the information. But if there isn't a matching number I just want to state it isn't available. Right now if I do that it repeats the message a bunch of times.

Thanks, Stan

0 likes
30 replies
Sinnbeck's avatar

Try adding this

@php break; @endphp
Sinnbeck's avatar

But a better solution and one I would recommend, is to find the feature in the controller, and just pass it from there

'mapFeature' => $features->filter(fn($item) => $item->MapNum == $map->MapNum)->first(),
stanhook's avatar

@sinnbeck I can break it but I want to show a message. That doesn't seem to allow me to do that.

Sinnbeck's avatar

@stanhook If none are found? Yeah thats why you should filter in the controller. Then you can do an if/else

stanhook's avatar

@Sinnbeck Okay, thanks. I will have to figure that out. Right now this is what I have:

$featuresDataSql = "SELECT DISTINCT trelMapFe.Site, trelMapFe.MapNum, trelMapFe.SUNum, 
                                    CASE
                                        WHEN tblFeature.HRONum IS NULL THEN tlkpFeTyp.FeTyp
                                        WHEN tblFeature.HRONum IS NOT NULL THEN 
                                            CONCAT(tlkpFeTyp.FeTyp, ' ', tblFeature.HRONum)
                                    END AS FullFeType, 
                                    trelMapFe.FeNum
                                FROM tlkpFeTyp 
                                INNER JOIN (tblFeature 
                                    INNER JOIN (tblMap 
                                        INNER JOIN trelMapFe ON (trelMapFe.Site = tblMap.Site) 
                                        AND (tblMap.MapNum = trelMapFe.MapNum)) 
                                    ON (tblFeature.FeNum = trelMapFe.FeNum) 
                                    AND (tblFeature.SUNum = trelMapFe.SUNum) 
                                       AND (tblFeature.Site = trelMapFe.Site)) 
                                ON tlkpFeTyp.FeTypCode = tblFeature.FeTypCode
                                WHERE tblMap.Site LIKE :id $mapNumFe AND tblMap.MapElec = 'True'
                                ORDER BY trelMapFe.FeNum";

        $featuresDataSql = DB::getPdo()->prepare($featuresDataSql);
        $featuresDataSql->setFetchMode(\PDO::FETCH_OBJ);
        $featuresDataSql->execute([
            'id' => $id,
        ]);

        $features = collect($featuresDataSql->fetchAll());

Can you point to docs that can help?

Sinnbeck's avatar

@stanhook I would recommend you start by learning how laravel works. :) No need to use raw pdo

But show what your are passing the to view instead :)

stanhook's avatar

@Sinnbeck Thanks. i have been going through tutorials and the docs. There is a long explanation but this is the way I need to do it. We rebuilt a site that was using APS.Net / T-SQL. I have done this 100 times. I just need to stop the foreach if there isn't a matching number and show a message. First time I needed to do this.

Thanks for the help!

Sinnbeck's avatar

@stanhook No worries. I would like to help but I need to see how your are passing data to the view and I bet I can help :)

stanhook's avatar

@Sinnbeck So I posted the query in my controller and then I return it like this:

->with('features', $features)

And then I run the foreach I posted first. Is that what you are talking about?

stanhook's avatar

@Sinnbeck Oh, sorry. It is a different query and is at the beginning of my content in a foreach.

@foreach( $maps as $map )
<div class="table-container">
                                <div class="item">
                                    <div class="column-title">
                                        <p>
                                            <a href="qrymapzoom?Filename=maps/{{ $map->Site }}/Map{{ $map->MapNum }}.tif&zoom=0.25&Site={{ $map->Site }}&MapNum={{ $map->MapNum }}&MapType={{$formData['view']}}">
                                                Map {{ $map->MapNum }}
                                            </a>
                                        </p>
                                    </div>
                                    <div class="column"><p><strong>{{ $map->MapTitle }}</strong></p></div>
                                </div>
blah, blah,blah...

Thanks, Stan

Sinnbeck's avatar

@stanhook This would be way easier if you were using eloquent and relationships. Maybe try something like this.

@php 
$feature = features->filter(fn($item) => $item->MapNum == $map->MapNum)->first())
@endphp
@if( $feature )
		{{ $feature->FeNum }} {{ $feature->FullFeType }}
		<br />
@else
   None found	
@endif
stanhook's avatar

@Sinnbeck I placed that in my foreach and it didn't work. All it does is repeat the same information - the first thing in the array.

In my case there could be multiple maps returned with each map having either none or 1+ features. If there isn't a match I just want to state that there is no data available.

Mega_Aleksandar's avatar

Hi, As @sinnbeck suggested, you should first check if there are any 'features' or 'maps' then iterate over them in the foreach. Your current logic expects that you ALWAYS have something to iterate over, while you are not sure if that is going to happen, so, as stated, you should check if you actually have something to iterate over, if not - display the message - either check with a count() on the array or filter them.

stanhook's avatar

@Mega_Aleksandar Hi, So I have this:

@if( count($features) != 0 )
	@foreach($features as $feature)
		@if( $feature->MapNum == $map->MapNum )
 			{{ $feature->FeNum }} {{ $feature->FullFeType }}
			<br />
		@endif
@endforeach
@else
	Not Available
@endif

And Yes, there will always be Features and possibly many for a particular number, just maybe not for that particular number. Which is why if there isn't a Feature I want to add the 'Not Available' text.

Snapey's avatar

@stanhook. suggest

	@forelse($features as $feature)
 			{{ $feature->FeNum }} {{ $feature->FullFeType }}

    		@if( $feature->MapNum != $map->MapNum )
                	Not Available
            @endif
			<br />
    @empty
        No Features
    @endforelse

You should tell the user which entry is not found rather than just abruptly terminating the loop, but I don't know what $map is. Is it another list? Do you need to see if map contains feature?

Mega_Aleksandar's avatar

@stanhook Since you are already doing a with('features') it might be a good idea to check that count and pass the identifier of features or maps that currently do not have that available (aka, a prop with 'noFeaturesYet'=>[{ids of maps that dont have features}]; and then in the foreach check the mapid before checking the feature->mapNum and map->mapNum. I am just throwing ideas...

tykus's avatar

@stanhook are you doing something else with this Collection that requires you to have potentially many Features passed to the view? If not, then you could modify the query to fetch a single result rather than iterating over the Features Collection.

What is the reason the @sinnbeck suggestion to filter the Collection is not suitable; it does exactly what you need according to your description;?

1 like
stanhook's avatar

@tykus So yes, I could have many features. I added some more clarification on a post below.

All filtering the collection did was return and repeat the first result (unless I did it wrong). There could be many different features for this particular map.

@foreach($features as $feature)
		@php
				$feature = $features->filter(fn($item) => $item->MapNum == $map->MapNum)->first();
		 @endphp
		@if( $feature )
				{{ $feature->FeNum }} {{ $feature->FullFeType }} <br />
		@else
				None found
		 @endif
@endforeach

If I do it outside I get the same result, the first item only once.

stanhook's avatar

Thank you all for your help and questions. Maybe I should be doing something different.

NOTE: I tried something different in the next post.

I have a site that could have many different maps. When I link is clicked all of the associated maps for that site are shown (using parameters in the URL for the query). Each map has various attributes - title, location, features, associated structures, etc - and each has its own query. Sometimes a map may not have one or more of those attributes.

I run a query at the beginning that gets all of the maps (and map numbers) associated with that site:

@foreach( $maps as $map )

In that foreach are other queries that are run to get all of the other data. Like $features:

$featuresDataSql = "SELECT DISTINCT trelMapFe.Site, trelMapFe.MapNum, trelMapFe.SUNum, 
                                    CASE
                                        WHEN tblFeature.HRONum IS NULL THEN tlkpFeTyp.FeTyp
                                        WHEN tblFeature.HRONum IS NOT NULL THEN 
                                            CONCAT(tlkpFeTyp.FeTyp, ' ', tblFeature.HRONum)
                                    END AS FullFeType, 
                                    trelMapFe.FeNum
                                FROM tlkpFeTyp 
                                INNER JOIN (tblFeature 
                                    INNER JOIN (tblMap 
                                        INNER JOIN trelMapFe ON (trelMapFe.Site = tblMap.Site) 
                                        AND (tblMap.MapNum = trelMapFe.MapNum)) 
                                    ON (tblFeature.FeNum = trelMapFe.FeNum) 
                                    AND (tblFeature.SUNum = trelMapFe.SUNum) 
                                       AND (tblFeature.Site = trelMapFe.Site)) 
                                ON tlkpFeTyp.FeTypCode = tblFeature.FeTypCode
                                WHERE tblMap.Site LIKE :id AND trelMapFe.MapNum IN ('" . $mapNumFeDataString . "')"AND tblMap.MapElec = 'True'
                                ORDER BY trelMapFe.FeNum";

        $featuresDataSql = DB::getPdo()->prepare($featuresDataSql);
        $featuresDataSql->setFetchMode(\PDO::FETCH_OBJ);
        $featuresDataSql->execute([
            'id' => $id,
        ]);

        $features = collect($featuresDataSql->fetchAll());

return view(name of view) ->with('features', $features)

I compare trelMapFe.MapNum to the map number in $map to show the features.

In some cases (like $features) I am matching that attribute with a number(s) from $map. When I match that number there could be many results for that attribute that need to be displayed, like the foreach I am asking about.

@if( count($features) != 0 )
	@foreach($features as $feature)
		@if( $feature->MapNum == $map->MapNum )
			{{ $feature->FeNum }} {{ $feature->FullFeType }}
			<br />
		@endif
	@endforeach
@else
	 Not Available
@endif

Sometimes there may not be any information and I just wanted to show a message that it wasn't available.

Does that help?

stanhook's avatar

@mega_aleksandar So I check in my controller for the maps and pull the features based on the maps being returned. I go over that array in my view. This works except that since some if the maps have features and some don't I can't figure how to show a message for the ones that don't.

I can do this:

@foreach($features as $feature)
		@if( $feature->MapNum == $map->MapNum )
				{{ $feature->FeNum }} {{ $feature->FullFeType }}
		@else
				Not Available
		@endif
@endforeach

But not available just gets repeated for how many items are in the array.

suggestions?

Snapey's avatar

@stanhook You just literally posted your initial code.

We get that, we understand it. We don't understand what you are trying to do

you are iterating over a set of features and comparing each to the map-->MapNum (a single value)

if $map->mapNum = 'xyz'

and features = 'abc', 'def', 'hij','klm', 'nop' etc then maybe you never find an 'xyz' and it says not available for every try.

stanhook's avatar

@Snapey Yes, I did re-post the code. I changed my controller so now I am only return features (if any) that belong to the map(s) instead of all the features for all the maps. I thought that would make a difference and I was just trying to keep things together, sorry.

There could be many maps retuned for a site. Each map could have no features or 1+.

if $map->mapNum = 'xyz'

and that has 4 features it should show them.

if $map->mapNum = 'pdq'

and it has no features I want to display a message.

Does that help?

Mega_Aleksandar's avatar

@stanhook You should be able to pass to the $map itself a features property, so that you can check if they exist (0 or 1+) and based on that, you can display a message or iterate over them. So you would not even need the if $feature->mapNum == $map->mapNum since you have the features nested under the map.

stanhook's avatar

@Mega_Aleksandar Okay, that sound promising but how would I do that? I started to compare arrays but I don't think that will work.

Keep in mind that $map and $features could have many results.

stanhook's avatar

I tried this but it adds Not Available to each one once. So the ones that have features it also adds Not Available and the ones the don't it shows Not Available.

@if( count($features) != 0 )
	@php $noFeature = false; @endphp
	@foreach($features as $feature)
		@if( $feature->MapNum == $map->MapNum )
			 {{ $feature->FeNum }} {{ $feature->FullFeType }}<br />
		@elseif( $feature->MapNum != $map->MapNum )
			@php $noFeature = true; @endphp
		@endif
	@endforeach
	@if($noFeature)
		Not Available
	@endif
@endif
Snapey's avatar

Keep in mind that $map and $features could have many results.

but you are always testing the same map value?

stanhook's avatar

@Snapey I am not sure I understand your question, sorry. Maybe this will help, here is what I get in my view when I do the query. There are about 50 maps returned:

The first has Features and not Horizontal Units. The next one is the opposite. The third has both. If there aren't any Features I want to have a message. does that help?

Please or to participate in this conversation.