A better way to improve blade template? - php

There are two type of packages that a customer can choose from: Phone packages or Broadband & Phone Packages.
When user ready to place an order, it will show a summary view with package name information and the cost. Some Summary information does not need to show if they select Phone package or Broadband & Phone Package.
Is there a better way to improve the readability and maintainable? For example
order-sidebar.blade.php
Note: This is small example of block of code. In the real application it is quite large with a lot of if statement broadbandphone or phone
#if ($summary['service'] == "phone" || $summary['service'] == "broadbandphone")
<div class="x5">
<h4>Phone Line x <span class="summary-lines">{{$summary['lines']}}</span></h4>
<ul class="clearfix">
#if ($summary['service'] == "phone")
<li>
<p class="x5-details">
#if ($summary['line_type'] == "newline")
New Line(s)
#endif
#if ($summary['line_type'] == "switch")
Switch line(s)
#endif
</p>
</li>
#endif
#if ($summary['service'] == "phone" && $summary['lines'] > 1)
<li>
<p class="x5-details">{{$summary['linesWithMulitpleNumbers']}}</p>
</li>
#endif
<li>
<p class="x5-details">{{$summary['package']->name}}</p>
<p class="x5-price">£{{$summary['monthlyLinesCost']}}</p>
</li>
</ul>
</div>
#endif
Or should I do two separate files for summary view like order-sidebar-phone.blade.php and order-sidebar-broadbandphone.blade.php
So it would be something like this:
#if ($summary['service'] == "phone")
#include('sections.order-sidebar-phone')
#end
#if ($summary['service'] == "broadbandphone")
#include('sections.order-sidebar-broadbandphone')
#end

You code looks okay to me. However here are some tips that might help reducing if's or making your code more readable.
Shorthand ternary if
Sometimes a shorthand if looks cleaner and more readable:
#if($summary['service'] == "phone")
Foo
#else
Bar
#endif
Can be written as:
{{ ($summary['service'] == "phone" ? "Foo" : "Bar") }}
It's especially useful for just little pieces of text that change depending on a condition.
Indentation
I shouldn't even need to say that. Indent your code right (not saying you didn't in your question...) And your if statements will be less confusing ;)
Partials
While it is an option to split it up completely like you suggested, this can cause a lot of duplicate code...
But you can also split your files so they are not as big and don't contain so many if statements (even if the total is still the same it's better structured and clearer)
For example instead of:
{{-- ... --}
</div>
#if ($summary['newSetup'] == false)
<div class="installation">
<h4>Phone Line x <span class="summary-lines">{{$summary['lines']}}</span></h4>
<ul class="clearfix">
<li>
<p class="installation-details">Installation</p>
<p class="installation-price">£{{$summary['installationCharge']}}</p>
</li>
</ul>
</div>
#endif
<div class="off-costs bg-gray">
<div class="off-costs-header clearfix">
{{-- ... --}}
Put the installation part in it's own file and include it:
{{-- ... --}
</div>
#if ($summary['newSetup'] == false)
#include('installation')
#endif
<div class="off-costs bg-gray">
<div class="off-costs-header clearfix">
{{-- ... --}}

Related

How to exclude certain styling in page2 in pagination

I have followed Jeffery Way in Laravel 8 from scratch amazing series but I'm having a trouble in pagination. In the index page we're making our latest post to have a specific styling and then first 2 posts comes after with a different styling and then rest of posts in different styling. The problem is that these styles are carrying over with us to page2 and 3 and ...etc
I want to make this to only posts in page1 or homepage and when I go to page 2 I should have a default styling for all posts.
This is the index
<x-bloglayout>
#include('posts.__header')
#if ($posts->count())
<x-featuredCard :post="$posts[0]" />
#if ($posts->count() > 1)
<div class="lg:grid lg:grid-cols-2">
<x-postCard :post="$posts[1]" />
<x-postCard :post="$posts[2]" />
</div>
<div class="lg:grid lg:grid-cols-3">
#foreach ($posts->skip(3) as $post)
<x-postCard :post="$post" />
#endforeach
</div>
#endif
{{ $posts->links() }}
#else
<p class="text-center">No posts matches your search, please check back later</p>
#endif
</x-bloglayout>
I tried to use if directive to say if route is home or ?/page1 do this if not do that but it doesn't seem to work.
This is my pagination:
public function index()
{
return view('posts.index', [
'posts' => Post::latest()->filter(request(['search', 'category', 'author']))->paginate(6)->withQueryString(),
]);
}
Thanks
You can use currentPage() method on paginator and check if it's on first page. May not be fanciest way but here is an example:
<x-bloglayout>
#include('posts.__header')
#if ($posts->count())
<x-featuredCard :post="$posts[0]" />
#if ($posts->count() > 1)
#if($posts->currentPage() == 1)
<div class="lg:grid lg:grid-cols-2">
<x-postCard :post="$posts[1]" />
<x-postCard :post="$posts[2]" />
</div>
#endif
<div class="lg:grid lg:grid-cols-3">
#foreach ($posts->skip($posts->currentPage() == 1 ? 3 : 0) as $post)
<x-postCard :post="$post" />
#endforeach
</div>
#endif
{{ $posts->links() }}
#else
<p class="text-center">No posts matches your search, please check back later</p>
#endif
</x-bloglayout>
You can check Paginator methods from Laravel 8.x document: https://laravel.com/docs/8.x/pagination#paginator-instance-methods

Add a block field from a specific article

I have an article, each article has article_blocks, the blocks have a video_link field
And I need to display this field in the list of articles
This is how the article list output is roughly implemented
<div class="blog-list">
#foreach($articles as $article)
<div class="blog-article">
<div class="video-button video-modal-button-blog" data-video="https://www.youtube.com/embed/{{ $article_block->video_link }}">
<span>Watch video</span>
</div>
<h2 class="blog-article__title">{{ $article->title }}</h2>
<span>{{ date('d F Y', strtotime($article->published_at)) }}</span>
<span>{{ $article->getTotalViews() }} Views</span>
</div>
#endforeach
</div>
Each article has a button to open a video, but this video field itself is not in the article itself, but in the article blocks
I now take this field from the block and output it, it turns out like this
<?php
use App\Models\ArticleBlock;
$article_block = ArticleBlock::whereNotNull('video_link')->first();
?>
<div class="blog-list">
#foreach($articles as $article)
<div class="blog-article">
#if ($article_block->video_link !== 'null')
<div class="video-button video-modal-button-blog" data-video="https://www.youtube.com/embed/{{ $article_block->video_link }}">
<span>Watch video</span>
</div>
#endif
<h2 class="blog-article__title">{{ $article->title }}</h2>
<span>{{ date('d F Y', strtotime($article->published_at)) }}</span>
<span>{{ $article->getTotalViews() }} Views</span>
</div>
#endforeach
</div>
As a result, I get this field with video and it is displayed, but the same video is displayed for all articles in the list, and each article should have its own field and its own video. How can this be fixed?
I probably need to look for something like blocks by article id
$article_block = ArticleBlock::where('article_id', $article->id)->whereNotNull('video_link')->first();
But I can't get id
Cant write comment, under 25 rep :(
data-video="https://www.youtube.com/embed/{{ $article_block->video_link }}"
This looks wrong. You should eager load article blocks (eager loading is generally faster than lazy loading) for all articles with a with statement in your eloquent query see: https://laravel.com/docs/8.x/eloquent-relationships#eager-loading
Then if everything is correct you should be able to do just {{ $article->block->video_link }} or something similar.
Above is right if article has only one article block (one to one relationship).
But it seems that article has multiple blocks (one to many relationship) so you would need to iterate over each of the article block as well with another #foreach statement.
#foreach($articles as $article)
#foreach($article->article_blocks as $block)
<p>URL of video is: https://www.youtube.com/embed/{{ $block->video_link }}</p>
#endforeach
#endforeach
Now lets answer your question why video is same everywhere? Because you've coded it as so. You should NEVER write custom queries in your blade files.
Here i am referring to this part of your code:
<?php
use App\Models\ArticleBlock;
$article_block = ArticleBlock::whereNotNull('video_link')->first();
?>
Queries should be either in controllers/services or repositories.
$article_block = ArticleBlock::whereNotNull('video_link')->first();
will just give you first article block defined in ur database where video_link is not null. It won't guarantee that ArticleBlock belongs to given Article.
Lets hope that i put you on the right path ^.^

Hiding <div> in laravel 7

In my home.blade.php file I have several div-s.And if the {{$user[0]->d1}} is 1 then the div must be hidden.But I have no idea how to do that.
{{$user[0]->d1}} //I want to have "if $user[0]->d1 == 1 ,then disable the following div
<div>Text 1</div>
Is it even possible(I don't want to use gates or cans)?
Update: You can actually also use the #unless directive which better translates your logic so you don't have to reverse the logic...
#unless ($user[0] == 1)
<div>Text 1</div>
#endunless
Other solution with #if directive:
You can simply use the #if directive like this:
#if ($user[0]->d1 != 1)
<div>Text 1</div>
#endif
Or even better (in case $user[0] might not exist):
#if (!isset($user[0]->d1) || $user[0]->d1 != 1)
<div>Text 1</div>
#endif

Ad Advertisement block after 4 Blocks automatically

I have website vokzo.com. I add apps block and one is advertisment block But Advertisement block only show one time on whole homepage at the top of apps block's.I want Advertisement block insert automatically after 4 apps blocks .Like when I add apps block's from admin panel after complete 4 blocks website should insert advertisement block automatically.I hope everyone will understand .Below is my index.blade.php file code please someone see and help me.Thank's
#extends( "layouts.master")
#section('content')
<div class="row">
<div class="navigation"> #include('web.home.partials.slider')
<ul>
<li>
<a href="/category/games">
<div class="icon" style="background: #F2B258;"><img src="https://static.apkpure.com/mobile/static/imgs/games.png" width="20"></div>
<div class="text">Hot Games</div>
</a>
</li>
<li>
<a href="/category/apps">
<div class="icon" style="background: #FA8484;"><img src="https://static.apkpure.com/mobile/static/imgs/apps.png" width="20"></div>
<div class="text">Hot Apps</div>
</a>
</li>
<li>
<a href="/category">
<div class="icon" style="background: #5EC9F3"><img src="https://static.apkpure.com/mobile/static/imgs/category.png" width="20"></div>
<div class="text">Category</div>
</a>
</li>
</ul>
</div>
{{-- Advertisement And Apps Block's Start --}}
{{-- ads start --}}
#include('common.ads-placement',[ 'identifier' => 'homepage-leaderboard'])
{{-- ads end --}}
{{-- Apps Block Start --}}
#include('web.home.partials.featured-apps')
{{-- Apps Block End --}}
{{-- Advertisement And Apps Block's END --}}
</div>
#endsection
#push('javascript')
#endpush
As far as I understand your question, you have a set of main blocks ($mainBlocks array) and a set of ad blocks ($adBlocks array) and in the view, you want to repeatedly show 4 main blocks and then, one ad block. Right?
That would be easy: just use a for loop for the main blocks and after each 4 main block, show one ad block. Some thing like this:
$adIndex = 0;
for ($i = 0; $i < count($mainBlocks); $i++)
{
//show a main block: inlcude('SHOW_MAIN_BLOCK', ['block' => $mainBlocks[$i]])
if ($i > 0 && $i % 4 == 0 && $adIndex < count($adBlocks))
{
//show an ad block: inlcude('SHOW_AD_BLOCK', ['block' => $adBlocks[$adIndex]])
$adIndex++;
}
}

Included blade template repeating in each foreach loop iteration

I'm using Blade templating with Laravel and I'm trying to use a #foreach loop to display notifications. The problem is that if I have say 10 notifications, the first notification is repeated 10 times.
The code to output each notification:
#foreach ( Auth::user()->unreadNotifications as $notification )
{{ $notification->type->web_template }}
{{ $notification->id }}
#include($notification->type->web_template)
#endforeach
web_template will output a path to the template: notifications.web.user_alert
For each iteration of the loop the {{ $notification->type->web_template }} and {{ $notification->id }} will output what they're supposed to but #include($notification->type->web_template) will only output the first notification each time.
So the output will look like:
156 notification.web.new_message
You have a new message from Joe.
154 notification.web.user_alert
You have a new message from Joe.
145 notification.web.new_like
You have a new message from Joe.
I think it's some sort of cache issue maybe, but I couldn't find anyone with the same problem.
Any ideas?
UPDATE: Adding some code
Example notification view:
#extends('layouts.notification-wrapper')
#section('url', url('jobs/'.$notification->job_id.'#highlight'.$notification->bid_id))
#section('image', '/assets/img/no-photo.jpg')
#section('header', $notification->collector->firstname . ' ' . $notification->collector->secondname)
#section('description')
has placed a bid of €{{ number_format($notification->bid()->withTrashed()->first()->amount,0) }} on your job.
#stop
Notification wrapper:
<li #if(!$notification->read)
class="unread"
#endif>
<a href="#yield('url')" data-id="{{ $notification->id }}">
<div class="pull-left">
<img src="#yield('image')" class="img-circle" alt="user image">
</div>
<h4>
#yield('header')
<small><i class="fa fa-clock-o"></i> {{ $notification->created_at->diffForHumans()}}</small>
</h4>
<p> #yield('description')</p>
</a>
</li>
Answering my own question!
Found this: Laravel Blade Templates Section Repeated / cache error
Basically whatever way it works I need to overwrite my sections when looping and using #yield... I think. So I need to replace #stop with #overwrite in my views.

Categories