Creating nested comments in laravel - laravel

I have the following blog control
public function show($slug)
{
$post = Blog::where('slugs', '=', $slug)->first();
$vars['pageTitle'] = Config::get('site.pageTitle') . $post['title'];
// The breadcrumbs... needs to be repopulated every page
$vars['breadCrumbs'] = [[
'url' => action('SimpleController#index'),
'title' => 'CovertDEV'
],[
'url' => action('BlogController#index'),
'title' => 'Blog'
],[
'url' => route('blog_post', ['slug' => $slug]),
'title' => $post['title']
]];
$vars['blog'] = $post;
$vars['comments'] = $post->Blog_comments->groupBy('comment_id');
return view('blog', $vars);
}
And the following scary view for the comments
#php
function display_comments($main, $depth = "\t")
{
foreach($main[0] as $mcomment)
{
#endphp
<div class="media">
<img class="m-3 avatar-sm rounded-1 border border-thick-1 shadow" src="../public/css/images/avatar-placeholder.png" alt="<?=$mcomment->firstname;?> <?=$mcomment->lastname;?>'s Avatar">
<div class="media-body">
<h6 class="mt-0 p-1 lead m-0 border-bottom"><?=$mcomment->firstname;?> <?=$mcomment->lastname;?></h6>
<div class="p-2">
<p><?=$mcomment->comment;?></p>
</div>
#php
if(isset($main[$mcomment->id]))
{
display_child($main, $main[$mcomment->id], $depth);
}
#endphp
</div>
</div>
#php
}
}
function display_child($main, $comment, $depth)
{
foreach($comment as $ccomment)
{
#endphp
<div class="media">
<img class="m-3 avatar-sm rounded-1 border border-thick-1 shadow" src="../public/css/images/avatar-placeholder.png" alt="<?=$ccomment->firstname;?> <?=$ccomment->lastname;?>'s Avatar">
<div class="media-body">
<h6 class="mt-0 p-1 lead m-0 border-bottom"><?=$ccomment->firstname;?> <?=$ccomment->lastname;?></h6>
<div class="p-2">
<p><?=$ccomment->comment;?></p>
</div>
#php
if(isset($main[$ccomment->id]))
{
display_child($main, $main[$ccomment->id], $depth."\t");
}
#endphp
</div>
</div>
#php
}
}
display_comments($comments);
#endphp
That is as ugly as it gets. It generates how I want it, but that is ugly, terribly ugly.
This is an image of the created nested comments
What is the best way to make this work elegantly in the blade template? I tried extending the blade template thing according to the docs, but that didn't prove fruitful for me. I simply couldn't figure out how to do it.
With this, I can't call asset, or anything like that... those are already out of scope.

I finally found my solution I'm satisfied with. If anyone has a better solution, do feel free to suggest.
My Blog controller is the same, only thing that changed is my view. In my blog view (where I see those comments as a user):
blog.blade.php
#foreach($comments[0] as $comment)
<div class="media comment">
#if(!is_null($comment->users['avatar']))
<img class="m-3 avatar-sm rounded-1 border border-thick-1 shadow" src="{{ asset( Config::get('site.asset_folder') . 'users/images/' . $comment->users['avatar']) }}" alt="{{ $comment->users['firstname'] }} {{ $comment->users['lastname'] }}'s Avatar">
#else
<img class="m-3 avatar-sm rounded-1 border border-thick-1 shadow" src="{{ asset( Config::get('site.asset_folder') . 'css/images/avatar-placeholder.png') }}" alt="{{ $comment->users['firstname'] }} {{ $comment->users['lastname'] }}'s Avatar">
#endif
<div class="media-body">
<h6 class="mt-0 p-1 lead m-0 border-bottom">{{ $comment->users['firstname'] }} {{ $comment->users['lastname'] }}</h6>
<div class="p-2">
<p>{{ $comment->comment }}</p>
</div>
#if(isset($comments[$comment->id]))
#include('block.comments', ['comments' => $comments, 'parent_id' => $comment->id, 'depth' => 0])
#endif
</div>
</div>
#endforeach
And then, my block/comments.blade.php
#foreach($comments[$parent_id] as $comment)
#if($depth >= Config::get('site.max_nested'))
</div>
</div>
#endif
<div class="media comment">
#if(!is_null($comment->users['avatar']))
<img class="m-3 avatar-sm rounded-1 border border-thick-1 shadow" src="{{ asset( Config::get('site.asset_folder') . 'users/images/' . $comment->users['avatar']) }}" alt="{{ $comment->users['firstname'] }} {{ $comment->users['lastname'] }}'s Avatar">
#else
<img class="m-3 avatar-sm rounded-1 border border-thick-1 shadow" src="{{ asset( Config::get('site.asset_folder') . 'css/images/avatar-placeholder.png') }}" alt="{{ $comment->users['firstname'] }} {{ $comment->users['lastname'] }}'s Avatar">
#endif
<div class="media-body">
<h6 class="mt-0 p-1 lead m-0 border-bottom">{{ $comment->users['firstname'] }} {{ $comment->users['lastname'] }}</h6>
<div class="p-2">
<p>{{ $comment->comment }}</p>
</div>
#if(isset($comments[$comment->id]))
#include('block.comments', ['comments' => $comments, 'parent_id' => $comment->id, 'depth' => $depth + 1])
#endif
#if($depth < Config::get('site.max_nested'))
</div>
</div>
#endif
#endforeach
And then I have a config file site in the config folder with the following contents
return [
// We define the max depth for the nested comments
// You could obviously define this value in database and be retrieving it from there
'max_nested' => 3,
];
The way my $comments array is set-up, the parent comments are always going to be in $comments[0] while the child comments would be in $comments[$parent_id]
I think that's fairly simple yet effectively functional!

Related

initialData is null in livewire component when there is a two events in the same component

I am having two events in my component one is changing the layout and another one is sorting. Changing a layout basically it only replace a layout component inside a parent component. Now when i am calling a sorting then livewire giving me a error 'initialdata is null '.
I am looking for to create a sorting order with this same component. And my code is
<div class="dropdown px-2 d-none d-lg-block">
<div class=" text-dark fw-bold dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<span class="px-1">
<img class="" src="{{ Vite::image('icons/classic.png') }}" alt="" />
</span>
<span>
<img class="" src="{{ Vite::image('icons/filter-down.png') }}" alt="" />
</span>
</div>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item text-primary #if($show == 1)text-primary #else text-dark #endif fw-bolder" href="javascript:void(0)" wire:click="$set('show', '1')">
<img src="{{ Vite::image('icons/compact.png') }}" alt="" class="ps-2" /> Card </a>
<a class="dropdown-item uni-border #if($show == 2)text-primary #else text-dark #endif fw-bolder " href="javascript:void(0)" wire:click="$set('show', '2')">
<img src="{{ Vite::image('icons/classic.png') }}" alt`your text`="" class="ps-2" />Classic </a>
<a class="dropdown-item uni-border #if($show == 3) text-primary #else text-dark #endif fw-bolder" href="javascript:void(0)" wire:click="$set('show', '3')">
<img src="{{ Vite::image('icons/com.png') }}" alt="" class="ps-2" />Compact </a>
</div>
</div>
{{-- sorting option --}}
<div class="d-flex justify-content-between pt-2 align-items-center d-none d-lg-block ">
<div class="d-flex align-items-center justify-content-between">
<div>
<span class="m-0">Selected Filters:</span>
<span class=" mx-3 boat-span2 align-items-center rounded-1">
<span>$500 </span>
<span>
<img src="{{ Vite::image('icons/cross.png') }}" alt="" class="" />
</span>
</span>
<span class=" boat-span2 align-items-center rounded-1">
<span> Skipper </span>
<span>
<img src="{{ Vite::image('icons/cross.png') }}" alt="" class="" />
</span>
</span>
</div>
<div class="">
<h6 class="m-0 text-secondary fw-500 ">
<u> Clear Filters</u>
</h6>
</div>
</div>
</div>
#if($show == 2)
{{-- classic layout --}}
#livewire('frontend.boat.listing.layout.classic',['product' => $product])
#elseif($show == 1)
{{-- card layout --}}
#livewire('frontend.boat.listing.layout.card',['product' => $product])
#elseif($show == 3)
{{-- compact layout --}}
#livewire('frontend.boat.listing.layout.compact',['product' => $product])
#endif
</div>
<?php
namespace App\Http\Livewire\Frontend\Boat\Listing;
use App\Models\Product;
use Livewire\Component;
class Listing extends Component
{
// Mount , boot , hydrate component
public $filter_option_recommend = "recommended";
public $show = "2";
// public $filter_option = "name";
// public $product;
public function detail($id, $title)
{
return redirect()->route('website.boat.detail', [$id, $title]);
}
public function render()
{
$product = Product::join('product_time_assign', 'product_time_assign.product_id', '=', 'products.id')
->where([
'products.type_id' => 1, // boat
'products.status' => 'Active',
])
->select(
'products.id as productid',
'product_time_assign.id as timeassignid',
'products.name',
'products.capacity',
'products.price_starts',
'product_time_assign.skipper',
'product_time_assign.product_time_assign_id',
'products.review_rating',
'products.image',
'products.description',
'products.discount_price'
)
->orderBy($this->filter_option_recommend, 'asc')->get();
return view('livewire.frontend.boat.listing.listing', ['product' => $product]);
}
}

Laravel query return wrong data

QUERY:
$recent_posts = Blog::join("categories",'categories.id', '=', 'blogs.category_id')
->where('categories.status', 1)
->orderBy('blogs.id', 'desc')
->take(3)
->get();
Both tables had a created_at column.
At frontend im using this to retrieve the data:
<div class="row justify-content-center">
#foreach ($recent_posts as $recent_post)
<div class="col-md-6 col-lg-4 latest-blog-resp">
<div class="blog-item">
<div class="blog-img">
<a href="{{ url('blog/'.$recent_post->slug) }}">
#if ($recent_post->blog_image == '')
<img src="{{ asset('fibonacci/adminpanel/assets/img/dummy/no_image.jpg') }}" class="img-fluid round-item" alt="blog image">
#else
<img src="{{ asset('fibonacci/adminpanel/assets/img/blog/thumbnail1/'.$recent_post->blog_image) }}" class="img-fluid round-item" alt="blog image">
#endif
</a>
</div>
<div class="blog-inner">
<div class="blog-meta">
<span class="mr-2">
<i class="mdi mdi-calendar-account-outline"></i>{{ __('frontend.by_admin') }}
</span>
<span>
<i class="mdi mdi-calendar-range"></i>{{Carbon\Carbon::parse($recent_post->created_at)->isoFormat('MMMM')}} {{Carbon\Carbon::parse($recent_post->created_at)->isoFormat('DD')}}
</span>
</div>
<h5 class="blog-title">
{{ $recent_post->title }}
</h5>
<p class="blog-desc">{{ $recent_post->short_description }}</p>
<a href="{{ url('blog/'.$recent_post->slug) }}" class="blog-more-link">
{{ __('frontend.read_more') }} <i class="fa fa-angle-right ml-2"></i>
</a>
</div>
</div>
</div>
#endforeach
#if (count($recent_posts) === 3)
<div class="col-12 text-center margin-top-30">
<div class="btn-group">
<a href="{{ url('blog') }}" class="default-button">
{{ __('frontend.view_all') }}
</a>
</div>
</div>
#endif
</div>
THE PROBLEM:
$recent_post->created_at returns the category table creation (created_at) date but we expect to receive the blog table result as created_as (like a post creation data).
Thanks in advance!
Specify your fields in a select clause.
$recent_posts = Blog::select(
'blogs.slug',
'blogs.blog_image',
'blogs.title',
'blogs.short_description',
'blogs.created_at'
)
->join('categories', 'categories.id', 'blogs.category_id')
->where('categories.status', 1)
->orderByDesc('blogs.id')
->take(3)
->get();

Else Statement returned Blank in Laravel

I want to implement a simple search on my Laravel Application
public function search()
{
$search = request()->query('search');
if ($search) {
$books = Book::where('name', 'LIKE', "%{$search}%")->simplepaginate(12);
}
else {
echo "<h2>Book Not Found, please try using another search term</h2>";
$books = Book::orderBy('created_at', 'desc')->simplepaginate(12);
}
return view('search')->with('books', $books);
}
But the else returned a blank screen when the search terms can't be found
UPDATE
Here is my view file
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-10 offset-md-1">
<div class="row">
#foreach($books as $book)
<div class="col-md-3">
<div class="home-catalog-image">
<a href="{{ route('book', $book->id) }}" target="_blank">
<!-- <img src="{{ $book->image }}" alt="trending image" /> -->
<img src="{{ $book->image_url }}" class="img-responsive" alt="{{$book->image_url}}">
</a>
</div>
<p class="author">{{ $book->author->name }}</p>
<h1 class="book-title">{{str_limit($book -> name, 20) }}</h1>
</div>
#endforeach
</div>
<p style="text-align:center;>"> {!! $books->render() !!} </p>
</div>
</div>
</div>
Check how to use the request() helper to get the input.
Also you can use when() method for conditional clauses instead if else.
public function search()
{
$search = request('search', null);
$books = Book::when($search, function ($query, $search) {
return $query->where('name', 'LIKE', "%{$search}%");
})
->orderBy('created_at', 'desc')
->simplePaginate(12);
return view('search')->with('books', $books);
}
Then in Blade you can use #forelse directive to loop the collection, or if it's empty, show the message.
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-10 offset-md-1">
<div class="row">
#forelse ($books as $book)
<div class="col-md-3">
<div class="home-catalog-image">
<a href="{{ route('book', $book->id) }}" target="_blank">
<!-- <img src="{{ $book->image }}" alt="trending image" /> -->
<img src="{{ $book->image_url }}" class="img-responsive" alt="{{$book->image_url}}">
</a>
</div>
<p class="author">{{ $book->author->name }}</p>
<h1 class="book-title">{{str_limit($book -> name, 20) }}</h1>
</div>
#empty
<h2>Book Not Found, please try using another search term</h2>
#endforelse
</div>
<p style="text-align:center;>"> {!! $books->render() !!} </p>
</div>
</div>
</div>
To solve my problem, I use forelse instead of foreach a
#forelse($books as $book)
<div class="col-md-3">
<div class="home-catalog-image">
<a href="{{ route('book', $book->id) }}" target="_blank">
<!-- <img src="{{ $book->image }}" alt="trending image" /> -->
<img src="{{ $book->image_url }}" class="img-responsive" alt="{{$book->image_url}}">
</a>
</div>
<p class="author">{{ $book->author->name }}</p>
<h1 class="book-title">{{str_limit($book -> name, 20) }}</h1>
</div>
#empty
<h2>Book Not Found, please try using another search term</h2>
#endforelse
In my controller, I used
public function search()
{
$search = request('search', null);
$books = Book::when($search, function ($query, $search) {
return $query->where('name', 'LIKE', "%{$search}%");
})
->orderBy('created_at', 'desc')
->simplePaginate(12);
return view('search')->with('books', $books);
}

Using 2 Controller Functions in a View in Laravel

I want to have two loops in my view, so I wrote these two functions
public function index()
{
$books = Book::orderBy('created_at', 'desc')->take(10)->get();
return view('bookpage')->with('books', $books);
}
public function loggedin()
{
$books = Book::orderBy('RAND()')->take(1)->get();
return view('bookpage')->with('books', $books);
}
In the view I have
<!--First Loop -->
#foreach($books as $book)
<div class="col-md-6">
<div class="out-box">
<h2>{{ $book->name }}</h2>
<h3>{{ $book->author->name }}</h3>
<br>
Start Reading<br><br>
<img src="assets/img/cart-buy.png" width="13px"/> Buy
</div>
</div>
</div>
</div>
<div class="col-md-6">
<input id="aboutbook" type="radio" name="tabs" checked>
<label for="aboutbook" class="aboutbook">About This Book</label>
<input id="bookreview" type="radio" name="tabs">
<label for="bookreview" class="bookreview">Reviews</label>
<hr style="background-color:black;">
<section style="padding-top:5px;" id="bookabout" >
<div class="row">
<div class="col-md-12">
<p>{{ $book -> about }}</p>
<h1>About the Author</h1>
</div>
</div>
<div class="row">
<div class="col-sm-4 col-md-3 col-6">
<img src="assets/img/Ellipse.png" class="rounded-circle" width="120px">
</div>
<div class="col-sm-4 col-md-4 col-6">
<h1>{{ $book->author->name }}</h1>
<h4>{{ $book->author->about }}</h4>
</div>
<div class="col-sm-4 col-md-5">
<div id="learnbtn">
Learn More
</div>
</div>
</div>
</section>
<section style="padding-top:5px;" id="bookabout1" >
jjjjjjj
</section>
</div>
</div>
</div>
#endforeach
</section>
<!--Second Loop -->
#foreach($books as $book)
#if($book->recommended === 1)
<div class="col-1-5">
<div class="home-catalog-image">
<a href="{{ $book->image_url }}" target="_blank">
<!-- <img src="{{ $book->image }}" alt="trending image" /> -->
<img src="{{ $book->image_url }}" class="img-responsive" alt="{{ $book->image_url }}">
</a>
<!-- <img src="{{ asset('/books/'.$book->image) }}" alt="trending image" /> -->
</div>
<p class="author">{{ $book->author->name }}</p>
<h1 class="book-title">{{str_limit($book -> name, 20) }}</h1>
</div>
#endif
#endforeach
In my web.php
Route::get('/', 'WelcomeController#index')->name('welcome');
I want to call another function in the view, although I know the method is wrong, I don't know how to go about it.
You don't have to create two different method for logged in user just use
public function index()
{
if(auth()->user()) {
$books = Book::orderBy('RAND()')->take(1)->get();
} else $books = Book::orderBy('created_at', 'desc')->take(10)->get();
return view('bookpage')->with('books', $books);
}
in view file use
#auth
//code for logged in user
#else
//code for guest user
#endauth
I was able to solve my problem like this
public function loggedin()
{
$data = array();
$data['recommends'] = Book::where('recommended', 1)->take(10)->get();
$data['latests'] = Book::orderBy('created_at', 'desc',)->where('recommended', 0)->take(10)->get();
$data['logged'] = Book::all()->random(1);
return view('index-logged', compact("data"));
}
In my view, I did
#foreach($data['logged'] as $log)
<h1>{{ $log->author->name }}</h1>
<h4>{{ $log->author->about }}</h4>
#endforeach
#foreach($data['recommends'] as $recommend)
<p class="author">{{ $recommend->author->name }}</p>
<h1 class="book-title">{{str_limit($recommend -> name, 20) }}</h1>
#endforeach
#foreach($data['latests'] as $latest)
<p class="author">{{ $latest->author->name }}</p>
<h1 class="book-title">{{str_limit($latest -> name, 20) }}</h1>
#endforeach

Accessing collection from a relationship

So I have 2 tables.
DirtyEvent model and Event model.
I am retrieving DirtyEvent with Event which works fine
In blade I have:
#if (\Request::is('profile/event'))
#foreach ($events as $event)
#if (empty( $event->image ))
<div class="card-header">
<span class="card-title"> {{($event->title) }}</span>
</div>
#else
<div class="card-image">
<img class="img-responsive" src="{{ $event->image }}"></img>
<span class="card-title"> {{($event->title) }}</span>
</div>
#endif
<div class="card-content">
<p><strong>Starts: </strong>#php echo ($startdate) #endphp - {{$event->startime }}</p>
<br>
#if ($startdate != $enddate)
<p><strong>Ends: </strong>#php echo ($enddate) #endphp - {{$event->endtime }}</p>
<br>
#endif
<p><strong>Description:</strong></p>
<br>
<p>{{$event->description }}</p>
</div>
<div class="card-action">
<i class="fa fa-pencil-square-o fa-2x" aria-hidden="true"></i>
<form method="POST" action={{ url('events/delete/' . $event->id) }}>
{{ method_field('PATCH') }}
{{ csrf_field() }}
<button type="submit" class="delete" style="border:none;"><i class="fa fa-trash-o fa-2x" aria-hidden="true"></i></button>
</form>
</div>
#foreach ($events->publicevents as $eventss)
{{dd($events)}}
#endforeach
#endforeach
However dd($events) gives me:
DirtyEvent Collection -> relations -> publicevents -> Event collection
But, It is saying that publicevents do not exist in current collection.
Controller
public function index()
{
$id = Auth::id();
$events = DirtyEvent::where('user_id', $id)
->with('publicevents')
->get();
return view('events.viewEvent', compact('events'));
}
Model
public function publicevents()
{
return $this->hasMany('App\Event', 'event_id');
}
I guess not all dirty event objects have events. So check this first with empty() or isEmpty() or count():
#if (!empty($event->publicevents))
#foreach ($event->publicevents as $eventss)
{{ $eventss->id }}
#endforeach
#endif
Update
It should be $event->publicevents, not $events->publicevetns.

Resources