Nested comments with Blade in Laravel - php

I'm trying to generate nested comments with Blade in Laravel. It seems as if I have to make a blade template that has unlimited nesting comments preconfigured for each comment and it's child comments. But I want the comments to generate automatically.
This is my Comment model:
class Comment extends Model {
protected $table = 'comments';
public function user()
{
return $this->hasOne('App\Models\User', 'id', 'user_id');
}
public function post()
{
return $this->hasOne('App\Models\Post', 'id', 'post_id');
}
public function children()
{
return $this->hasMany('App\Models\Comment', 'parent_id', 'id');
}
}
And in my view I'm doing
#foreach($comments as $comment)
<!-- Comment markup -->
#if($comment->children->count() > 0)
#foreach($comment->children as $child)
<!-- Child comment markup -->
#if($child->children->count() > 0) // I have to do this unlimited times
#foreach ....
#endforeach
#endif
#endif
#endforeach
I'm looking for a way to automate this, maybe with a function or something.

You're basically looking for a recursive view. This is illustrated in the example below (extracting out the show view isn't really needed, but it's a good idea).
resources/views/comments/index.blade.php
#foreach($comments as $comment)
{{-- show the comment markup --}}
#include('comments.show', ['comment' => $comment])
#if($comment->children->count() > 0)
{{-- recursively include this view, passing in the new collection of comments to iterate --}}
#include('comments.index', ['comments' => $comment->children])
#endif
#endforeach
resources/views/comments/show.blade.php
<!-- Comment markup -->

Related

How can I display posts' comment?

should I give id for posts? How Laravel know which comments belong to which post?
This is my controller :
public function show($id){
$posts=Post::where('id',$id)->get();
return view('user',compact('posts'));
}
This is my blade :
#foreach($posts->comments as $comment)
<div class="comment-form">
<section class="post-body">
<p>{{ $comment->description }}</p> <!-- burda ilisdim -->
</section>
</div>
#endforeach
So I built polymorphic relations about comments. but I don't know how to use it.
UPDATE
here is my Post Model
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
You need to define the relation on Post model, as like :
public function comments()
{
return $this->hasMany(Comment::class);
}
Then you can access like this :
#foreach($posts->comments as $comment) // $posts->comments will call your comments() function
{{ $comment->description }}
#endforeach
As I can see you doing something wrong. Please replace your code with below:
To Get Single post you have to replace code with given below in controller
public function show($id){
$posts=Post::where('id',$id)->first();
return view('user',compact('posts'));
}

Trying to get property 'cover_image' of non-object (View: C:\Users\BWB\Documents\Laravel\asperablogs\resources\views\blogs\blogs.blade.php)

So I'm making a blog website and I'm implementing tags. I keep getting the error in the title and not sure what I'm supposed to do. I've looked through similar questions here but they look different from how i've done it. Im using pivot tables for the the tags. When I did it with the posts only it worked well and displayed everything
here is the index method from my posts controller.
public function index()
{
$posts = Post::all()->sortByDesc('created_at');
return view('blogs.blogs', compact('posts'));
}
here is the index method from my tag controller.
public function index(Tag $tag){
$posts = $tag->posts();
return view('blogs.blogs')->with('posts',$posts);
}
Here is how I'm outputting it in the view
#foreach($posts as $post)
<div class="well row">
<div class="col-md-4">
<img style="width: 100%" src="/storage/cover_images/{{$post->cover_image}}" alt="">
</div>
<div class="col-md-8">
<h3> {{$post->title}}</h3>
<h3>{{$post->created_at}}</h3>
</div>
</div>
#endforeach
This is my tags model
public function posts() {
return $this->belongsToMany(Post::class);
}
public function getRouteKeyName()
{
return 'name';
}
Error
Your error comes from the fact that the variable $post within your foreach loop has returned as a non-object.
Probable Cause
That $posts is not being returned as a collection but rather a query builder instance
$posts = $tag->posts();
If you have built an eloquent relationship between a Tag model and a Post model, when you access this as a method (i.e. $tag->posts()) you will get an eloquent query builder instance. If you access this as a property (i.e. $tag->posts), it will return an eloquent collection.
Suggestion
Try passing the posts to the view as a collection
public function index(Tag $tag) {
return view('blogs.blogs', [
'posts' => $tag->posts
]);
}
And try using a #forelse loop to catch the instances where you have no posts
#forelse ($posts as $post)
#empty
#endforelse

Get all the data with specific tag in laravel

I am using eloquent relationships for post and tags through post_tags. What i'm trying to do is make sections of posts in my front-end view with specific tags. Like if i have a section 1 it should have all posts of tag "new", section 2 should have all posts of tag "old" etc. And i want all of this to happen in a same view.
Post Model
public function tags()
{
return $this->belongsToMany('App\Tag', 'post_tag');
}
Tag Model
public function posts()
{
return $this->belongsToMany('App\Post', 'post_tag');
}
Controller
public function index()
{
$posts = Post::all();
return view('frontend.index')->withPosts($posts);
}
Please help me out:)
You can get all the tags with loading the posts :
public function index()
{
$tags = Tag::with('posts')->get();
return view('frontend.index')->withTags($tags);
}
In the view you can do something like this :
#foreach ($tags as $tag)
<h2>Tag : {{ $tag->name }}</h2>
#foreach ($tag->posts as $post)
<p>Post : {{ $post->title }}</p>
#endforeach
#endforeach
For geting the posts where you have a tag :
public function index()
{
$tagName = 'new';
$posts = Post::whereHas('tags', function ($q) use($tagName) {
$q->where('name', $tagName);
})->get();
return view('frontend.index')->withTagName($tagName)->withPosts($posts);
}
And in the view you can do this :
<h2>Tag : {{ $tagName }}</h2>
#foreach ($posts as $post)
<p>Post : {{ $post->title }}</p>
#endforeach
If you want to do queries from view you can do it like this (but it's not a god practice because the view is just for viewing the content not geting it from database) :
<?php foreach ((\App\Post::whereHas('tags', function ($q) use($tagName) {
$q->where('name', $tagName);
})->get()) as $post) { ?>
<p>Post : {{ $post->title }}</p>
<?php } ?>
To get all posts with tags with name new, do this:
Post::whereHas('tags', function ($q) {
$q->where('name', 'new');
})->get();
It is solution not perfect answer
You can handle this situation in two ways
1- send two objects from controller to view seprate one for only new tag and second without new tag
2- you can handle this situation in front-end by using conditions
#if($user->tag == "new")
{$user->show}
#endif

Laravel 5.1 - Showing Comments on Specific Page

Edit3: Could a reason be because both controllers are leading to the same page?
Edit2: Still not working after the answers I got.
Edit: Error one is solved, now I'm getting:
Undefined variable: project (View:
/var/www/resources/views/pages/showProject.blade.php)
Can this be because both variables are leading to the same page? The projects variable was working perfectly before the comment system.
public function index()
{
$projects = Project::all();
return view('pages.projects', compact('projects'));
}
Project variable declare.
I'm trying to get my comments from my database to show on a specific 'project page' in the laravel 5 project I'm working on. The idea is that the user can add art projects and other users can comment on them, but whenever I try to visit the page I get
Undefined variable: comments (View:
/var/www/resources/views/pages/showProject.blade.php)
This is my controller
public function index()
{
$comments = Comment::all();
return view('pages.showProject', compact('comments'));
}
public function store()
{
$input = Request::all();
$comment = new Comment;
$comment->body = $input['body'];
$comment->project_id = $input['project_id'];
$comment->user_id = Auth::user()->id;
$comment->save();
return redirect('projects/'.$input['project_id']);
}
These are my routes
// add comment
Route::post('projects/{id}','CommentController#store');
// show comments
Route::post('projects/{id}','CommentController#index');
And my view
#if (Auth::check())
<article> <!--Add comment -->
<br/>
{!! Form::open() !!}
{!! form::text('body', null, ['class' => 'form-control']) !!}
<br/>
{!! Form::Submit('Post Comment', ['class' => 'btn btn-primary form-control']) !!}
{!! Form::hidden('project_id', $project->id) !!}
{!! Form::close() !!}
<br/>
</article>
<article>
#foreach ($comments as $comment)
<article>
<p>Body: {{ $comment->body }}</p>
<p>Author: {{ $comment->user->name }}</p>
</article>
#endforeach
</article>
#else
<p>Please log in to comment</p>
#endif
The Model
class Comment extends Model
{
//comments table in database
protected $guarded = [];
// user who has commented
public function author()
{
return $this->belongsTo('App\User','user_id');
}
// returns post of any comment
public function post()
{
return $this->belongsTo('App\Project','project_id');
}
public function comments()
{
return $this->hasMany('App\Comment');
}
public $timestamps = false;
}
Is there any way I can solve this?
Thanks in advance
First, you need to make sure that you are aliasing your 'Comment' model in your controller. This is done with the use statement.
use App\Comment;
class CommentController extends Controller
{
public function index()
{
$comments = Comment::all();
return view('pages.showProject', compact('comments'));
}
}
Second, you will need to change your route for showing comments from a POST request to a GET request. At the moment you are making identical routes and furthermore GET is the correct request type for retrieving data.
Route::get('projects/{id}','CommentController#index');
Third, you are referencing a $project variable in your view, but never passing it in from the controller. That needs to reference something.
I think your relationship is wrong. Try this:
Comment model:
class Comment extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
}
User model:
class User extends Model
{
public function comments()
{
return $this->hasMany('App\Comment');
}
}
In the view you can use:
#foreach($comments as $comment)
<p>{{ $comment->user->name }}</p>
#endforeach
I needed to empty the show in the commentsController and only use it for saving the comments. For showing them I made an extra function in my projectsController. It ended up being this;
public function show($id)
{
$project = Project::findOrFail($id)->load("User");
$input = Request::all();
//-----------------------DB-----------------------------//
$project_comments = DB::table('comments')
->select('body', 'name')
->where('project_id', '=', $id)
->join('users', 'users.id', '=', 'user_id')
->get();
//-----------------------DB-----------------------------//
return view('pages.showProject', ['project' => Project::findOrFail($id), 'comments' => $project_comments]);
}

Trouble retrieving data laravel4(oneToMany)

Okay so I just started learning Laravel and its fantastic. I just got stuck trying to retrive all the post from a user. Here is my code
models/User.php
public function posts()
{
$this->hasMany('Post');
}
models/Post.php
public function user()
{
$this->belongsTo('User');
}
controller/UserController.php
public function getUserProfile($username)
{
$user = User::where('username', '=', $username)->first();
$this->layout->content = View::make('user.index', array('user'=>$user));
}
views/user/index.blade.php
<div class="show-post">
<ul>
<li>{{ $user->posts }}</lo>
</ul>
</div>
I also tried:
#foreach($user->posts as $post)
<li>{{$post->post}}</li>
#endforeach
So im having trouble displaying the post for each specific user. Thank you.
So with the help of #WereWolf- The Alpha I was able to solve it and make my code better, If you notice I forgot to return my relationship functions. example:
Notice I hadn't returned it before
models/Post.php
public function users()
{
return $this->belongsTo('users');
}
But also the way I was querying my database was inefficient so Alpha showed me Eager Loading
http://laravel.com/docs/eloquent#eager-loading
example of controller
public function getUserProfile($username)
{
$user = User::with('posts')->where('username', '=', $username)->first();
$this->layout->content = View::make('user.index', array('user'=>$user));
}
and finally the view:
div class="show-post">
#foreach($user->posts as $post)
{{ $post->post }}
#endforeach
</div>
Actually $user->posts returns a collection of Post model so when you try this
{{ $user->posts }}
Laravel tries to echo that collection object which is not possible. You may try foreach loop instead:
#foreach($user->posts as $post)
{{ $post->somepropertyname }}
#endforeach
It's also possible to do something like this:
// Get first post->somepropertyname
{{ $user->posts->first()->somepropertyname }}
// Get last post->somepropertyname
{{ $user->posts->last()->somepropertyname }}
// Get first post->somepropertyname (same as first)
{{ $user->posts->get(0)->somepropertyname }}
// Get second post->somepropertyname from collection
{{ $user->posts->get(1)->somepropertyname }}
// Get the post->somepropertyname by id (post id) 2
{{ $user->posts->find(2)->somepropertyname }}
Also you may use eager loading like this (better):
$user = User::with('posts')->where('username', '=', $username)->first();
You may like this article about Cocllection.
Update: Also use return in model methods, like:
public function posts()
{
return $this->hasMany('Post');
}

Categories