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`? - laravel

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

Related

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);
}

How to load a CodeIgniter view in $promise->then() in a controller?

In my CodeIgniter 2 controller I call a model method which returns a ReactPHP promise, and I want to load a CodeIgniter view in the function called by that promise's ->then() method. How can I do this? What happens instead is the controller method returns nothing, so I get a blank page in the browser.
Here is a simplified example illustrating what I'm trying to do:
class My_class extends My_Controller {
function my_method() {
$this->my_model->returns_a_promise()->then(function ($data) {
// How can I pass the promise's resolved value to the template here?
// It seems this never gets called, because my_method() returns
// before we get here. :(
$this->load->view('my_view', $data);
});
}
}
Is there any way to tell the controller method not to send output to the browser until after the promise has resolved?
I'm not sure what are you trying to do but if you want to stop view from outputting and return it as a string then output it with echo yourself you can do this:
$view = this->load->view('my_view', $data, TRUE);
Now you have the view as a var string you can use it to do what you are trying to do.
It turns out the code in my original question does work. So the question is the answer. But the reason it wasn't working for me was that returns_a_promise() was not returning a resolved promise, so ->then() was not called and the view was not rendered. In order to make it return a resolved promise, I had to call $deferred->resolve(); in the code that returned the promise.
The upshot of this is that this code example demonstrates it is possible to run asynchronous PHP (via ReactPHP in this case) in CodeIgniter controller methods. My particular use case is to run many database queries concurrently in the CodeIgniter model.
try this:
function my_method() {
$data = array();
$data['promise'] =$this->my_model->returns_a_promise();
$data['view'] = 'my_view';
$this->load->view('my_view', $data);
}

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.

Yii2 - fucntions in controller or model

I have such function in the controller
public function actionNext(){
$category = $this->getCategory();
$not_finished = $this->getQuestionFromCategory($category);
if(!empty($not_finished)){
$next_question_id = getNextQuestionId();
$this->updateNextQuestion();
}
else{
addNextCategory();
}
}
My question is: all fuctions
getCategory
getQuestionFromCategory
getNextQuestionId
updateNextQuestion
addNextCategory
from the example should be in model or controller too (all functions is the requests to the db).
Normally the function related to the db are in model, tipically the model extend the active record and for this contain also the related sql/schema/model related function. in your case is think the function getCategory and probably getQuestionFormCategory
The function related to service for support controller action are place in controller. in your case genNextQuestionId, updateNewQuestion, addNextQuestion.
The main rules is: what's regarding the structural knwoledge of an entity is in model, what's regarding tactical behaviuor is in controller.
Obviously the part related to sort and find are placed in ...search class.

Laravel Retrieve the last record of a thread in the model

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);

Resources