Laravel 5: how to do multi threaded comments - php

I am using Laravel Commentable package which uses Nested Sets pattern with Baum.
I have managed to allow users to make comments on posts but they're not threaded, each comment has depth set to zero in the database.
So I'm wondering how does one go about making multi threaded comments like reddit for example?
These are my tables
users: id, name, email...
posts: id, user_id, subreddit_id...
comments: id, body, parent_id, lft, rgt, depth, commentable_id, commentable_type, user_id
My Models (Comment and User)
class Comment extends Model
{
use Commentable;
public function commentable()
{
return $this->morphTo();
}
public function user() {
return $this->belongsTo('App\User');
}
public function posts() {
return $this->belongsTo('App\Post');
}
}
class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
public function posts() {
return $this->hasMany('App\Post');
}
public function comments() {
return $this->hasMany('App\Comment');
}
}
This is how I'm submitting comments in PostsController
public function createComment($id) {
$post = Post::with('user.votes')->with('subreddit.moderators')->where('id', $id)->first();
$comment = new Comment;
$comment->body = Input::get('comment');
$comment->user_id = Auth::id();
$post->comments()->save($comment);
}
And this is the view
<div class="post-comments">
{!! Form::open(['route' => ['comment', $post]]) !!}
<div class="form-group">
<label for="comment">Your Comment</label>
<textarea name="comment" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-default">Send</button>
{!! Form::close() !!}
<div class="comments-nav">
<ul class="nav nav-pills">
<li role="presentation" class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
there are {{ count($comments) }} comments <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>Best</li>
<li>Hot</li>
</ul>
</li>
</ul>
</div>
<div class="row">
<div class="media">
<!-- first comment -->
#foreach($comments as $comment)
<div class="media-heading">
<button class="btn btn-default btn-xs" type="button" data-toggle="collapse" data-target="#{{ $comment->id }}" aria-expanded="false" aria-controls="collapseExample"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></button> <span class="label label-info">12314</span> {{ $comment->user->name }} 12 hours ago
</div>
<div class="panel-collapse collapse in" id="{{ $comment->id }}">
<div class="media-left">
<div class="vote-wrap">
<div class="vote up">
<i class="glyphicon glyphicon-menu-up"></i>
</div>
<div class="vote inactive">
<i class="glyphicon glyphicon-menu-down"></i>
</div>
</div>
<!-- vote-wrap -->
</div>
<!-- media-left -->
<div class="media-body">
<p>{{ $comment->body }}</p>
<div class="comment-meta">
<span>delete</span>
<span>report</span>
<span>hide</span>
<span>
<a class="" role="button" data-toggle="collapse" href="#replyCommentT" aria-expanded="false" aria-controls="collapseExample">reply</a>
</span>
<div class="collapse" id="replyCommentT">
<form>
<div class="form-group">
<label for="comment">Your Comment</label>
<textarea name="comment" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-default">Send</button>
</form>
</div>
</div>
<!-- comment-meta -->
</div>
</div>
<!-- comments -->
#endforeach
</div>
<!-- first comment -->
</div>
</div>
<!-- post-comments -->

I haven't used Laravel Commentable package, but the docs look pretty good.
I believe you need use Commentable; on your Post model and not your Comment model.
It looks like your Comment model needs to extend Baum\Node and not Model
Then what you have should work.
$post = Post::with('user.votes')->with('subreddit.moderators')->where('id', $id)->first();
$comment = new Comment;
$comment->body = Input::get('comment');
$comment->user_id = Auth::id();
$post->comments()->save($comment);
// or you could do
$comment->makeChildOf($post);
To make a comment on a comment, it looks like you do something like this. I would probably make a CommentsController.
public function addComment(Request $request){
$parent = Comment::find(Input::get('parent_id'));
$comment = new Comment;
$comment->body = Input::get('comment');
$comment->user_id = Auth::id();
$comment->makeChildOf($parent);
}
The Relations, Root and Leaf scopes, Accessing the ancestry/descendancy chain section of the docs have several examples on how to then retrieve the comments for comments.
Edit
It looks like the Comment model in the package already extends the Baum\Node so you don't need to do that. In order to use this package, it looks like you need to use his Comment model. I am sure you could use his model as a base and roll your own.
You could do something like this. You would have to set up a route.
<div class="collapse" id="replyCommentT">
{!! Form::open(['route' => ['comment', $comment]]) !!}
<input type="hidden" name="parent_id" value="{{ $comment->id }}"/>
<div class="form-group">
<label for="comment">Your Comment</label>
<textarea name="comment" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-default">Send</button>
{!! Form::close() !!}
</div>

Related

Laravel 8 Error: Attempt to assign property "id_gerai" on null

I building a page to insert rows into database tables using a HTML form. I created my view, model, controller, and route already and it return this error when i try to submit the form:
Attempt to assign property "id_gerai" on null
Here are the rest of the code
resources\views\dashboard\manajemen_donasi.blade.php
#extends('layouts.dashboard')
#section('title')
<title>KitaKenyang - Dashboard Admin</title>
#endsection
#section('nav_link')
<li class="nav-item active">
<a class="nav-link" href="/manajemen donasi">
<i class="fas fa-fw fa-tachometer-alt"></i>
<span>Manajemen Donasi</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="/manajemen penyimpanan">
<i class="fas fa-fw fa-tachometer-alt"></i>
<span>Manajemen Penyimpanan</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="/manajemen penyaluran">
<i class="fas fa-fw fa-tachometer-alt"></i>
<span>Manajemen Penyaluran</span></a>
</li>
#endsection
#section('username')
Admin
#endsection
#section('content')
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800 text-center">Dashboard Manajemen Donasi</h1>
</div>
<div class="container-fluid">
<!-- DataTales Example -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-success">Input Donasi</h6>
</div>
<div class="card-body">
<form action="#" method="post" class="probootstrap-form">
#csrf <!-- {{ csrf_field() }} -->
<div class="form-group">
<label for="id_user">ID Donatur</label>
<input type="text" class="form-control" id="id_user" name="id_user">
</div>
<div class="form-group">
<label for="tanggal">Tanggal Donasi</label>
<input type="date" class="form-control" id="tanggal" name="tanggal">
</div>
<div class="form-group">
<label for="id_kategori_barang">Kategori</label>
<input type="text" class="form-control" id="id_kategori_barang" name="id_kategori_barang">
<i>* dry staple: 1 | dehydrated food: 2 | canned food: 3 | frozen food: 4</i>
</div>
<div class="form-group">
<label for="id_kuantitas">Kuantitas</label>
<input type="text" class="form-control" id="kuantitas" name="kuantitas">
</div>
<div class="form-group">
<label for="id_nama_barang">Nama barang</label>
<input type="text" class="form-control" id="nama_barang" name="nama_barang">
</div>
<div class="form-group">
<label for="id_gerai">ID Gerai</label>
<input type="text" class="form-control" id="id_gerai" name="id_gerai">
</div>
<div class="form-group">
<input type="submit" class="btn btn-success btn-lg" id="submit" name="submit" value="Input">
</div>
</form>
</div>
</div>
</div>
<!-- /.container-fluid -->
#endsection
routes\web.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Models\Donasi;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', 'PagesController#index');
Route::get('/beranda', 'PagesController#index');
Route::get('/tentang kami', 'PagesController#about');
Route::get('/berita', 'PagesController#news');
Route::get('/program', 'PagesController#program');
Route::get('/gerai donasi', 'PagesController#gerai');
Route::get('/login', 'PagesController#login');
Route::get('/register', 'PagesController#register');
Route::get('/kinerja organisasi', 'DashboardController#laporan_org');
Route::get('/donasi user', 'DashboardController#laporan_user');
Route::get('/profil user', 'DashboardController#profil_user');
Route::get('/manajemen donasi', 'DashboardController#manajemen_donasi');
Route::post('manajemen donasi', 'DashboardController#input_donasi');
Route::get('/manajemen penyimpanan', 'DashboardController#manajemen_penyimpanan');
Route::get('/manajemen penyaluran', 'DashboardController#manajemen_penyaluran');
App\Models\Donasi.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Donasi extends Model
{
use HasFactory;
protected $table = 'donasi';
protected $primaryKey = 'id';
protected $fillable = [
'id_user',
'id_kategori_barang',
'id_gerai',
'nama_barang',
'kuantitas',
'tanggal',
];
public $timestamps = false;
}
app\Http\Controllers\DashboardController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Program;
use App\Models\DonasiDalamPenyimpanan;
use App\Models\TotalDonasi;
use App\Models\TotalDonatur;
use App\Models\Donasi;
class DashboardController extends Controller
{
public function laporan_org()
{
$totaldonatur = TotalDonatur::all();
$totaldonasi = TotalDonasi::all();
$program = Program::all();
return view('dashboard.laporan_org', compact('program', 'totaldonasi', 'totaldonatur'));
}
public function laporan_user()
{
return view('dashboard.laporan_user');
}
public function profil_user()
{
return view('dashboard.profil_user');
}
public function manajemen_donasi()
{
return view('dashboard.manajemen_donasi');
}
public function manajemen_penyimpanan()
{
$penyimpanan = DonasiDalamPenyimpanan::all();
return view('dashboard.manajemen_penyimpanan', compact('penyimpanan'));
}
public function manajemen_penyaluran()
{
$program = Program::all();
return view('dashboard.manajemen_penyaluran', compact('program'));
}
public function input_donasi(Request $request)
{
$donasi = new Donasi;
$donasi->id_user = $request->input('id_user');
$donasi->tanggal = $request->input('tanggal');
$donasi->id_kategori_barang = $request->input('id_kategori_barang');
$donasi->kuantitas = $request->input('kuantitas');
$donasi->nama_barang = $request->input('nama_barang');
$donasiModel->id_gerai = $request->input('id_gerai');
$donasi->save();
}
}

Laravel 6 pagination

Hi i am trying to paginate data from the database and i am getting the error below
"Call to undefined method App\Material::links() (View: C:\xampp\htdocs\project104\resources\views\swapview.blade.php)"
I don`t know where i am getting this wrong, i tried changing variables but still got an error
below is my controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Material;
class SwapViewController extends Controller
{
public function index()
{
return view('swapview');
}
public function show()
{
$inf = Material::paginate(4);
$info = Material::orderBy('created_at', 'DESC')->get();
return view('swapview',['info'=>$info]);
}
}
below is my view
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
#foreach($info as $inf)
<div style="background-color:#162238; color:white;" class="card mb-3" style="max-width: 540px;">
<div class="row g-0">
<div class="col-md-4">
<img
src="{{asset('images/' . $inf->imogi)}}"
alt="Trendy Pants and Shoes"
/>
</div>
<div class="col-md-8">
<div class="card-body">
<div style="text-align: right;">
<i style="color:#3490dc" class="fa fa-building-o" style="font-size:24px"></i> <small>{{$inf->organazation}}</small> <small><i class="fa fa-calendar" style="color:#3490dc" aria-hidden="true"></i> {{ $inf->created_at->format('d/m/Y') }}</small>
</div>
<br/>
<!--LIVEWIRE online status-->
#if($inf->isOnline())
<small><div class="circle"></div></small> <small style="color:#22bb33;">operative</small>
#else
<small><div class="ocircle"></div></small> <small>inoperative</small>
#endif
<h5 class="card-title"><i class="fa fa-user-circle-o" style="color:#3490dc" aria-hidden="true"></i> {{$inf->name}}</h5>
<small style="color:#3490dc;"><i class="fa fa-clock-o" style="color:#3490dc;"></i></small> <small style="color:#3490dc;"> posted {{ \Carbon\Carbon::parse($inf->created_at)->diffForHumans() }}</small><br/>
<small><i class="fa fa-map-marker" style="color:#3490dc" aria-hidden="true"></i> {{$inf->location}}</small> | <small><i class="fa fa-phone" style="color:#3490dc" aria-hidden="true"></i>{{$inf->contact}}</small>
<hr color=3490dc>
<p class="card-text">
<small><small style="color:#3490dc;"><i class="fa fa-exchange" aria-hidden="true"></i></small> {{$inf->swap}}</small>
</p>
<hr color=3490dc>
<p class="card-text">
<small><small style="color:#3490dc;"><i class="fa fa-exchange" style="font-size:10px"></i></small> {{$inf->exchange}}</small>
</p>
</div>
</div>
</div>
<a style="color:red;" href="{{ route('report') }}"><i class="fa fa-flag" style="color:red;" aria-hidden="true"></i> <small style="color:#3490dc;">Report</small></a>
</div>
<br/>
#endforeach
{{ $inf->links() }}
</div>
</div>
</div>
#include('footer')
#endsection
I will appreciate any help, thanks in advance
In your controller, this is your show method:
public function show()
{
$inf = Material::paginate(4);
$info = Material::orderBy('created_at', 'DESC')->get();
return view('swapview',['info'=>$info]);
}
So in your return, you send the $info variable to your view, but not you $inf.
And then, in your view, you are using $info as $inf, so your $inf variable is one Material item, not the paginate Material items you get in the controller. So then, when you use $inf->links(), Laravel can't get you some pagination links... because you are not on a paginate element.
It seems there is some confusion in variable naming.

Main Category showing posts underneath

PostController.php
public function index($id)
{
$post = Post::where('post_id', $id)->first();
$categories = DB::table('categories')->select('name AS category_name', 'slug AS category_slug', 'category_id AS cid')->get();
return view('post', compact('post','categories'));
}
post.blade.php
<div class="accordion sticky-top" id="sideNavigation" style="top:55px">
#foreach($categories as $category)
<?php $posts_list = DB::table('posts')->join('categories', 'categories.category_id', 'posts.category_id')
->where('posts.category_id', $category->cid)
->get();
?>
<h2 class="mb-0 border-bottom py-2 ">
<button class="btn btn-link" type="button" data-toggle="collapse"
data-target="#{{$category->category_slug}}" aria-expanded="true"
aria-controls="{{$category->category_slug}}">
{{ $category->category_name}}
</button>
</h2>
<div id="{{$category->category_slug}}" class="collapse" aria-labelledby="headingOne"
data-parent="#sideNavigation">
<div class="card-body">
<ul class="list-unstyled">
#foreach($posts_list as $post_list)
<li>{{$post_list->title}}</li>
#endforeach
</ul>
</div>
</div>
#endforeach
</div>
The idea is so have this:
Category
Post
Post
Post
Category 2
Post
Post
My current solution works but I can see this becoming a problem very quickly to maintain.
You need to add relationships to your models. Documentation is here.
Providing its a one to many relationship you would do the following
In your Category model
public function posts()
{
return $this->hasMany('App\Post', 'category_id', 'category_id');
}
In your Post model
public function category()
{
return $this->hasOne('App\Category', 'category_id', 'category_id');
}
Then you can clean up your view
<div class="accordion sticky-top" id="sideNavigation" style="top:55px">
#foreach($categories as $category)
<h2 class="mb-0 border-bottom py-2 ">
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#{{$category->category_slug}}" aria-expanded="true" aria-controls="{{$category->category_slug}}">{{ $category->category_name}}</button>
</h2>
<div id="{{$category->category_slug}}" class="collapse" aria-labelledby="headingOne" data-parent="#sideNavigation">
<div class="card-body">
<ul class="list-unstyled">
#foreach($category->posts as $post)
<li>{{$post->title}}</li>
#endforeach
</ul>
</div>
</div>
#endforeach
</div>
I would also think this line is not the best way of going about it, you will likely need a route applying
<a href="{{ $post->post_id}}">

How to link comments to each post by id with Laravel Blade

I have created a Post and Comment application. I am trying to link the comments to the id of the post. I am trying to use PHP in a Blade template to do this. I get the error that the variable post_id does not exist. I want to use the #if and #foreach of Blade. The problem seems to be in the #if statement.
Here is my HTML:
<div class="col-md-9">
<div class="row">
#foreach($posts as $post)
<div class="col-md-12 post" id="post{{ $post->id }}">
<div class="row">
<div class="col-md-12">
<h4>
{{ $post->title }}
</h4>
</div>
</div>
<div class="row">
<div class="col-md-12 post-header-line">
<span class="glyphicon glyphicon-user"></span> by {{ $post->user->firstName }} {{ $post->user->lastName }} | <span class="glyphicon glyphicon-calendar">
</span> {{ $post->created_at }} | <span class="glyphicon glyphicon-comment"></span><a href="#">
3 Comments</a>
</div>
</div>
<div class="row post-content">
<div class="col-md-2">
<a href="#">
<img src="/images/random/postimg.jpg" alt="" class="img-responsive postImg">
</a>
</div>
<div class="col-md-10">
<p>
{{ $post->post }}
</p>
</div>
</div>
<div class="row add-comment">
<div class="form-group">
<input type="text" name="addComment" placeholder="Add your comment" class="form-control" v-model="comment">
</div>
<input id="addComment" type="submit" name="submitComment" value="Submit Comment" class="btn btn-default" v-on:click="submitComment" data-id="{{ $post->id }}">
</div>
#if($post->comment->post_id == $post->id)
#foreach($post->comment as $comment)
<div class="row">
<div class="col-md-12 mb-r">
<div class="card example-1 scrollbar-ripe-malinka">
<div class="card-body">
<h4 id="section1"><strong>By: {{ $comment->user->firstName }} {{ $comment->user->lastName }}</strong></h4>
<p>{{ $comment->comment }}</p>
</div>
</div>
</div>
</div>
#endforeach
#endif
</div>
#endforeach
</div>
</div>
Here is my PostController:
public function index(){
$posts = Post::with('comment', 'user')->orderBy('id', 'desc')->limit(20)->get();
return view('post.posts')->with('posts', $posts);
}
You don't need #if statement, remove it. $post->comment is a collection, that 's why your are not getting post_id. if you want to check, then check inside foreach.
#foreach($post->comment as $comment)
<div class="row">
<div class="col-md-12 mb-r">
<div class="card example-1 scrollbar-ripe-malinka">
<div class="card-body">
<h4 id="section1"><strong>By: {{ $comment->user->firstName }} {{ $comment->user->lastName }}</strong></h4>
<p>{{ $comment->comment }}</p>
</div>
</div>
</div>
</div>
#endforeach
You need to add post_id to the comments table and use the relationship:
public function comments()
{
return $this->hasMany(Comment::class);
}
Then you'll be able to load related comments:
Post::with('comments', ....
And iterate over posts and their comments:
#foreach ($posts as $post)
#foreach ($post->comments as $comment)
{{ $comment->content }}
#endforeach
#endforeach
I think if you create relationship between Post model and Comment model (post table and comments table), your #if is useless. I recommend you to check your corresponding models.
Your code should be like this,
Post.php
public function comments(){
return $this->morphMany('App\Comments','commentable');
}
Comment.php
public function commentable(){
return $this->morphTo();
}
in my app Comment model is shared by some other models also.
Eg :- User’s Questions also have comments.
Find more details in laravel:Eloquent page

Update value to database with many to many relations Laravel

I want to update value data from radio button to database table product_categories but I'm confused. Because my data is belongs to many.
Here my belongs to many function in Product Model
public function categories()
{
return $this->belongsToMany(Category::class,'products_categories','product_id','category_id')
->withPivot('id')
->orderBy('category_id')
->withTimestamps();
}
Here my radio button structure in view
{!! Form::model($product, ['route' => ['products.update', $product->id], 'method' => 'patch']) !!}
<div class="dropdown dropdown-full-width dropdown-category">
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">
<span class="name">
<span id="category-select">Choose Category</span>
</span>
<span class="caret"></span>
</button>
<div class="dropdown-menu row">
<div class="col-md-4">
<li><strong>By {{ $category[1] }}</strong></li>
#foreach($category1 as $occasions)
<li>
<div class="checkbox">
<label><input type="radio" name="category['occasions']" class="category-radio" value="{{ $occasions->id }}"> {{ $occasions->name }}</label>
</div>
</li>
#endforeach
</div>
<div class="col-md-4">
<li><strong>By {{ $category[2] }}</strong></li>
#foreach($category2 as $types)
<li>
<div class="checkbox">
<label><input type="radio" name="category['types']" class="category-radio" value="{{ $types->id }}"> {{ $types->name }}</label>
</div>
</li>
#endforeach
</div>
<div class="col-md-4">
<li><strong>By {{ $category[3] }}</strong></li>
#foreach($category3 as $flowers)
<li>
<div class="checkbox">
<label><input type="radio" name="category['flowers']" class="category-radio" value="{{ $flowers->id }}"> {{ $flowers->name }}</label>
</div>
</li>
#endforeach
</div>
</div>
</div>
{!! Form::close() !!}
and here my update function in controller
public function update($id, UpdateProductRequest $request)
{
$product = $this->productRepository->findWithoutFail($id);
$categories = Product::with('categories')->where('id','=', $product->id)->get();
$idcategories = $categories[0]->categories;
if (empty($product)) {
Flash::error('Product not found');
return redirect(route('products.index'));
}
//place update code for radio button here//
Flash::success('Product updated successfully.');
return redirect(route('products.index'));
}
I'm very confused with many to many relation with sync.
Update
Here my table structure in product_categories

Categories