Laravel Retrieve the last record of a thread in the model - laravel

For a certain forum, i retrieve all the posts. I can access them by
$thread->posts
For the moment I can retrive the last post saved for this thread by doing
$thread->posts[0]->author
But i'd like a better solution like something like
$thread->last_post
But I need your help I'm stuck

You can put into your Thread model this:
public function last_post() {
return $this->hasOne('Post')->orderBy('id', 'desc');
}
Then you can access it like you wanted.

You can simply create a method in your Thread model:
public function lastPost() {
return $this->posts[0];
// OR: return $this->posts->first();
}
var_dump($thread->lastPost()->author);

Related

Laravel6 WhereHas Error 500 when using AJAX

im new to Laravel and facing an interesting Issue right now in my App.
I have 3 tables.
Producers
id
producer_name
Types
id
type_name
Models
id
model_name
device_type_id
device_producer_id
Within my Producers Model I have defined the follwing Filter method:
public function scopeFilterByType($query, $type_id)
{
$query->whereHas('models', function($q) use $type_id { $q->where('device_type_id', $type_id );});
}
Using Tinker I can do the following:
App\DeviceProducer::filterByType(3)->get()
And get full response with my Producers associated to my given type.
I created an Function so when a user select a device type Ajax will load all Producers from this type.
public function reqProducer(Request $request)
{
$producers = DeviceProducer::filterByType($request->type_id)->get();
return response()->json( $producers );
}
But when AJAX is calling my endpoint it gets HTTP500 error.
I figured out when using a request without WhereHas for example:
$producers = DeviceProducer::where('id', $request->producer_id)->get();
It just works fine and I get my results. So it seems have to do something with "WhereHas". I know I could Solve this by first asking Models Table and the creating an Foreach loop. But I this solution would be less readable then my first attempt.
Does anyone has an suggestion what im doing wrong or is it just like there is noch AJAX support for WhereHas querys?
Kind regards
Mike
I think this is your issue use $type_id
Please fix as
public function scopeFilterByType($query, $type_id)
{
$query->whereHas('models', function($q) use ($type_id) { $q->where('device_type_id', $type_id );});
}

How do I call `with` directly on an object thats been fetched through a route with the same results as if it were fetched through `where`?

How do I call with directly on an object thats been automagically fetched through a route with the same results as if it were fetched through where?
Let me explain through code!
My route (same in both):
Route::get('post/{post}', 'PostsController#show');
Alternative 1:
My Controller:
public function show(Post $post){
$postWithComments = Post::where('id', $post->id)->with('comments')->first();
}
Output: The comments of the intended post.
Alternative 2:
My Controller:
public function show(Post $post){
$postWithComments = $post->with('comments')->first();
}
Output: The comments from the first of ALL posts.
Desired output: Same as alternative one.
How can I modify the query in alternative 2 to output the same as alternative 1?
I am thinking that it is unnecessary to make first the where-request as I already have the object loaded. So I am thinking that I would want to do this to reduce DB calls. Or am I thinking wrong?
There are two ways to solve this:
Query related data with lazy loading:
$post->comments; // this did the trick - comments for post will queried here
return $post; // here posts already has comments collection
Setup model binding and use eager loading:
At your Post model add resolveRouteBinding method:
class Post extends Model
{
public function resolveRouteBinding($id)
{
return $this->where('id', $id)->with(['comments'])->first();
}
}
Then your controller will recieve Post instance with already loaded comments

A readable way to pull in a hasMany collection into a result object in the controller

Inside a resource controller I have the following show function.
public function show(Invite $invite)
{
return response($invite->jsonSerialize(), Response::HTTP_CREATED);
}
The invite model has many guests and the guest model belongs to an invite. Standard resource routes. When I query the url, I get a response like:
{
id":17,
"user_id":2,
"event_id":1,
"name":"Fred Neumann +1",
"called":0,
"emailed":0,
"invited":1,
"max_guests":2,
"created_at":"2019-05-18 21:31:07",
"updated_at":"2019-05-18 21:31:07",
"deleted_at":null
}
Now I would also like to return the guests along with the invite info. I can achieve this by modifying the show function as such:
public function show(Invite $invite)
{
// Don't remove this line:
$invite->guests = $invite->guests;
return response($invite->jsonSerialize(), Response::HTTP_CREATED);
}
This works fine but it's not obvious that it actually does anything. I could easily see myself removing it later by accident and breaking the API, hence the comment. Is there a more readable alternative?
Load the guests relationship with lazy eager loading:
public function show(Invite $invite)
{
return response($invite->load('guests')->jsonSerialize(), Response::HTTP_CREATED);
}

Best practices to define response in action controller Laravel

I have a method inside PostController
class PostController extends Controller {
public function index() {
$posts = Post::all();
return response($posts);
}
}
Two way:
class PostController extends Controller {
public function index() {
$posts = Post::all();
return $posts;
}
}
Both work fine but which way is better and more correctly?
I personnaly prefer this version:
return \Response::json($data);
Because it makes clear that the response is actual json data.
Just make sure your code is understandable by someone new on your project.
If you are writing an API project, where everything is always returned in json, simply return the model because you don't have to make the reader learn that it's JSON because everything is in JSON everywhere.
On the other hand, if it's some sort of mixed project (some routes return view, JSON, XML, whatever), try to make is as obvious as you can that this specific route return JSON data and nothing else.
Also as stated in comments, stay consistent. The shorter isn't the better. The better is the one that is simple to read and give enough info about what's going on.
It doesn't matter actually.. its depends on your desire and consistency..
return Response::json($model);
//or
return response()->json($model);
//or
return $model;
it give you same output..but if you using response, you can set the status code. most of the time, this reponse thing is used in API project.

Laravel Backpack - getting current record from crud controller

In my crud controller I am trying to get the name of the person who is currently being edited.
so
http://192.168.10.10/admin/people/93/edit
In the people crud controller
public function setup() {
dd(\App\Models\People::get()->first()->name)
}
This returns the first person not the person currently being edited.
How do I return the current person (with an id of 93 in this example)
Ok, So since you use backpack look into CrudController to see how the method looks:
public function edit($id)
{
$this->crud->hasAccessOrFail('update');
$this->data['entry'] = $this->crud->getEntry($id);
$this->data['crud'] = $this->crud;
$this->data['fields'] = $this->crud->getUpdateFields($id);
$this->data['id'] = $id;
return view('crud::edit', $this->data);
}
So now you can overwrite the edit function and change whatever you want. You can even create a custom edit page if you so wish.
Setup on the other hand is usually used to add things like
$this->crud->addClause(...);
Or you can even get the entire constructor and put it in the setup method because setup call looks like this:
public function __construct()
{
// call the setup function inside this closure to also have the request there
// this way, developers can use things stored in session (auth variables, etc)
$this->middleware(function ($request, $next) {
$this->setup();
return $next($request);
});
}
So you could do something like \Auth::user()->id;
Also it's normal to work like this. If you only use pure laravel you will only have access to the current id in the routes that you set accordingly.
Rahman said about find($id) method. If you want to abort 404 exception just use method findOrFail($id). In my opinion it's better way, because find($id)->name can throw
"Trying to get property of non-object error ..."
findOrFail($id) first fetch user with specified ID. If doesn't exists just throw 404, not 500.
The best answer is:
public function edit($id)
{
return \App\Models\People::findOrFail($id);
}
Good luck.
you need person against id, try below
public function setup($id) {
dd(\App\Models\People::find($id)->name);
}

Resources