I have a few questions about how Laravel works - php

I hope you are well. I am currently learning Laravel 8, and am of course encountering some small complications while learning. I would like to understand the following:
What does "{{ ... }}" mean? I understand the principle, of putting PHP in HTML, but how does it work? What does the "{{ }}" mean?
What does "#if", "#foreach" mean? I also understand the principle of putting a conditional aspect within a file, but what does "#" represent?
I have a particular problem, and when I search on the internet, I quickly come across PHP version problems (and I confess I don't believe it):
For example, I make a complete pagination system, and when I set up a foreach to set up my page numbers, it returns me an error:
#if ($paginator->hasPages())
<ul class="pagination">
#foreach ($elements as $element)
#if (is_string($element))
<li class="page-item disabled"><span class="page-link">{{ $element }}</span></li>
#endif
#if (is_array($element))
#foreach ($element as $page => $url)
<li class="page-item">
{{ $page }}
</li>
#endforeach
#endif
#endforeach
</ul>
#endif
 
Now, if I put this:
#if ($paginator->hasPages())
<ul class="pagination">
#foreach ($elements as $element)
#if (is_string($element))
<li class="page-item disabled"><span class="page-link">{{ $element }}</span></li>
#endif
#if (is_array($element))
#foreach ($element as $page => $url)
<li class="page-item">
{{ $page ?? '' }}
</li>
#endforeach
#endif
#endforeach
</ul>
#endif
Now it works properly. If I replace the elements like the first text quote, then it's no longer a problem...
Could it be the cache? From the update of the server pages without restarting it with Laravel 8?
I thank you in advance for your help. I come here as a last resort, without knowing what to write on the internet, without finding a very logical and coherent answer...
Thanks 🙏
Typical example of an error that I have right away:
ParseError
syntax error, unexpected ' ' (T_STRING), expecting ')' (View: /Applications/MAMP/htdocs/Laravel/Site/resources/views/vendor/pagination/custom.blade.php)
In the code, I wrote this:
#if ($paginator->onFirstPage())
#else
<li class="page-item">
<a href="{{ $paginator->previousPageUrl() }}" rel="prev" class="page-link">
Précédent
</a>
</li>
#endif
For it to work I have to put : {{ $paginator->previousPageUrl() ?? '' }}

Blade templates
Those "{{ ... }}" and "#" are just statements by which laravel template engine called blade knows what to do with provided statement.
You can read documentation of blade here.
Blade's {{ }} echo statements are automatically sent through PHP's htmlspecialchars function to prevent XSS attacks.
"{{ ... }}" is called echo statement. So:
{{ $variable }}
is translated to something like this:
<?php echo htmlspecialchars($variable )?>
#if, #for, #foreach are replaced to something like this:
<?php foreach($variable as $key => $value) { ?>
// template that you put inside
<?php } ?>
and so on.
Null coalescing operator
Errors with your functions that you claim that you have to put ?? '' are caused that probably value of function / function itself is null.
The ?? operator checks for nulls (what you can read here):
The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not null; otherwise it returns its second operand.

Related

When using the blade structure in Laravel 9, I get the error "Undefined variable $__env"

There is no problem when I get php's own tags instead of '#' tags. Can anyone make sense of this?
<?php function buildCategory($parent, $category){ ?>
#isset($category['parent_cats'][$parent])
<ul>
#foreach ($category['parent_cats'][$parent] as $cat_id)
#foreach ($category['userPagePerms'] as $userPagePerm)
#if (!isset($category['parent_cats'][$cat_id]))
<li data-jstree='{"selected":{{ ($userPagePerm->backend_page_permission_id == $cat_id) ? 'true' : 'false' }},"opened":true}'>
<a href='{{$category['categories'][$cat_id]->id }}'> {{ $category['categories'][$cat_id]->name}}</a>
</li>
#endif
#if (isset($category['parent_cats'][$cat_id]))
<li data-jstree='{"selected":{{ ($userPagePerm->backend_page_permission_id == $cat_id) ? 'true' : 'false' }},"opened":true}'>
<a href='{{ $category['categories'][$cat_id]->id }}'>{{$category['categories'][$cat_id]->name }}</a>
<?php buildCategory($cat_id, $category); ?>
</li>
#endif
#endforeach
#endforeach
</ul>
#endisset
<?php } buildCategory(0, $category); ?>
It worked when using PHP's own tags. I would expect it to work with the '#' tag.
The code snippet I was able to run. Only the foreach part is the problem.
<?php foreach ($category['parent_cats'][$parent] as $cat_id) {
<?php foreach ($category['userPagePerms'] as $userPagePerm) { ?>
Error ss : enter image description here

Undefined offset: 1 in CompilesLoops.php laravel 5

I have a services list. Now I want to add sub-services to services list. I have two tables 'services' and 'sub-services' with foreign key constraint 'service_id'. Now, I want to show the 'services' and related 'sub-services' in master.blade.php. For services it was working fine, but, when trying with sub-services then getting this error. Would someone please help to get the expected result.
In master.blade.php-
<li class="dropdown"> Services
<ul class="dropdown-menu services-dropdown" role="menu">
#forelse(App\Model\Service::all() as $service)
<li class="dropdown-submenu">
{{ $service->title }}
<ul class="dropdown-menu sub-services">
#foreach(App\Model\SubService::where('service_id', '=',$service->id)->get()) as $subservice)
<li>
{{ $subservice->title }}
</li>
#endforeach
</ul>
</li>
#empty
#endforelse
</ul>
</li>
Two tables are here-
1.Services table
2.Sub-services table
You're using the wrong syntax. You're using redundant ) near the get(), so change it to:
#foreach(App\Model\SubService::where('service_id', $service->id)->get() as $subservice)
Also, as I say in my best practices repo, you shouldn't execute queries in a Blade template. Consider moving the logic to a controller.
This error also occurs when you don't close you loop correctly.
Use #foreach() to start a loop and #endforeach to close the same loop.
Its a bad way to write a logic part in blade file.I would suggest you to move it to controller because if in case you need to change the code you have to edit blade page.As well as please make use of relationship for fetching the data you can relate your Service with SubService
E.g
Service.php (model file)
public function subServices()
{
return $this->hasMany('App\SubService');
}
SubService.php (model file)
public function services()
{
return $this->belongsTo('App\Service','service_id');
}
your blade code:
#forelse(App\Model\Service::all() as $service)
<li class="dropdown-submenu">
{{ $service->title }}
<ul class="dropdown-menu sub-services">
#foreach($service->subServices as $subservice)
<li>
{{ $subservice->title }}
</li>
#endforeach
</ul>
</li>
#empty
#endforelse

How to display something only for the first item from the collection in Laravel Blade template

I have a #foreach loop in the Blade template and need to apply special formatting to the first item in the collection. How do I add a conditional to check if this is the first item?
#foreach($items as $item)
<h4>{{ $item->program_name }}</h4>
#endforeach`
Laravel 5.3 provides a $loop variable in foreach loops.
#foreach ($users as $user)
#if ($loop->first)
This is the first iteration.
#endif
#if ($loop->last)
This is the last iteration.
#endif
<p>This is user {{ $user->id }}</p>
#endforeach
Docs: https://laravel.com/docs/5.3/blade#the-loop-variable
SoHo,
The quickest way is to compare the current element with the first element in the array:
#foreach($items as $item)
#if ($item == reset($items )) First Item: #endif
<h4>{{ $item->program_name }}</h4>
#endforeach
Or otherwise, if it's not an associative array, you could check the index value as per the answer above - but that wouldn't work if the array is associative.
Just take the key value
#foreach($items as $index => $item)
#if($index == 0)
...
#endif
<h4>{{ $item->program_name }}</h4>
#endforeach
As of Laravel 7.25, Blade now includes a new #once component, so you can do it like this:
#foreach($items as $item)
#once
<h4>{{ $item->program_name }}</h4> // Displayed only once
#endonce
// ... rest of looped output
#endforeach
Laravel 7.* provides a first() helper function.
{{ $items->first()->program_name }}
*Note that I'm not sure when this was introduced. So, it may not work on earlier versions.
It is only briefly mentioned in the documentation here.
The major problem with Liam Wiltshire's answer is the performance because:
reset($items) rewind the pointer of $items collection again and again at each loop... always with then same result.
Both $item and the result of reset($item) are objects, so $item == reset($items) requires a full comparison of its attributes... demanding more processor time.
A more efficient and elegant way to do that -as Shannon suggests- is to use the Blade's $loop variable:
#foreach($items as $item)
#if ($loop->first) First Item: #endif
<h4>{{ $item->program_name }}</h4>
#endforeach
If you want to apply a special format to the first element, then maybe you could do something like (using the ternary conditional operator ?: ):
#foreach($items as $item)
<h4 {!! $loop->first ? 'class="special"': '' !!}>{{ $item->program_name }}</h4>
#endforeach
Note the use of {!! and !!} tags instead of {{ }} notation to avoid html encoding of the double quotes around of special string.
Regards.
if you need only the first element you can use #break inside your #foreach or #if.see example:
#foreach($media as $m)
#if ($m->title == $loc->title) :
<img class="card-img-top img-fluid" src="images/{{ $m->img }}">
#break
#endif
#endforeach
you can do it by this way.
collect($users )->first();
To get the first element of a collection in Laravel, you can use :
#foreach($items as $item)
#if($item == $items->first()) {{-- first item --}}
<h4>{{$item->program_name}}</h4>
#else
<h5>{{$item->program_name}}</h5>
#endif
#endforeach

Blade if(isset) is not working Laravel

Hi I am trying to check the variable is already set or not using blade version. But the raw php is working but the blade version is not. Any help?
controller:
public function viewRegistrationForm()
{
$usersType = UsersType::all();
return View::make('search')->with('usersType',$usersType);
}
view:
{{ $usersType or '' }}
it shows the error :
Undefined variable: usersType (View: C:\xampp\htdocs\clubhub\app\views\search.blade.php)
{{ $usersType or '' }} is working fine. The problem here is your foreach loop:
#foreach( $usersType as $type )
<input type="checkbox" class='default-checkbox'> <span>{{ $type->type }}</span>
#endforeach
I suggest you put this in an #if():
#if(isset($usersType))
#foreach( $usersType as $type )
<input type="checkbox" class='default-checkbox'> <span>{{ $type->type }}</span>
#endforeach
#endif
You can also use #forelse. Simple and easy.
#forelse ($users as $user)
<li>{{ $user->name }}</li>
#empty
<p>No users</p>
#endforelse
#isset($usersType)
// $usersType is defined and is not null...
#endisset
For a detailed explanation refer documentation:
In addition to the conditional directives already discussed, the #isset and #empty directives may be used as convenient shortcuts for their respective PHP functions
Use ?? , 'or' not supported in updated version.
{{ $usersType or '' }} ❎
{{ $usersType ?? '' }} ✅
Use 3 curly braces if you want to echo
{{{ $usersType or '' }}}
On Controller
$data = ModelName::select('name')->get()->toArray();
return view('viewtemplatename')->with('yourVariableName', $data);
On Blade file
#if(isset($yourVariableName))
//do you work here
#endif
You can use the ternary operator easily:
{{ $usersType ? $usersType : '' }}
#forelse ($users as $user)
<li>{{ $user->name }}</li>
#empty
<p>No users</p>
#endforelse
Use ?? instead or {{ $usersType ?? '' }}
I solved this using the optional() helper. Using the example here it would be:
{{ optional($usersType) }}
A more complicated example would be if, like me, say you are trying to access a property of a null object (ie. $users->type) in a view that is using old() helper.
value="{{ old('type', optional($users)->type }}"
Important to note that the brackets go around the object variable and not the whole thing if trying to access a property of the object.
https://laravel.com/docs/5.8/helpers#method-optional

laravel blade template variables

In working with laravel blade templates, what's the approved way to manage variables in output?
For example, I'm working on a view that shows upcoming chores / tasks for each farmer. The pivot table holds a due_at datetime field for the task, and I'd like to change the class of the item depending on whether it's overdue, done, etc.
#foreach ($farmer->tasks as $task)
#if ($task->pivot->due_at) < date(now))
$style = 'alert alert-danger';
#elseif ($task->pivot->due_at) > date(now))
$style = 'alert alert-success';
#else
$style = '';
#endif
<div class="list-group-item {{ $style }}">{{$task->name}} <span class="glyphicon glyphicon-calendar"> {{ $task->pivot->due_at }}</span> <span class="glyphicon glyphicon-pencil"></span><span class="glyphicon glyphicon-trash"></span></div>
#endforeach
This example throws an error: Undefined variable: style (View: /home/vagrant/Code/app/views/farmers/show.blade.php)
I don't see an obvious way to do simple code blocks to set variables like I'd do in a "normal" PHP view to define the class to apply to the task item by doing some basic calculations on the due_at value.
Should this logic be moved to a helper function or something?
Assume due_at is a timestamp.
#foreach ($farmer->tasks as $task)
#if (Carbon::parse($task->pivot->due_at) < Carbon::now())
<?php $style = 'alert alert-danger'; ?>
#elseif (Carbon::parse($task->pivot->due_at) > Carbon::now())
<?php $style = 'alert alert-success'; ?>
#else
<?php $style = ''; ?>
#endif
<div class="list-group-item {{ $style }}">{{$task->name}} <span class="glyphicon glyphicon-calendar"> {{ $task->pivot->due_at }}</span> <span class="glyphicon glyphicon-pencil"></span><span class="glyphicon glyphicon-trash"></span></div>
#endforeach
#Anam Your answer works, but I will use following method.
#user101289 Assuming that you have default layout and it yields content section. So to declare and use variables I would suggest you use vars section in your inner template file and declare all your variables all at once on the top. And then use it. Since we will not yield the section vars, it will not going to print it.
This will help you to keep track of variables used and its standard method to declare all variables on top and use in rest of the program:
#extends('layouts.default') /* Your default layout template file. */
#section("vars")
{{ $yourVar = 'Your value' }}
#endsection
#section("content") /* The content section which we will print */
// Your other HTML and FORM code and you can use variables defined in **vars** section
#endsection
#stop

Categories