Eloquent relationship through 2 models - laravel

I have Post model:
class Post extends Model
{
use HasFactory;
protected $fillable = [
'category_id',
'user_id',
'img',
'title',
'content',
];
public function user(){
return $this->belongsTo(User::class);
}
public function category(){
return $this->belongsTo(Category::class);
}
public function comments(){
return $this->hasMany(Comment::class)->where('parent_id', '0');
}
}
Comments model:
class Comment extends Model
{
use HasFactory;
protected $fillable = [
'post_id',
'user_id',
'parent_id',
'content',
// 'img'
];
public function user()
{
return $this->belongsTo(User::class);
}
public function replies()
{
return $this->hasMany(Comment::class,'parent_id');
}
}
Can I use the replies function via the post model?
For example:
#foreach($comments->comments->replies->sortByDesc('id') as $comment)
#endforeach
I am just trying to add replies to comments.
<div class="col-md-12">
<div class="blog-comment">
<hr/>
<ul class="comments">
<li class="clearfix">
#foreach($post as $comments)
#foreach($comments->comments->sortByDesc('id') as $comment)
<img src="https://bootdey.com/img/Content/user_1.jpg" class="avatar">
<div class="post-comments">
<p class="meta d-flex justify-content-between">{{ $comments->user->name }}<span>{{ $comments->user->created_at }}</span></p>
<p>
{{ $comment->content }}
</p>
</div>
<form action="{{ route('comment.store') }}" method="POST" class="w-100">
#csrf
<div class="replyform d-flex mb-3">
<input type="hidden" name="post_id" value="{{ $comments->id }}">
<input type="hidden" name="parent_id" value="{{ $comment->id }}">
<input class="d-block ml-auto w-50 align-top" type="text" name="content" required>
<button type="submit" class="offset replysub fas fa-paper-plane ml-1"></button>
</div>
</form>
#endforeach
#endforeach
#foreach($comments->comments->replies->sortByDesc('id') as $comment)
#if($comment->parent_id !== 0)
<ul class="comments">
<li class="clearfix">
<img src="https://bootdey.com/img/Content/user_3.jpg" class="avatar">
<div class="post-comments">
<p class="meta">Dec 20, 2014 JohnDoe says : <i class="pull-right"><small>Reply</small></i></p>
<p>
{{ $comment->content }}
</p>
</div>
<input class="replyform d-block ml-auto mb-3 w-50" type="text" name="" value="">
</li>
</ul>
#endif
#endforeach
</li>
</ul>
</div>
</div>
Of course, I can take and pass one more variable to the template, but I heard that you shouldn't do this, it overloads the controller. Therefore, I try to do it through an eloquent relationship.
P.S. Or is there a way to do it in the post model? Like:
public function replies(){
return $this->hasMany(Comment::class)->where('parent_id', 'id(of parent comment)');
}

Related

Pre-Populating Parent Child Form from DB

I have tried prepopulating the forms from DB records, not happening for child form, I have use all conventions for Laravel table, pivot table etc., still nothing. The array display with the dd('$allTariffs') but doesn't show on view file, please help am stuck with
ErrorException
foreach() argument must be of type array|object, null given
Edit Component Code
<?php
namespace App\Http\Livewire\Admin;
use App\Models\Products;
use App\Models\Tariffs;
use Livewire\Component;
class AdminEditTariffsComponent extends Component
{
// public $productId;
public $tariffId;
public $allTariffs = [];
public $rowProducts = [];
public $tariffName;
public function mount ($tariffId)
{
$this->rowProducts = Products::all();
$tariff = Tariffs::where('id', $tariffId)->first();
$this->tariffName = $tariff->tariff_name;
// $allTariffs = $tariff->products()->where('tariffs_id', $tariffId)->get()->toArray();
$allTariffs = $tariff->products->find($tariffId);
// var_dump($allTariffs) ;
// dd( $allTariffs);
foreach ($allTariffs->products as $product)
{
['productId' => $product->pivot->products_id, 'basicCharge' => $product->pivot->basic_charge, 'additionalCharge' => $product->pivot->additional_charge];
}
}
public function updateStatus()
{
$tariff = Tariffs::find($this->tariffId);
$tariff->tariff_name = $this->tariffName;
$tariff->created_by = auth()->user()->id;
$tariff->save();
foreach ($this->allTariffs as $product) {
$tariff->products()->sync($product['productId'],
['basic_charge' => $product['basicCharge'],
'additional_charge' => $product['additionalCharge']]);
}
session()->flash('message', 'Tariff added successfully!');
return redirect('/admin/tariffs/');
}
public function addProduct()
{
$this->allTariffs[] = ['productId' => '', 'basicCharge' => '', 'additionalCharge' => ''];
}
public function removeProduct($index)
{
unset($this->allTariffs[$index]);
$this->allTariffs = array_values($this->allTariffs);
}
public function render()
{
$rowProducts = Products::all();
return view('livewire.admin.admin-edit-tariffs-component',['rowProducts'=>$rowProducts])->layout('layouts.admin.base');
}
}
Edit View
<div class="container-fluid">
<!-- Begin Page Content -->
<!-- Page Heading -->
<div class="row">
<div class="col-lg-8">
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">Edit Tariff</h6>
</div>
<div class="card-body">
<form wire:submit.prevent="editTariff">
#csrf
<div class="form-row">
<!-- Default input -->
<div class="form-group col-md-8">
<input type="text" class="form-control" placeholder="Enter Tariff Name"
wire:model="tariffName" required>
</div>
</div>
<hr>
<div class="card">
<div class="card-header">
<h6 class="text-primary">Products, Basic and Weight Charges</h6>
</div>
<div class="card-body">
<table class="table" id="products_table">
<thead>
<tr>
<th>Product</th>
<th>Basic Charge</th>
<th>Weight Charge</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach ($allTariffs as $index => $allTariff)
<tr wire:key="tariff-{{ $value->wireKey }}">
<td>
<select
wire:model="allTariffs.{{$index}}.productId"
class="custom-select custom-select-sm form-control form-control-sm">
<option value="">Select Product</option>
#foreach ($rowProducts as $product)
<option value="{{ $product->id }}">
{{ $product->product_name }}
</option>
#endforeach
</select>
</td>
<td>
<input type="text"
class="form-control custom-select-sm form-control form-control-sm"
placeholder="Basic Charge"
wire:model="allTariffs.{{$index}}.basicCharge" required>
</td>
<td>
<input type="text"
class="form-control custom-select-sm form-control form-control-sm"
placeholder="Weight Charge"
wire:model="allTariffs.{{$index}}.additionalCharge" required>
</td>
<td>
<a href="#" wire:click.prevent="removeProduct({{$index}})" class="btn btn-danger btn-circle btn-sm">
<i class="fas fa-trash"></i>
</a>
</td>
</tr>
#endforeach
</tbody>
</table>
<div class="row">
<div class="col-md-12">
<a href="#" wire:click.prevent="addProduct" class="btn btn-success btn-circle btn-sm">
<i class="fas fa-plus"></i>
</a>
</div>
</div>
</div>
</div>
<hr>
<div class="form-row">
<div class="form-group col-md-3">
<button type="submit" class="form-control btn btn-small btn-primary">Edit
Tariff</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- /.container-fluid -->
</div>
Model File
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Tariffs extends Model
{
use HasFactory;
protected $table = "tariffs";
public function products()
{
return $this->belongsToMany(Products::class, 'products_tariffs',
'products_id', 'tariffs_id')
->withPivot('basic_charge', 'additional_charge');
}
public function productstariffs()
{
return $this->hasMany(ProductsTariffs::class);
}
}
I have tried prepopulating the forms from DB records, not happening for child form, I have use all conventions for Laravel table, pivot table etc., still nothing. The array display with the dd('$allTariffs') but doesn't show on view file, please help am stuck with
ErrorException
foreach() argument must be of type array|object, null given .thankyou
In your foreach in your mount function, you are creating an array but you aren't assigning it to anywhere. Therefore, $allTariffs is empty.
Also, you're casting your variables by default as an array. You are setting $rowProducts as a Collection, however. But then in your render you are also getting the $rowProducts again. I'd suggest removing the = [] and removing the fetching of the $rowProducts each render.
public $allTariffs = [];
public $rowProducts;
public $tariffName;
public function mount ($tariffId)
{
$this->rowProducts = Products::all();
// This assumes the $tarrifId always exists. If this isn't the case, perhaps
// wrap the related code in an "if ($tariff instanceof Tariff)"
$tariff = Tariffs::find($tariffId);
$this->tariffName = $tariff->tariff_name;
foreach ($tariff->products as $product) {
$this->allTariffs[] = ['productId' => $product->id, 'basicCharge' => $product->pivot->basic_charge, 'additionalCharge' => $product->pivot->additional_charge];
}
}
public function render()
{
return view('livewire.admin.admin-edit-tariffs-component')->layout('layouts.admin.base');
}

Array to string conversion using laravel

I am trying to send a multi user-id into the database when I select users from the checkbox then I click to submit so I face error Array to string conversion how can I resolve this issue? please help me thanks.
please see error
https://flareapp.io/share/17DKWRPv
controller
public function adduseraction(REQUEST $request)
{
$useradd=$request->get('userid');
$checkid=$request->get('multiusersid');
$user=Users_permissions::create([
'user_id'=>$useradd,
'user_Access_id'=> $checkid
]);
$user->save();
}
html view
<div class="card card-success">
<div class="card-header">
<h3 class="card-title">Users Permission </h3>
</div>
<br>
<form action="{{route('adduseraction')}}" method="post">
{{ csrf_field() }}
<div class="col-sm-4">
<select name="userid" class="form-control">
#foreach($users as $user)
<option value="{{$user->id}}">{{$user->name}}</option>
#endforeach
</select>
</div>
<div class="card-body">
<!-- Minimal style -->
<div class="row">
#foreach($users as $user)
<div class="col-sm-2">
<div class="form-check">
<input type="checkbox" name="multiusersid[]" value="{{$user->id}}" class="form-check-input" >
<h5 style="position:relative;left:10px;">{{$user->name}}</h5>
</div>
<!-- checkbox -->
</div>
#endforeach
</div>
<!-- /.card-body -->
</div>
<div class="card-footer">
<button type="submit" name="btnsubmit" class="btn btn-primary col-md-2
center">Submit</button>
</div>
</form>
</div>
<!-- /.content-wrapper -->
Route
Route::post('adduseraction','AdminController#adduseraction')->name('adduseraction');
** current status **
{"_token":"4Z3ISznqKFXTMcpBKK5tUgemteqxuJjQpKF8F0Ma","userid":"6","multiusersid":["2","5","7"],"btnsubmit":null}
use implode($checkid, ',');
public function adduseraction(REQUEST $request)
{
$useradd=$request->get('userid');
$checkid=$request->get('multiusersid');
$user=Users_permissions::create([
'user_id'=>$useradd,
'user_Access_id'=> implode($checkid, ',');
]);
}
Change in your Users_permissions model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Users_permissions extends Model
{
protected $table = 'userspermissions';
protected $fillable = [
'user_id','user_Access_id'
];
}
Here is your solution
public function adduseraction(REQUEST $request)
{
$useradd=$request->get('userid');
$checkid=implode(",", $request->get('multiusersid'));
Users_permissions::create([
'user_id'=>$useradd,
'user_Access_id'=> $checkid
]);
}
It is expecting a string and you are passing an array of ids. You may want to change the database to json or do json_ecode(checkid). Which will stringify your array. then you can store. However, remember you will need to convert it back with typecasting or manually doing it.
example:
public function adduseraction(REQUEST $request)
{
$useradd=$request->get('userid');
$checkid=$request->get('multiusersid');
$user=Users_permissions::create([
'user_id'=>$useradd,
'user_Access_id'=> json_encode($checkid)
]);
// $user->save(); // yes obviously not needed
}

ReflectionException (-1) Class App\Http\Controllers\AnswersController does not exist

I want to save data in a database using the form
I tried to use a form with input text, radios ... and controller to save data in a database with post method
Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Auth;
use App\Survey;
use App\Answer;
use App\Http\Requests;
class Answerscontroller extends Controller
{
public function store(Request $request, Survey $survey)
{
$request->validate([
'answer'=>'required'
]);
$answers = new Answer([
'answer' => $request->get('answer'),
'commentaire' => $request->get('commentaire'),
'user_id' => auth()->id(),
'last_ip' => request()->ip(),
'survey_id' => $survey->id
]);
$answers->save();
return redirect('/survey')->with('success', 'Stock has been added');
}
}
View:
{!! Form::open(array('action'=>array('AnswersController#store', $survey->id))) !!}
#forelse ($survey->questions as $key=>$question)
<p class="flow-text">Question {{ $key+1 }} - {{ $question->title }}</p>
#if($question->question_type === 'text')
<div class="form-group">
<div class="input-field col s12">
<input id="answer" type="text" name="{{ $question->id }}[answer]">
<label for="answer">Answer</label>
</div>
</div>
#elseif($question->question_type === 'textarea')
<div class="form-group">
<div class="input-field col s12">
<textarea id="textarea1" class="materialize-textarea" name="{{ $question->id }}[answer]"></textarea>
<label for="textarea1">Textarea</label>
</div>
</div>
#elseif($question->question_type === 'radio')
#foreach($question->option_name as $key=>$value)
<p style="margin:0px; padding:0px;">
#if($value === 'else')
<div class="form-group" style="margin-left: 20px;">
<input name="answer" class="custom-control-input" type="radio" id="{{ $value }}" value="{{$value}}"/>
<label class="custom-control-label" for="{{ $value }}">{{ $value }}</label>
<div id="textboxes" style="display: none">
<br>
<textarea class="form-control" name="commentaire" id="exampleFormControlTextarea1" rows="3" placeholder="Write a large text here ..."></textarea>
</div>
</div>
#else
<p style="margin:0px; padding:0px;">
<div class="form-group" style="margin-left: 20px;">
<input name="answer" class="custom-control-input" type="radio" id="{{ $value }}" value="{{ $value}}"/>
<label class="custom-control-label" for="{{ $value }}">{{ $value }}</label>
</div>
</p>
#endif
#endforeach
#elseif($question->question_type === 'checkbox')
#foreach($question->option_name as $key=>$value)
<p style="margin:0px; padding:0px;">
<div class="form-group">
<input type="checkbox" id="{{ $value }}" name="answer" value="{{$value}}"/>
<label for="{{$value}}">{{ $value }}</label>
</div>
</p>
#endforeach
#endif
<div class="divider" style="margin:10px 10px;"></div>
#empty
<span class='flow-text center-align'>Nothing to show</span>
#endempty
<div class="form-group">
{{ Form::submit('Submit Survey', array('class'=>'btn btn-success mt-4')) }}
</div>
{!! Form::close() !!}
model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Answer extends Model
{
protected $fillable = ['answer','commentaire','user_id','survey_id','last_ip'];
protected $table = 'Answer';
public function survey() {
return $this->belongsTo(\App\Survey::class);
}
public function question() {
return $this->belongsTo(\App\Question::class);
}
public function user() {
return $this->belongsTo('App\User');
}
}
Error:
ReflectionException (-1) Class App\Http\Controllers\AnswersController
does not exist
Please could you help me to fix that
ps: in the router, I put post method and controller
The problem is about naming. Your controller is Answerscontroller but the Laravel Looks fo AnswersController with capital C. So, check your controller name that should be AnswersController.php and the class name (inside the file AnswersController.php) that sould be AnswersController.

Cant Display my Reply under the Comment Laravel 5.7

I can't display my reply under each comment. Here is my code...
Comment model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function commentable()
{
return $this->morphTo();
}
public function user()
{
return $this->belongsTo('App\User');
}
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
Post model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = [
'user_id', 'topic', 'body', 'category',
];
public function user()
{
return $this->belongsTo('App\User');
}
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
Comment controller
<?php
namespace App\Http\Controllers;
use App\Comment;
use App\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class CommentController extends Controller
{
public function store(Request $request, $post)
{
$comment = new Comment;
$comment->body = $request->body;
$comment->user_id = Auth::user()->id;
$post = Post::find($post);
$post->comments()->save($comment);
return back();
}
public function replyStore(Request $request, $comment)
{
$comment = new Comment;
$comment->body = $request->body;
$comment->user_id = Auth::user()->id;
$comment = Comment::find($comment);
$comment->comments()->save($comment);
return back();
}
}
Routes
Route::post('/comment/store/{post}', 'CommentController#store')->name('comment.add');
Route::post('/reply/store/{commentid}', 'CommentController#replyStore')->name('reply.add');
View
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
<div class="card">
<div class="card-header">{{$post->topic}}
Create New Post
</div>
<div class="card-body">
#if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
#endif
<h3>{{$post->topic}}</h3>
<p>{{$post->body}}</p>
</div>
</div>
<form action="/comment/store/{{$post->id}}" method="post" class="mt-3">
#csrf
<div class="form-group">
<label for="">Comment :</label>
<textarea class="form-control" name="body" id="" rows="3"></textarea>
<br>
<input type="submit" value="Comment" class="btn btn-secondary">
</div>
</form>
<div class="row mt-5">
<div class="col-md-10 mx-auto">
<h6 style="border-bottom:1px solid #ccc;">Recent Comments</h6>
#foreach($post->comments as $comment)
<div class="col-md-12 bg-white shadow mt-3" style="padding:10px; border-radius:5px;">
<h4>{{$comment->user->name}}</h4>
<p>{{$comment->body}}</p>
<button type="submit" class="btn btn-link" onclick="toggleReply({{$comment->id}})">
Reply
</button>
<div class="row">
<div class="col-md-11 ml-auto">
{{-- #forelse ($replies as $repl)
<p>{{$repl->body}}</p>
#empty
#endforelse --}}
</div>
</div>
</div>
<form action="/reply/store/{{$comment->id}}" method="post"
class="mt-3 reply-form-{{$comment->id}} reply d-none">
#csrf
<div class="form-group">
<textarea class="form-control" name="body" id="" rows="3"></textarea>
<br>
<input type="submit" value="Reply" class="btn btn-secondary">
</div>
</form>
#endforeach
</div>
</div>
</div>
</div>
</div>
#endsection
#section('js')
<script>
function toggleReply(commentId) {
$('.reply-form-' + commentId).toggleClass('d-none');
}
</script>
#endsection
I have created the normal table with parent_id but I don't know how to display the replies for each comment. Please, anyone who can help me with this - I am stranded here and the error coming from the second controller function which is replystore() saying it doesn't recognize the comments() method. Please help me out to display the reply.

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'pk5.roles' doesn't exist

I am able to insert records to employee_roles through tinker but unable to insert them through code
Role.php
<?php
namespace App\Models\Admin\Employee;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
protected $table = 'employee_roles';
public function permissions()
{
return $this->belongsToMany('App\Models\Admin\Employee\Permission', 'employee_permission_role', 'role_id', 'permission_id');
}
}
RoleController.php
<?php
namespace App\Http\Controllers\Admin\Employee;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Employee\Employee;
use App\Models\Admin\Employee\Role;
use App\Models\Admin\Employee\Permission;
class RoleController extends Controller
{
public function __construct()
{
$this->middleware('auth:admin');
}
public function index()
{
$roles = Role::all();
return view('admins.employees.roles.role', compact('roles'));
}
public function create()
{
$permissions = Permission::all();
return view('admins.employees.roles.create',compact('permissions'));
}
public function store(Request $request)
{
//dd($request);
$this->validate($request, [
'name' => 'required|unique:roles'
]);
$role = new Role();
$role->name = $request['name'];
$role->save();
$role->permissions()->sync($request->permission);
return redirect(route('admin.employee.role.index'));
}
admins.employees.roles.create.blade.php
#extends('layouts.admin')
#section('title', 'Role - Create')
#section('left-menu')
#endsection
#section('right-menu')
#endsection
#section('content')
<h1>Add an Employee Role</h1>
<br><br>
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
<form action="{{ route('admin.employee.role.store') }}" method="post">
#csrf
<div class="form-group">
<label for="name">Role Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Role Name" value="{{ old('name') }}">
</div>
<div class="form-row">
<div class="col-md-4">
<label for="name"><b>Customer Permissions</b></label>
#foreach ($permissions as $permission)
#if ($permission->for == 'Customer')
<div class="checkbox">
<label><input type="checkbox" name="permission[]" value="{{ $permission->id }}">{{ $permission->name }}</label>
</div>
#endif
#endforeach
</div>
<div class="col-md-4">
<label for="name"><b>Despatch Permissions</b></label>
#foreach ($permissions as $permission)
#if ($permission->for == 'Despatch')
<div class="checkbox">
<label><input type="checkbox" name="permission[]" value="{{ $permission->id }}">{{ $permission->name }}</label>
</div>
#endif
#endforeach
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
Back
</div>
</form>
#endsection
#section('pagescript')
#stop
$this->validate($request, [
'name' => 'required|unique:roles'
]);
You should fix table name as employee_roles
Because you don't have table as roles you said that in your Role model you're using employee_roles table ( protected $table = 'employee_roles';)

Resources