Compare string value against array of strings in PHP/ Laravel? - php

I want to match string with array. I am retrieving the status code from status table in the database...I have a json file with code and name...Based on the status code returned from db i need to match this code in json file and display the status name in foreach
Please anyone help
Thanks
statuscodes array
[
{
"code":"0",
"name":"AB"
},
{
"code":"1",
"name":"CD"
},
{
"code":"2",
"name":"XY"
},
{
"code":"10",
"name":"EF"
},
{
"code":"12",
"name":"FG"
}
]
<?php $findproducts = \DB::table('status')->select('id', 'status_name', 'ab', 'status_code','created_at')->where('ab', $track->ab)->orderBy('id', 'DESC')->get(); ?>
String Pos....
#foreach($findproducts as $pr)
#if($statuscodes != null)
#foreach ($statuscodes as $stcode)
#if (strpos($pr->status_code, $stcode['code']) !== FALSE)
{{ $stcode['name']." " .$stcode['code'] }}
#endif
#endforeach
#endif
#endforeach
The output which i am getting from above is
CD 1 XY 2 FG 12
CD 1 AB 0 EF 10
XY 2
CD 1
AB 0
Expected Output should be
FG 12
EF 10
XY 2
CD 1
AB 0

Why are you doing:
#if (strpos($pr->status_code, $stcode['code']) !== FALSE)
{{ $stcode['name']." ".$stcode['code'] }}
#endif
Instead of:
#if ($pr->status_code === $stcode['code'])
{{ $stcode['name']." ".$stcode['code'] }}
#endif
I think your problem is strpos (I am not sure why you are using it). As the documentation says: Prior to PHP 8.0.0, if needle is not a string, it is converted to an integer and applied as the ordinal value of a character. This behavior is deprecated as of PHP 7.3.0, and relying on it is highly discouraged. Depending on the intended behavior, the needle should either be explicitly cast to string, or an explicit call to chr() should be performed.
I am not sure if your needle is being used as a number so it is messing things up...
Also, when the if is true and you print what you want, you can break the foreach so you don't waste time nor effort on iterating something that you know will never be true again until something changes. You can do so using #break.
#if($statuscodes != null)
#foreach($findproducts as $pr)
#foreach ($statuscodes as $stcode)
#if ($pr->status_code === $stcode['code'])
{{ $stcode['name']." ".$stcode['code'] }}
#break
#endif
#endforeach
#endforeach
#endif
See also that I have switched the foreach with the first if, because if you do not have $statuscodes, why are you going to iterate $findproducts and skip everything ? Don't even iterate it...

try this , it is more cleaner
first convert status code to collection and convert it so collection of key=> value pairs
this should be the status code collection
then look up your key using simple foreach loop.
Note I am not sure what is returned from database so you can change the code to suite the desired output.
also try to avoid nested loops as much as you can
$status_code = collect(json_decode('[
{
"code":"0",
"name":"AB"
},
{
"code":"1",
"name":"CD"
},
{
"code":"2",
"name":"XY"
},
{
"code":"10",
"name":"EF"
},
{
"code":"12",
"name":"FG"
}]'
,true))->pluck('code','name');
#foreach($findproducts as $pr)
{{$pr->status_code ." ". $status_code[$pr->status_code]}}
#endforeach

Related

How to limite foreach loop

How to print limited data with FOREACH
I have 10 data in db but, i want to print only first 3 data with foreach.
Also i tried and used array_slice() method, but next i got some errors.
Thank you!
#foreach($products as $_product)
//there is Html code... with variables
#foreach
I tried : #foreach(array_slice($products, 0, 2) as $_product). and i got:
array_slice() expects parameter 1 to be array, object given.
You can use limit(3) in your eloquent or take(3)
Or if you need to make it in blade use $loop variable
Like this
#if($loop->iteration <=3)
#continue
Or in your controller
Product::limit(3)->get();
Product::take(3)->get();
If u use it in controller there will be no need to check in your blade view
Just use the #break; statement once you've printed however many you want - it will jump you out of the foreach loop.
so something quick i can think of this:
#foreach($products as $_product)
//there is Html code... with variables
#if($loop->iteration == 3) //Thanks to the response of #MohammedAktaa
#break
#endif
#foreach
Although I think it should be best to limit the results from the query to the database.
Ordering, Grouping, Limit, & Offset

Laravel - blade check if object has relationship

In my controller I'm getting a complex query that filter data depending on input provided by the user:
if (conditionB) {
$query = Model::with('relationA', 'relationB');
} else {
$query = Model::with('relationA', 'relationC');
}
// checking filters and apply conditions...
$query = $query->get();
Now in my blade file I'm looping result and I want to display "eager load" relationship B or C:
#if (count($myObject->relationB)) {
<span>{{ $myObject->relationB->someField }}</span>
#else
<span>{{ $myObject->relationC->someField }}</span>
#endif
It works, but if my $myObject has relationC and not relationB, then
during the verification of the if condition the relationship is loaded.
How I can avoid loading that relationship??
when I do: {{ $myObject }}
It gives me:
// has relationB
"field1": value1,
"field2": value2,
....
"fieldx": valuex,
"relation_b":[
{
"relationBfield1": relationBvalue1,
"relationBfield2": relationBvalue2,
},
{ ... }
// doesn't have relationB
"field1": value1,
"field2": value2,
....
"fieldx": valuex
I tried access relation_b (note that json is changing name by replacing UpperCase for _<LowerCase>) but it returns NULL, but if I access relationB it shows data:
myObject->relation_b; // NULL
myObject->relation_b[0]; // NULL
myObject->relationB; // works, but if item has RelationC it will "eager load" relationship B just to check that if condition
I was trying different options, and I don't see where I make mistake, I also tried to create a public function in my model:
{{ $myObject->checkRelation() }}
public function checkRelation()
{
if (count($this->relationB) > 0) {
// code...
But I always end up with the same problem, when object item doesn't have relationB it will load it to check that if condition.
How can I avoid it? Or there is another way to check with relation has my object item without executing an additional query?
If you want to check if a relationship has been loaded you can use the relationLoaded() method on the model:
#if ($myObject->relationLoaded('relationB')) {
<span>{{ $myObject->relationB->someField }}</span>
#else
<span>{{ $myObject->relationC->someField }}</span>
#endif

PHP variable is not assigned

I'm working on a laravel project.
now I want to access one of my column which is data
The data colmn contains an array of stuff like message, klant_address, reactionPlacer and more.
foreach(Auth::user()->unreadNotifications as $notfiy) {
{{ $notify->data['klant_address'] }} //This gives an error "variable is not assigned"
}
but if i store it first to a variable it does'nt gives an error like this
foreach(Auth::user()->unreadNotifications as $notfiy) {
$klantAddress = $notify->data['klant_address']
echo $klantAddress
}
Now comes the weirdest part of all
if i do
dd($notify->data['klant_address']) <-- this does gives me the signle string return
and
foreach(Auth::user()->unreadNotifications as $notfiy) {
{{ $notfiy->data['messages'] }} <--- This does output
}
does work.
I hope someone can help me or at least explain why this is happened. Because I'm so confused for it.
thanks in advance.
Error Page
Database Table
Looks more like JSON to me. (Look at the last image)
Try this:
{{ $notify->data->klant_address ?? '' }}
If that doesn't work, try {{ json_encode($notify->data)->klant_address ?? '' }}
(Thrown in ternaries to help with nulls etc.)

How to handle Undefined Offset in laravel?

I am getting this error when I land on the page after logging in:
ErrorException in compiled.php line 11573: Undefined offset: 0 (View:
C:\xampp\htdocs\campusguru\resources\views\home.blade.php)
I know that the cause of this error is the empty variable that I passed to the view.
I have already tried:
if(isset($blog)) { do something }
and in blade view as:
{{ $blogs[0]->title or '' }}
Is there anyway I could handle this error. Or is there a better way of doing it?
Try the following:
{{ isset($blogs[0]) ? $blogs[0]->title : '' }}
If you are using a foreach to get every $blog->title use
#foreach ($blogs as $blog)
{{ $blog->title }}
#endforeach
The problem is that $blogs is actually defined and its value is [] (i.e. empty array) so it means that isset($blogs) statement will evaluate to true. Same thing is valid for collections. If a collection is empty (i.e. has no elements but it's defined) isset($blogs) will still evaluate to true but accessing $blogs[0] will cause an Undefined offset: 0 error.
You could try the following solutions:
Using count
if(count($blogs)) { /* do something */ }
if $blogs = [] or $blogs = null the function count will return zero so that means that $blogs is empty.
Using empty
if(!empty($blogs)) { /* do something */ }
This is the equivalent of writing !isset($var) || $var == false as described in the PHP Manual - empty:
Returns FALSE if var exists and has a non-empty, non-zero
value. Otherwise returns TRUE.
The following things are considered to be empty: "" (an
empty string) 0 (0 as an integer) 0.0 (0 as a
float) "0" (0 as a string) NULL
FALSE array() (an empty array) $var; (a
variable declared, but without a value)
Checking if a collection is empty
If $blogs is a Collection is sufficient to check if it is not empty using `isNotEmpty() method:
#if($blogs->isNotEmpty()) <!-- Do your stuff --> #endif
EDIT
I forgot to add the blade syntax:
#if(count($blogs)) <!-- Do whatever you like --> #endif
or
#if(!empty($blogs)) <!-- Do whatever you like --> #endif
EDIT 2
I'm adding more content to this answer in order to address some of the issues presented in the comments. I think that your problem is the following:
$blogs is an empty collection, so it's defined but it has no elements. For this reason the if(isset($blogs)) statement will evaluate to true passing the first if condition. In your blade template you are making the check {{ $blogs[0]->title or '' }} that is absolutely not equal to <?php isset($blogs[0]->title) ? $blogs[0]->title : '' ?> as pointed out in the comments, but it is an expression that will return true or false, so it will never print out title parameter even if $blogs[0] exists. The problem here is that when checking the condition $blogs[0]->title you are actually accessing the element 0 of the $blogs collection that will trigger the exception Undefined offset: 0 because the collection is actually empty. What i was saying is that in addition to the
if(count($blogs)) { /* do something */ }
(that checks that $blogs is set and that it's length is greater than 0) in your template you should do
{{ isset($blogs[0]->title) ? $blogs[0]->title : '' }}
or more concisely
{{ $blogs[0]->title ?: '' }}
assuming that the control flow will arrive there only if the $blogs passed the first if. If the issue still persists the problem is elsewhere in your code IMHO.
You can simply solve this with the data_get() helper.
For example:
php artisan tink
Psy Shell v0.8.11 (PHP 7.0.22-0ubuntu0.16.04.1 — cli) by Justin Hileman
>>>
>>> $a = collect([[], null, App\Models\User::find(1)]);
=> Illuminate\Support\Collection {#887
all: [
[],
null,
App\Models\User {#896
id: 1,
name: "user1",
email: "user1#thisisdevelopment.nl",
last_name: "Gabrielle",
first_name: "Rempel",
deleted_at: null,
created_at: "2017-08-12 15:32:01",
updated_at: "2017-09-05 12:23:54",
},
],
}
>>> data_get($a[0], 'name', 'nope');
=> "nope"
>>> data_get($a[1], 'name', 'nope');
=> "nope"
>>> data_get($a[2], 'name', 'nope');
=> "user1"
>>>
So in this case:
{{ data_get($blogs[0], 'title', '') }}
data_get() will work both on arrays and objects, returning the key or attribute defined in the second param (this can be laravel.dot.notation.style, or just an array), the 3rd param will be the default return value if the object/array or the key/attribute does not exist, the default is null.
Edit:
Just saw the request for the extra explanation on why the original code wasn't working.
Index 0 simply does not exist on the array/collection that is passed to the view.
>>> $a = [1 => App\Models\User::find(1)];
=> [
1 => App\Models\User {#890
id: 1,
name: "user1",
// ... etc
},
]
>>> $a[0]->name ?: 'nope';
PHP error: Undefined offset: 0 on line 1
>>> $a[1]->name ?: 'nope';
=> "user1"
It doesn't matter if OP used the blade or default, it doesn't even make it to the ternary statement because of the missing 0 index on $blogs.
Edit 2 as requested:
So the reason you get the Undefined offset: x error is because of the order in which PHP evaluates the code.
Blade's or default is behind the scenes nothing more than a ternary statement:
return preg_replace('/^(?=\$)(.+?)(?:\s+or\s+)(.+?)$/si', 'isset($1) ? $1 : $2', $value);
So this will make:
isset($blogs[0]->title) ? $blogs[0]->title : ''
isset() will check if title on the object is set, but to do so, it will require $blogs[0] to be a valid object. In order to do that, it will try and get the object from the $blogs array at index 0. But since this index does not exist, it will trigger the Exception with an Undefined offset: 0.
In order to make this work with Blade's or default, you would first have to ensure that $blogs[0] is defined (and preferably also check that it's an object, otherwise you'll get the trying to get property of non-object error, please note that this should not be the responsibility of the view), after that you would be able to use the or default as you would any other time.
#if (isset($blogs[0]) && is_object($blogs[0]))
{{ $blogs[0]->title or '' }}
#else
// some other default placeholder
#endif
Basically you will get the same offset error when using data_get(), because index 0 still does not exist.
{{ data_get($blogs[0], 'title', '') }} // Undefined offset: 0
You could play dirty and do this (this would not pass any code review anywhere and I should not have typed this at all, this is just to illustrate)
{{ data_get($blogs, '0.title', '') }} // Will display '' as it will check if key 0 exists
Anyway, with data_get() you would still end up doing something like this, as you would need to make sure $blogs[0] is something you can work with:
#if (isset($blogs[0]))
{{ data_get($blogs[0], 'title', '') }}
#else
// some other default placeholder
#endif
Bottomline, the best option would be not to rely on indexes like this in your view, this is simply not the responsibility of your view.
Blade's or default works perfectly on single variables, but when dealing with object attributes, you would just have to make sure the (parent) object exists when doing so.
I do this way in controller:
if (empty($allFares) || count($allFares)==0){
return back()->withError('No Fare Found For The City!');
}
OR in blade:
#if (!empty($allFares) || count($allFares)>0)
#foreach(allFares as $key=>$value)
#endforeach
#endif
If you have an object that's passed to the view and let's say your data is "posts" which is being held inside an object like this:
$obj->posts.
If you then go and do a foreach loop which would iterate trough every post and print out its parameters like in the example below it works perfectly well when you actually have posts.
#foreach($obj->posts as $post)
<h1>$post->title</h1>
<p>$post->content</p>
#endforeach
Before doing the loop you'd want to check if attribute has been set with values. You can use isset() for this, and since it's a special form it can be used as isset($obj->posts) or isset($obj->posts[0]). The difference is that the latter will only check if the array key has any value so if your index key is anything but 0, it'll return false. For instance you have:
$foo = ['first' => somevalue1, 'second' => somevalue2];
isset($foo[0]); //returns false
isset($foo['first']); //returns true
isset($foo); //returns true
The way I'd make the check is the following:
#if(isset($obj->posts))
#foreach($obj->posts as $post)
...
#endoforeach
#endif
As of PHP7 you can use null coalescing operator ?? for checking ternary conditions:
#if($posts?? '')
#foreach($posts as $post)
<h1>$post->title</h1>
<p>$post->content</p>
#endforeach
#endif
And if you want to print any variable directly then check first that the variable exists or not in condition, so you can do as below:
{{ $blogs && $blogs[0]->title ? $blogs[0]->title : '' }}
For simply solving the issue use the # operator (error control operator)
{{ #$blogs[0]->title }}
The # error control operator (also called STFU operator with mixed feelings), that suppresses errors just for the expression that immediately follows.

ElseIf statement with laravel

I have the following foreach loop that I'm getting good results with however when it gets to the elseif statement I'm attempting to see if two of the players are on the same team or not and if they are then have them listed together separated with a & symbol. Currently I am getting the following still.
Player 1 vs. Player 2 vs. Player 3 vs. Player 4
This is okay however Player 1 and Player 2 are on the same team. So its not seeing them as on the same team for some reason. Does someone see what my issue is?
#foreach ($match->players AS $key => $player)
#foreach ($player->list as $member)
{{ $member->player_name }}
#endforeach
#if($match->players->count() - 1 != $key)
vs.
#elseif ($match->players[$key - 1]->team_id == $player->team_id)
&
#endif
#endforeach
EDIT: I changed the data a little but still should work.
http://pastebin.com/AdyzemC4
It was tricky to puzzle together your $match variable :)
#if($match->players->count() - 1 != $key)
Your $match->players->count() is always equal to the value of the number of players(say 'n'). So your 'if' ONLY checks the 'n-1' != current key ($key). [Which is true except for the last key, so you get all 'vs'].
This should work:
#foreach ($match->players AS $key => $player)
#foreach ($player->list as $member)
{{ $member->player_name }}
#endforeach
#if($player->team_id != $match->players[$key + 1]->team_id)
vs.
#elseif ($player->team_id == $match->players[$key + 1]->team_id)
&
#endif
#endforeach
In this we are checking if the current player's team is the same as the next player's team [$key+1].
Note:
You need to stop the loop for the last player, since $key+1 will go outside your array and you will get an offset error.
Therefore add another if:
#foreach ($match->players AS $key => $player)
#foreach ($player->list as $member)
{{ $member->player_name }}
#endforeach
#if($key + 1 < $match->players->count())
#if($player->team_id != $match->players[$key + 1]->team_id)
vs.
#elseif ($player->team_id == $match->players[$key + 1]->team_id)
&
#endif
#endif
#endforeach

Categories