Cannot loop through Eloquent object in Blade using #foreach - php

I have looked at a similar question but unfortunately the answer does not apply to me.
I know that my object does contain my data but the inside of the #foreach is never called in my view.
Here is my controller:
$newest_article = $this->article->orderBy('created_at', 'DESC')->first();
$articles = Article::allButFirst($newest_article->id)->orderBy('created_at', 'DESC');
return View::make('site/news/index', compact('newest_article', 'articles'));
My model's scopeAllButFirst function:
public function scopeAllButFirst($query, $id){
return $query->where('id', '<>', $id);
}
And lastly my view:
#extends('site.layouts.default')
#section('content')
<section id="news-main">
<div class="container">
<!-- all posts wrapper -->
<div class="news-box-wrap js-packery clearfix" data-packery-options='{ "itemSelector": ".news-item"}'>
#foreach($articles as $article)
<div class="col-sm-4 news-item">
<a href="{{{ $article->url() }}}" class="news-box-inner">
<div class="news-box-image-wrap">
#if($article->image->url('tile_landscape'))
<img src="{{{ $article->image->url('tile_landscape') }}}" class="news-box-image">
#endif
<span class="news-box-icon">
<i class="fa fa-align-left"></i>
</span>
</div>
<div class="news-box-bottom">
<div class="news-box-data">
<span class="news-box-cat">News</span>
•
<span class="news-box-time">{{{ $article->date() }}}</span>
</div>
<h3>{{{ $article->title }}}</h3>
<div class="news-box-det">
<span class="news-box-author">{{{ $article->author->username }}}</span>
<span class="news-box-like"><i class="fa fa-smile-o fa-lg"></i> 225</span>
<span class="news-box-comment"><i class="fa fa-comment-o fa-lg"></i> 16</span>
</div>
</div>
</a>
</div>
#endforeach
</div>
#stop
I need to loop through the Eloquent object because I have to access some of the methods in my model class.
just as a reference, I am following andrewelkins/Laravel-4-Bootstrap-Starter-Site
UPDATE
In my debugging I noticed if I replace
$articles = Article::allButFirst($newest_article->id)->orderBy('created_at', 'DESC');
with
$articles = Article::all();
I don't have this problem.

For those facing the problem, the answer as usual is in the API. Turns out you have to call the get() method in order to receive a Collection. And that is what all() returns. So simply changing
$articles = Article::allButFirst($newest_article->id)->orderBy('created_at', 'DESC');
to
$articles = Article::allButFirst($newest_article->id)->orderBy('created_at', 'DESC')->get();
solves the problem.
Hope it helps

Related

Is there any way to pass object as a parameter in laravel livewire?

I have an array of product and i am trying to pass a single item as a parameter for quick view, but I can't. anyone have any sollution? thanks in advance.
#foreach ($products as $product)
#php
$product = (object) $product;
#endphp
<div class="col-md-3 mb-4">
<div class="product-item product-item-border custom-product-item">
<a class="product-item-thumb" href="shop-single-product.html">
#if (count($product->related_images) > 0)
<img src="{{ $product->related_images[0]['image'] }}" width="233" height="245" alt="Image-HasTech">
#endif
</a>
<div class="product-item-action">
<button type="button" class="product-action-btn action-btn-wishlist" data-bs-toggle="modal" data-bs-target="#action-WishlistModal">
<i class="icon-heart"></i>
</button>
<button type="button" class="product-action-btn action-btn-compare" data-bs-toggle="modal" data-bs-target="#action-CompareModal">
<i class="icon-shuffle"></i>
</button>
<button type="button" wire:click="quickView({{ $product }})" class="product-action-btn action-btn-quick-view">
<i class="icon-magnifier"></i>
</button>
</div>
<div class="product-bottom">
<div class="product-item-info text-center pb-6">
<h5 class="product-item-title mb-2">{{ $product->product_name }}</h5>
{{-- <div class="product-item-price mb-0">{{ $product->default_price }}<span class="price-old">{{ $product->default_price }}</span></div> --}}
</div>
<div class="d-flex justify-content-between">
<div class="ms-4 product-item-price mb-4">{{ $product->default_price }}</div>
<button type="button" wire:click="addToCart({!! $product->id !!})" class="info-btn-cart me-4 mb-4"><i class="icon-handbag"></i></button>
</div>
</div>
</div>
</div>
#endforeach
<div class="col-12">
<div class="text-center">
<div wire:click="nextPage" type="button" class="btn btn-primary">Load more</div>
</div>
</div>
and in my controller I am trying to do something like this:
public function quickView($product)
{
$this->view_product = $product;
}
I tried to pass the object but I am getting error such:
htmlspecialchars() expects parameter 1 to be string, object given
The error happens because in blade {{ }} will automatically escape the output. And this function only escapes strings.
Instead what you can do is
wire:click="quickView( {{ $product->id }} )
And within your livewire component
public function quickView($product_id)
{
// I assume $products is collection
$this->view_product = $this->products->where('id', $product_id)->first();
}
EDIT:
If you do not want to add "extra query" inside quickView()
I suggest you change how $products collection is collected
$this->products = $existing_query->get()->keyBy('id');
This will resulting array list of object product.
After that within quickView() do the following
public function quickView($product_id)
{
$this->view_product = $this->products[$product_id];
}
Extra note: please do add some kind of check or validation in case product with selected id is not found
It may be a little too late but I got to solve something similar by type hinting the object class. From the docs
So maybe you can do something like this:
public function quickView(Product $product)
{
$this->view_product = $product;
}

i can't listing users' post in theirs profile. i use one to many relationship in User model

//here is my controller `
public function index($id){
$users=User::where('id',$id)->get();
return view('user',compact('users'));
}
}`
//here is my User model
public function getPosts()
{
return $this->hasMany('App\Post','user_id','id');
}
//here is my user blade
#foreach($user->getPosts as $post)
<div class="profile-content">
<section class="post-heading">
<div class="rows">
<div class="col-md-11">
<div class="media">
<div class="media-left">
<a href="#">
<img class="media-object photo-profile" src="https://scontent.fgyd4-2.fna.fbcdn.net/v/t1.0-9/p960x960/73248174_2597397730318615_6397819353256951808_o.jpg?_nc_cat=109&_nc_sid=7aed08&_nc_ohc=VxH_cAqJ778AX_7B97W&_nc_ht=scontent.fgyd4-2.fna&_nc_tp=6&oh=e5b02c7f91818664cf253e71f2ddf106&oe=5F5F4E74" width="40" height="40" alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{$user->name}} </h4>
{{$user->$post['created_at']}}
</div>
</div>
</div>
<div class="col-md-1">
<i class="glyphicon glyphicon-chevron-down"></i>
</div>
</div>
</section>
<section class="post-body">
<p>{{ $user->getPost->post['post_description'] }}</p> <!-- i stick around here -->
</section>
//it give this error to me
Property [getPosts] does not exist on this collection instance. (View: C:\xampp\htdocs\site\resources\views\user.blade.php)
In controller get() will return collection,you want one user, so use find() or first(), it will return one user object
public function index($id){
$user=User::find($id); //or $user=User::where('id',$id)->first();
return view('user',compact('user'));
}
Relation method
public function posts()
{
return $this->hasMany('App\Post','user_id','id');
}
Since their is one to many relation between user and posts,you have to use loop to show posts for a user
foreach($user->posts as $post)
<div class="profile-content">
<section class="post-heading">
<div class="rows">
<div class="col-md-11">
<div class="media">
<div class="media-left">
<a href="#">
<img class="media-object photo-profile" src="https://scontent.fgyd4-2.fna.fbcdn.net/v/t1.0-9/p960x960/73248174_2597397730318615_6397819353256951808_o.jpg?_nc_cat=109&_nc_sid=7aed08&_nc_ohc=VxH_cAqJ778AX_7B97W&_nc_ht=scontent.fgyd4-2.fna&_nc_tp=6&oh=e5b02c7f91818664cf253e71f2ddf106&oe=5F5F4E74" width="40" height="40" alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{$user->name}} </h4>
{{$post->created_at}}
</div>
</div>
</div>
<div class="col-md-1">
<i class="glyphicon glyphicon-chevron-down"></i>
</div>
</div>
</section>
<section class="post-body">
<p>{{ $post->post_description }}</p> <!-- i stick around here -->
</section>
#endforeach
$users=User::where('id',$id)->get(); returns a collection of users
So when you do this:
#foreach($user->getPosts as $post)
$user is a collection of users. That collection doesn't have a getPosts() method.
you are returning list of users, so you don't have one user and you can't have the posts of all certain user
below code can fix the issue:
User::where('id', $id)->first();
First of all you should update your controller like this
User::find($id);
You should update your relation like this
public function posts()
{
return $this->hasMany('App\Post','user_id','id');
}
After that you should update your blade like this
foreach ($user->posts as $post)
You can't access posts with ->getPosts. If you want, you should use like this ->getPosts()->get()

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 get an item in an iteration using foreach?

Im having a hard time extracting an item in an array, for example trying to retrieve a post in posts.
this is the error
keep in mind everything works, i can extract posts but im trying to successfully show the delete button to users.
im following laravel polices, to show a delete button for the user who made the post
laravel.com/docs/5.5/authorization#via-blade-templates
Undefined variable: post (View:
/Applications/MAMP/htdocs/eli42/resources/views/home.blade.php)
this is what i have so far
public function index()
{
$posts = Post::with('user')->get();
return view('home', compact('posts'));
}
home.blade.php
<div id="mypost" class="col-md-8 panel-default" ng-repeat="post in myposts ">
<div id="eli-style-heading" class="panel-heading"><% post.user.name %></div>
<div class="panel-body panel">
<figure>
<p> <% post.body %></p>
<p> <% post.created_at %></p>
</figure>
<span>
#foreach($posts as $post)
#if(Auth::user()->can('delete',$post) )
<i style="color:red;" class="glyphicon glyphicon-remove" ng-click="deletePost(post)">
</i>
#endif
#endforeach
<span>Edit</span>
</span>
</div>
</div>
I'm not sure what im doing wrong
it needs to show one close button not 3
return returns program control to the calling module. Execution
resumes at the expression following the called module's invocation.
You are sending request on method getPosts for collecting posts. So you don't need to return posts variable by index method. Then you need it in getPosts.
You are using angular and in this case you need to have variable about delete availability but this variable you need in javascript. Just add it in controller and send to angular, then use ng-if attribute in angular for show/hide delete button.
In this case you need to change getPosts method as it is in answer what will add deletable variable in every post then you can use post.deletable in angular. What you need to end this task is that add ng-if="post.deletable" to <i> tag what means if delete post is available show this tag(button).
Controller
public function getPosts()
{
return response()->json(Post::with('user')->get()->map(function(Post $post){
return collect($post->toArray())->put('deletable', auth()->user()->can('delete', $post));
}));
}
public function index()
{
return view('home');
}
It looks like you are using Angular. For this case your blade seems good.
In this case you don't need $posts variable in view and you don't need #foreach too in blade.
<div id="mypost" class="col-md-8 panel-default" ng-repeat="post in myposts ">
<div id="eli-style-heading" class="panel-heading"><% post.user.name %></div>
<div class="panel-body panel">
<figure>
<p> <% post.body %></p>
<p> <% post.created_at %></p>
</figure>
<span>
<i style="color:red;" class="glyphicon glyphicon-remove" ng-click="deletePost(post)" ng-if="post.deletable"></i>
<span>Edit</span>
</span>
</div>
</div>
You should try this:
Function
public function index() {
$posts = Post::with('user')->get();
return view('home', compact('posts'));
}
home.blade.php
<div id="mypost" class="col-md-8 panel-default" ng-repeat="post in myposts ">
<div id="eli-style-heading" class="panel-heading"><% post.user.name %></div>
<div class="panel-body panel">
<figure>
<p> <% post.body %></p>
<p> <% post.created_at %></p>
</figure>
<span>
#foreach(posts as $post)
#if(Auth::user()->can('delete',$post->id) )
<i style="color:red;" class="glyphicon glyphicon-remove" ng-click="deletePost(post)">
</i>
#endif
#endforeach
<span>Edit</span>
</span>
</div>
</div>

Undefined variable: $ Laravel 5

This is the code from CategoriesController:
public function index()
{
$categories = Category::all();
return view('/home', compact('categories'));
}
And this is the code that I'm writing to the home.blade.php
#foreach($categories as $cat)
#endforeach
And then in home.blade.php
I'm getting this error: Undefined variable: categories
Why this happening ? Everything works fine with Articles but not categories and the code is the same.
Home.blade.php
#extends('app')
#section('content')
<div class="col-md-4 pull-right">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Categories</h3>
</div>
<div class="panel-body">
#foreach($categories as $cat)
<div class="col-lg-6">
<ul class="list-unstyled">
<li>News
</li>
</ul>
</div>
#endforeach
</div>
</div>
</div>
#if(count($articles))
#foreach($articles as $article)
<div class="panel panel-default col-md-8">
<div class="panel-heading">
<h3>{{ $article->title }}</h3>
<small>posted by {{ $article->author->name }} {{ $article->created_at }}</small>
</div>
<div class="panel-body">
{!! str_limit($article->body, 1000) !!}
<hr>
Read More
</div>
</div>
#endforeach
#else
<h1>No articles at the moment.</h1>
#endif
<br>
{!! $articles->render() !!}
#stop
You have two routes
Route::get('/home', 'ArticlesController#index');
Route::get('/home', 'CategoriesController#index');
Which means when you visit /home, only ArticlesController#index is fired, not both.
This means that the $categories variable used in the view is not populated because your index() method in CategoriesController is intended to do this but is never called.
Therefore you need to do something like this
Route::get('/home', 'HomeController#index');
public function index()
{
$categories = Category::all();
$articles = Article::all();
return view('/home', compact('articles', 'categories'));
}
try to use
return View::make('/home')->with(compact('categories'));
instead of
return view('/home', compact('categories'));
I insert this in the top of my #foreach
<?php
use App\models\PersonalContact;
$data = PersonalContact::all();
?>
or this before #foreach add #if statement like this
#if (count($data) > 0)
#foreach ($data as $bloginfo)
<tr role="row" class="odd">
<td class="sorting_1">{{$bloginfo->name}}</td>
<td>{{$bloginfo->description}}</td>
<td>{{$bloginfo->email}}</td>
<td>{{$bloginfo->phone}}</td>
<td><img src="{{url('images/'.$bloginfo->image)}}" alt="" width="100px" height="100px"></td>
<td><i class="fas fa-edit"></i>Add | <i class="fas fa-edit"></i>Edit | <a class="btn btn-app"><i class="fas fa-edit"></i>Delete</a></td>
</tr>
#endforeach
#endif
return view('/home', compact('categories'));
The problem was $categories on compact method, you must use like a string

Categories