Beginner in Laravel - Eager loading seems to not work? - php

I'm new to Laravel and I'm trying to make a post where the user's post can receive likes from other users. But I'm trouble at when you click the user, it was suppose to direct to the users page where you can see all its post and the likes the it received. This is the code that suppose to do that work:
This is the controller:
public function index(User $user)
{
$posts = $user->posts()->with('user', 'likes')->get();
return view('users.posts.index', [
'user' => $user,
'posts' => $posts,
]);
}
}
and this is the view/template:
<div class="flex justify-center">
<div class="w-8/12 bg-white p-6 rounded-lg">
{{$user->name}}
</div>
</div>
I don't know what's the problem though, or is it a bug with Laravel eager loading?
But unfortunately it only returns a blank page, there's no error though.
The thing is after putting this code inside dump and die, there's data showing from the database. I don't why it doesn't show. Can someone help me with this problem? Much appreciated
Following this tutorial: https://www.youtube.com/watch?v=MFh0Fd7BsjE
Tutorial Github: https://github.com/codecourse/posty-traversy-media

If you want to access the posts you can iterate through them:
#foreach($posts as $post)
{{ $post->title }}
{{ $post->likes->count() }}
#endforeach
Not sure what data or relationships you want to access.

Check your route whether it has a user id for model injection
eg:/index/{user}
also in your blade example, there is no posts are used.you are using the user object
public function index(User $user)
{
$posts = $user->posts()->with('user', 'likes')->get();
return view('users.posts.index')->with([
'user' => $user,
'posts' => $posts,
]);
}

Related

Attempt to read property "ticket_title" on bool

I have this problem when I want to open specific page by id.
now I am trying to shown title on my page with specific id, which have post in db, but that error stopped me.
there are my code.
route
Route::get('/tickets/{id}', [TicketsController::class, 'show'])->name('tickets.show');
controller
public function show($id) {
$tickets = Tickets::with('companies')->get();
$ticketscomp = Companies::with('tickets')->get();
$severities = Severities::with('tickets')->get();
$ticketspage = Tickets::findOrFail($id);
return view('tickets.chat', compact('ticketspage'))->with(['tickets'=> $tickets])->with(['ticketscomp'=>$ticketscomp])->with(['severities'=>$severities])->with(['ticketspage'=>$ticketspage]);
//dd($ticketspage->toArray());
blade.php
#foreach ($ticketspage as $item)
<h6 class="mb-1; ticket-list-title;">{{ $item->ticket_title }}</h6>
#endforeach
When I dd post. post is opening by id with included information.
::findOrFail() returns a single model instance. You do not need a #foreach() loop.
<h6 class="mb-1; ticket-list-title;">{{ $ticketspage->ticket_title }}</h6>
I fix this now but if someone have problem like me just read my comment.
Just remove foreach and type like this
<h6 class="mb-1; ticket-list-title;">{{ $ticketspage->ticket_title }}</h6>

Property [name] does not exist in laravel

I want to show my product in a single page but I have "Property [name] does not exist on this collection instance." error
blade:
<div class="title">
<h2>{{ $singleproduct->name }}</h2>
</div>
<div class="single-product-price">
<h3>{{ $singleproduct->price }}</h3>
</div>
<div class="single-product-desc">
<p>{!! $singleproduct->explain !!} </p>
</div>
controller:
public function show()
{
$singleproduct = Singleproduct::get();
return view('UI.store.SingleProduct' , compact('singleproduct' ));
}
route:
Route::get('/singleproduct/{product}' , 'admin\SingleproductController#show');
You have a Collection of potentially many or no Singleproducts. If you only want 1 you would use first.
Most likely because this is a show route you want a specific Singleproduct, which I will guess you are passing an 'id' via the URL.
public function show($product)
{
$singleproduct = Singleproduct::findOrFail($product);
return view('UI.store.SingleProduct', compact('singleproduct'));
}
Now in the view you know that singleproduct is definitely an instance of Singleproduct and is accessible.
You need to select only one product not all of them,
so you can update your show method like this
using the route model binding you can read more about this awesome feature in laravel docs
public function show(Singleproduct $product)
{
return view('UI.store.SingleProduct' , compact('product' ));
}

Laravel - getting relation in loop - best practices

Just an example:
let's say I have Post model, and the Comment model. Post, of course, have Comments, one-to-many relation.
I have to display list of posts with comments below it.
I'll get my posts in the controller:
$posts = Post::get(), I'll pass it to the blade view and then I'll loop through it
#foreach($posts as $post)
{{ $post->title }}
{{ $post->comments }}
#endforeach
where $post->comments is some relation
public function comments()
{
return $this->hasMany(Comment::class);
}
As we know, that query will be executed many times.
Now my question: how we should optimize it?
Return Cache::remember in the getter?
Get (somehow?) those comments, when getting the posts in one query? Something like join query? I know that I can write that kind of query, but I'm talking about Eloquent's query builder. And then how get the comments within the loop? Wouldn't {{ $post->comments }} call the relation again instead of getting stored data?
Different solution?
You can do $posts = Post::with('comments')->get() to eager load the comments with the post. Read more about it in the documentation: https://laravel.com/docs/5.7/eloquent-relationships#eager-loading
Also, to display the comments you would want to add another foreach loop. It would look something like this:
#foreach($posts as $post)
{{ $post->title }}
#foreach($post->comments as $comment)
{{ $comment->title }}
#endforeach
#endforeach
You’ve probably cached some model data in the controller before, but I am going to show you a Laravel model caching technique that’s a little more granular using Active Record models
Note that we could also use the Cache::rememberForever() method and rely on our caching mechanism’s garbage collection to remove stale keys. I’ve set a timer so that the cache will be hit most of the time, with a fresh cache every fifteen minutes.
The cacheKey() method needs to make the model unique, and invalidate the cache when the model is updated. Here’s my cacheKey implementation:
public function cacheKey()
{
return sprintf(
"%s/%s-%s",
$this->getTable(),
$this->getKey(),
$this->updated_at->timestamp
);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
public function getCachedCommentsCountAttribute()
{
return Cache::remember($this->cacheKey() . ':comments_count', 15, function () {
return $this->comments->count();
});
}
yes u can do like that in controller
$minutes = 60;
$posts = Cache::remember('posts', $minutes, function () {
return Post::with('comments')->get()
});
in blade u can get like that
#foreach($posts as $post)
{{ $post->title }}
#foreach($post->comments as $comment)
{{ $comment->title }}
#endforeach
#endforeach
for more information read this article

Laravel displaying all posts with WHERE clause and pagenation in laravel

so i want to display post in my index page but only the posts that are reviewed by the admin. so i added another column in my database table post which is called "review" which is integer. So this is what i have in hand.
in my controller i have this
public function index()
{
$this->layout->content = View::make('partials.index',
array(
'posts' => Post::paginate(9)
));
}
and in my index page i have this
#section('content')
<div class="dashboard">
#foreach (array_chunk($posts->getCollection()->all(),2) as $row)
<div class="row">
#foreach($row as $post)
<article class="col-md-4 effect4" id="dash-box">
<p></p>
<c>{{$post->content}}</c><br>
<b>{{$post->title}}</b><br>
<d>posted..{{$post->created_at->diffForHumans()}}</d>
<hr>
</article>
#endforeach
</div>
#endforeach
<div class="page">
{{$posts->appends(Request::only('difficulty'))->links()}}
</div>
</div>
#stop
Help im newbie here i hope someone can help me out with this one hoping for a reply thanks
Just call:
Post::whereReview(1)->paginate(9);
Please read the documentation (and also the one for the query builder since these pages apply to Eloquent as well)
You can just add a where() call to the query:
$posts = Post::where('review', '=', 1)->paginate(9);
Or a shorter version (= is the default operator)
$posts = Post::where('review', 1)->paginate(9);
Or even with a dynamic method name:
$posts = Post::whereReview(1)->paginate(9);
Also you can use true instead of 1. Laravel will convert it:
$posts = Post::whereReview(true)->paginate(9);
There is also no need to do chunking that complicated:
#foreach (array_chunk($posts->getCollection()->all(),2) as $row)
You can just use the chunk method on any collection:
#foreach ($posts->chunk(2) as $row)

Laravel eloquent undefined method user when querying 3 tables

Hi I'm trying to query three tables from my client controller, a quick overview of my database, users clients projects tasks a user hasMany clients, projects and tasks and these projects and tasks also belongTo a client.
So I'm in the Client Controller and I want to query the logged in users clients projects, however when I try to do this I get thrown an undefined method error:
BadMethodCallException Call to undefined method Illuminate\Database\Query\Builder::user()
I'm not sure why this is occurring, I queried the clients projects separately and it works fine but when I add an additional layer it throws me the above error.
I'm a newbie on Laravel 4 so would appreciate some guidance to help rectify the error and help me understand where I'm going wrong.
My code is below:
ClientController.php
public function show($id)
{
$client = Client::find($id);
$client->load(array('projects' => function($query)
{
// With the clients for each project
$query->with('user');
}));
// Create an empty array
$associated = array();
// Loop through client projects
foreach($client->projects as $project):
// Loop through project users
foreach($project->user as $user):
// Check if the user is the same as the logged in user
if($user->id == Auth::user()->id){
// If yes add the $project to the $associated array
array_push($associated, $project);
}
endforeach;
endforeach;
// show the view
return View::make('clients.show')
->with('client', $client);
}
clients/show.blade.php
<?php $clients = $client->projects; ?>
#if (Auth::check())
#if (count($clients) > 0)
#foreach ($clients as $project)
<div class="one-third column">
<div class="projects">
<ul class="data">
<li><label>Project Name: </label><a class="btn btn-small btn-success" href="{{ URL::to('project/' . $project->id.'/show' ) }}"> {{ $project->project_name }}</a></li>
<li><label class="titletoggle">Project Brief <p>(click to toggle)</p></label><p class="brief">{{ $project->project_brief }}</p></li>
</ul>
<ul class='buttonslist'>
<li><button>Edit Project</button></li>
<li><button>Create Task</button></li>
<li><button>View Tasks</button></li>
</ul>
</div>
</div>
#endforeach
#else
<h3>You have no projects click here to create a project</h3>
#endif
#endif
The problem has to do with the way you are eager loading. Specifically this part.
$client->load(array('projects' => function($query)
{
// With the clients for each project
$query->with('user');
}));
The proper way to eager load these nested relationships would be.
$client->load(array(
'projects',
'projects.user',
));
Or more simply.
$client->load('projects.user');
Or you can set up the eager loading during the initial query.
$client = Client::with('projects.user')->find($id);
You also didn't mention that projects belongs to user. This relationship will need to be defined in the Project model.
class Project extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
}
The lack of this method is probably the cause of the error message. Eloquent will forward calls to undefined methods to it's internal query builder object. The query builder object doesn't have a user() method, so that's why you get that error.

Categories