Undefined Variable 'Comments' in Compact Laravel - php

I am getting 'undefined offset 1' error. It does returns everything I need -> the posts and the comments in the category. However, I believe the 'Undefined Offset 1' problem is probably due to some post which have no replies to them?? -> thus, help.
I have
1. Category Model
2. Post Model
3. Comment Model
This is the show function in my Category Model
public function show($id)
{
$category = Category::with('posts.comments')->find($id);
return view('categories.show', compact('category'));
}
I have made relation for 'Category hasMany Posts' -> 'Post hasMany Comments'.

You can try this
public function show($id)
{
$comments = []; // Empty array to initialize the variable. This variable will be filled once the foreach statement is ran.
$category = Category::find($id);
if($category !== null) {
$posts = $category->posts;
foreach($posts as $post) {
$comments = $post->comments;
}
}
return view('categories.show', compact('posts', 'category', 'comments'));
}
Alternative method
public function show(Category $category) //same as... public function show($id)
{
return view('categories.show', compact('category'));
/*
Render this content in the view.
#foreach($category->posts as $post)
{{-- Display Post Content --}}
#foreach($post->comments as $comment)
{{-- Display Comment Content --}}
#endforeach
#endforeach
*/
}

You are creating $comments variable inside foreach loop that make it's scope locally and will not be available outside foreach
To resolved this error you need to define your comments variable inside your function so that it is available in your function
public function show($id)
{
$comments = []; // define it here
$category = Category::find($id);
if($category !== null) {
$posts = $category->posts;
foreach($posts as $post) {
$comments = $post->comments;
}
}
return view('categories.show', compact('posts', 'category','comments'));
}

Related

how to retrieve data from laravel relationship?

Hello im trying to do a quiz app with laravel and im struggeling with retrieving my questions with category..
i have a unsightly solution with this but it's not dynamically..
public function startQuiz(Request $request){
$questions = Question::all();
foreach ($questions as $key => $question) {
dd($question->where('categories_id', 'LIKE', 2)->get()); // i want to change the 2 to the real category id
}
}
i thought i could to that with the relationship like $question->category->id but wont work.
thats my model:
class Question extends Model
{
protected $fillable = ['question_text', 'categories_id', 'correct_answer', 'options'];
protected $casts = ['options' => 'array'];
public function category(){
return $this->belongsTo(Category::class, 'categories_id');
}
}
class Category extends Model
{
protected $fillable = ['name', 'slug'];
public function question()
{
return $this->hasMany(Question::class, 'questions_id');
}
i cant somehow pass the id and check it i dont know why.. thats my form where i pass the category:
#section('content-categories')
<div class="card">
<div class="card-header">Choose Category to Start</div>
<div class="card-body">
#foreach($categories as $category)
<form class="form-group" action="{{route('user.quiz', $category->slug)}}" method="post">
#csrf
<input type="submit" name="categoryTest" class="form-control" value="{{$category->name}}">
</form>
#endforeach
</div>
</div>
#endsection
Edit:
i think i know why i couldnt retrieve data with my relationship..i had an error with my relationship in Category Class, i have not a field for questions_id, i replaced it to:
public function question()
{
return $this->hasMany(Question::class);
}
and now i could get the questions with:
public function startQuiz(Request $request){
$questions = Question::all();
$questionsCategory = [];
if($request){
foreach ($questions as $question) {
if ($request->categoryTest == $question->category->name) {
$questionsCategory = $question->where('categories_id', '=', $question->category->id)
->get();
var_dump($questionsCategory);
}
}
}
}
For your form listing probably you already have $categories = Categories::all().
Next to get all questions of this category after the submit you should first get the category and then questions for it.
Let say you have category id in your form:
$categoryQuestions = Category::find($request->get('id'))->questions;
I see you are using category slug for your url, can also use it to find the category:
public function startQuiz(Request $request, string $slug){
$questions = Category::whereSlug($slug)->first()->questions;
...
}
Bonus:
In your service provider you can bind {category} directly to your model like this:
Route::bind('category', function($value) {
return Category::whereSlug('slug', $value)->first();
});
And then your category will be available in controller methods:
public function startQuiz(Request $request, Category $category){
$questions = $category->questions;
}
Try replacing 'LIKE' with '='. And remove dd(...)Like this:
foreach ($questions as $key => $question) {
dd($question->where('categories_id', 'LIKE', 2)->get());
}
to:
foreach ($questions as $key => $question) {
$question->where('categories_id', '=', 2)->get();
}

Laravel how to loop through array in controller and combine relationship

In my laravel-application I have a blogs- and an author-table. On the index page, where you see all published blog posts, I want the authors name to appear. So I tried to do this:
public function index()
{
$blogs = Blog::where("publishes_on", "<=", Carbon::now())
->orderBy('publishes_on', 'desc')
->published()
->get();
foreach ($blogs as $blog) {
$author = Author::where('id', $blog->author_id)->get();
}
return view('app.blog.index', compact('blogs', 'author'));
}
For some reason I do not know, this gives me the last added author to my application and on each post, the name of that author is displayed on all posts.
What am I doing wrong here?
In Blog model add author relation
public function author()
{
return $this->belongsTo(Author::class);
}
In controller
$blogs = Blog::where("publishes_on", "<=", Carbon::now())
->orderBy('publishes_on', 'desc')
->published()
->with('author:id,name')
->get();
In view you can use
#foreach($blogs as $blog)
// blog related data
Author: {{ $blog->author->name ?? '' }}
#endforeach
No need for the foreach loop
Blog::with('author')->where( [...]`
In your view
$blog->author->name
Make sure you define author() as a relationship on the Blog model:
https://laravel.com/docs/master/eloquent-relationships
e.g.
class Blog {
function author(){
return $this->belongsTo(Author::class);
}
}

laravel getting dynamic view based on url

I have made dynamic category routes by adding custom class to my app (how i did it is here) now i need to make my blade works with this dynamic path.
Logic
based on categories deeps my url will create such as:
site.com/category/parent
site.com/category/parent/child
site.com/category/parent/child/child
etc.
so far my view is just loading for site.com/category/parent for other urls it return 404 error.
code
CategoryRouteService
class CategoryRouteService
{
private $routes = [];
public function __construct()
{
$this->determineCategoriesRoutes();
}
public function getRoute(Category $category)
{
return $this->routes[$category->id];
}
private function determineCategoriesRoutes()
{
$categories = Category::all()->keyBy('id');
foreach ($categories as $id => $category) {
$slugs = $this->determineCategorySlugs($category, $categories);
if (count($slugs) === 1) {
$this->routes[$id] = url('category/' . $slugs[0]);
}
else {
$this->routes[$id] = url('category/' . implode('/', $slugs));
}
}
}
private function determineCategorySlugs(Category $category, Collection $categories, array $slugs = [])
{
array_unshift($slugs, $category->slug);
if (!is_null($category->parent_id)) {
$slugs = $this->determineCategorySlugs($categories[$category->parent_id], $categories, $slugs);
}
return $slugs;
}
}
CategoryServiceProvider
class CategoryServiceProvider
{
public function register()
{
$this->app->singleton(CategoryRouteService::class, function ($app) {
// At this point the categories routes will be determined.
// It happens only one time even if you call the service multiple times through the container.
return new CategoryRouteService();
});
}
}
model
//get dynamic slug routes
public function getRouteAttribute()
{
$categoryRouteService = app(CategoryRouteService::class);
return $categoryRouteService->getRoute($this);
}
blade
//{{$categoryt->route}} returning routes
<a class="post-cat" href="{{$category->route}}">{{$category->title}}</a>
route
//show parent categories with posts
Route::get('/category/{slug}', 'Front\CategoryController#parent')->name('categoryparent');
controller
public function parent($slug){
$category = Category::where('slug', $slug)->with('children')->first();
$category->addView();
$posts = $category->posts()->where('publish', '=', 1)->paginate(8);
return view('front.categories.single', compact('category','posts'));
}
Note: I'm not sure about this but i think i my route is kinda static! I mean it just getting 1 slug with it while my category can goes 2, 3 or 4 slug deep and it doesn't make sense to me to make several route and keep repeating Route::get('/category/{slug}/{slug}/{slug} like that.
As I said I'm not sure about this, please share your idea and solutions if you may.
UPDATE
based on Leena Patel answer I changed my route but when I get more than 1 slug in my url it returns error:
Example
route: site.com/category/resources (works)
route: site.com/category/resources/books/ (ERROR)
route: site.com/category/resources/books/mahayana/sutra (ERROR)
error
Call to a member function addView() on null
on
$category->addView();
when I comment that it returns error for $posts part. then error for my blade where i returned category title {{$category->title}}
So basically it seem doesn't recognize this function for returning view of category routes.
here is my function
public function parent($slug){
$category = Category::where('slug', $slug)->with('children')->first();
$category->addView();
$posts = $category->posts()->where('publish', '=', 1)->paginate(8);
return view('front.categories.single', compact('category','posts'));
}
any idea?
You can try using Route Pattern like below
Route::get('/category/{slug}', 'Front\CategoryController#parent')->where('slug','.+')->name('categoryparent')
So if you have more than one slugs in your url like /category/slug1/slug2
Your addView() method will work for one record and not for Collection So add foreach loop to achieve this.
public function parent($slug){
// $slug will be `slug1/slug2`
$searchString = '/';
$posts = array();
if( strpos($slug, $searchString) !== false ) {
$slug_array = explode('/',$slug);
}
if(isset($slug_array))
{
foreach($slug_array as $slug)
{
$category = Category::where('slug', $slug)->with('children')->first();
$category->addView();
$posts_array = $category->posts()->where('publish', '=', 1)->paginate(8);
array_push($posts,$posts_array);
}
}
else
{
$category = Category::where('slug', $slug)->with('children')->first();
$category->addView();
$posts = $category->posts()->where('publish', '=', 1)->paginate(8);
}
return view('front.categories.single', compact('category','posts'));
}
Hope it helps!
Documentation : https://laravel.com/docs/4.2/routing#route-parameters
Create route
Route::get('category/{cat}', 'YourController#mymethod');
Add this to your Providers/RouteServiceProvider.php 's boot method
public function boot()
{
Route::pattern('cat', '.+'); //add this
parent::boot();
}
In your method:
public function mymethod($cat){
echo $cat; //access your route
}
You can use optional URL sections in the route and use conditionals in controllers. Try this:
In your route:
Route::get('/category/{parent?}/{child1?}/{child2?}', 'Front\CategoryController#parent')->name('categoryparent');
In your controller:
public function mymethod($category, $parent, $child1, $child2){
if(isset($child2)){
//use $category, $parent, $child1, $child2 and return view
} else if(isset($child1)){
//use $category, $parent, $child1 and return view
} else if(isset($parent)){
//use $category, $parent and return view
} else {
//return view for $category
}
}

Trying to get property of non-object error in laravel

ive been trying to match User_id from my users with Creator_id to display the creators username in my post
but im getting the trying to get property from non-object error and i cant get arround it
the function in my controller
postcontroller.php:
public function index()
{
$allusers = users::getusers();
$posts = DB::table('posts')->get();
foreach ($posts as $posts) {
foreach ($allusers as $allusers) {
if ($posts->creator_id == $allusers->user_id) {
array_push($posts,$allusers->username);
}
}
}
return view('blog',['posts'=>$posts]);
}
the functions in my model:
public static function getusers(){
$allusers = users::all();
return $allusers;
}
You are using the same variable names in your foreach loops :
foreach ($posts as $post) {
foreach ($allusers as $user) {
if ($post->creator_id == $user->user_id) {
array_push($post,$user->username);
}
}
}
But for your issue, you should try to add this in your Post Model
public function user(){
return $this->belongsTo(User::class, 'creator_id', 'user_id);
}
then in your view :
#foreach($posts as $post)
{{ $post->user->name }}
#endforeach
https://laravel.com/docs/5.4/eloquent-relationships#one-to-many-inverse
Does your users table has a column like user_id?
I think you have check with users table id with posts creator_id.

Relationship not working. Foreach. Laravel

So I have defined relationship between OrderProduct.php and 'Product.php' models like this:
OrderProduct.php:
public function product()
{
return $this->belongsTo('App\Product');
}
Product.php
public function order()
{
return $this->belongsTo('App\OrderProduct');
}
OrderController function
public function orderShow($id)
{
//$order = Order::where('id', $id)->first();
$products = OrderProduct::where('id', 32)->first();
return view('admin.orders.show', compact('order', 'products'));
}
When I do this foreach:
#foreach($products as $product)
<?php dd($product) ?>
#endforeach
I get Invalid argument supplied for foreach() How to fix this ?
You've got only first record from set.
Try
public function orderShow($id)
{
//$order = Order::where('id', $id)->get();
$products = OrderProduct::where('id', 32)->get();
return view('admin.orders.show', compact('order', 'products'));
}
EDIT
If you need to retrieve particular record by id, use find() or even findOrFail() method (difference you can find in docs);
public function orderShow($id)
{
// this will retrieve record with id=32 from db if it exists,
// and throw Illuminate\Database\Eloquent\ModelNotFoundExceptio otherw
$product = OrderProduct::findOrFail(32);
return view( 'admin.orders.show', compact('product') );
}
then in your blade template you can access your $product info as an object, like so
{{ $product->name }}
{{ $product->otherProductProperty }}
You are giving
$products = OrderProduct::where('id', 32)->first();
which will fetch you only one record the result will not be a collection so you cannot do foreach for this
You can change it as
$products = OrderProduct::where('id', 32)->get();
to make it work
You need to even check the Relationship used. One will be belongs to and the other will be hasmany
you should try like this..
public function orderShow($id)
{
//$order = Order::where('id', $id)->get();
$products = OrderProduct::where('id', 32)->with('product')->get();
return view('admin.orders.show', compact('order', 'products'));
}

Categories