Hello guys I am using Laravel 5.6 I have three tables in the database posts,comments and replies and three models Post , Comment , Reply
the relations are as follow one post has many comments and one comment has many replies. I created a route that when hit will return some data ;however, I want this data to be in a specific way read this example:
Lets say I have 6 posts in my database and each post has 6 comments also each comment has 6 replies I want to return only the first 3 posts along with the first 3 comments for each post also the first 3 replies for each comment
//this is a function inside a controller
//and for sure I have make sure to make use of the models namespaces
public function test(){
$posts = Post::with(['comments' => function($data){
return $data->take(3);
},
'comments.replies' => function($data){
return $data->take(3);
}])->paginate(3);
//returning the posts
return $posts
}
This way is working it returns the first 3 post and it returns the first 3 comments and first 3 replies only for the first post but for other posts I only get an empty key of comments so there is no replies as a result
hope you get my question please help
sorry for big question
Thanks in advance.
There is no native support for this in Laravel.
I created a package for it: https://github.com/staudenmeir/eloquent-eager-limit
Use the HasEagerLimit trait in both the parent and the related model.
class Post extends Model {
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
}
class Comment extends Model {
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
}
Then you can apply ->take(3) to your relationship.
The same goes for the replies.
Related
I am a newbe in Laravel. The docs show how to use relationships like this:
One To Many (Inverse) / Belongs To
Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a hasMany relationship, define a relationship method on the child model which calls the belongsTo method:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo(Post::class);
}
}
Once the relationship has been defined, we can retrieve a comment's parent post by accessing the post "dynamic relationship property":
use App\Models\Comment;
$comment = Comment::find(1);
return $comment->post->title;
My question is: Where is this code? In a controller or in a view?
If you use MVC structure, you should understand that
Model is layer where you store your data
View is layer where you should only display your data
and Controller is layer where you can keep your logic.
If you have a lot of difficult logic or big application, you should better to use Services, as layer between Controllers And Models.
Receiving Comments from model and prepeare them should be in controller level. In view level you just define how to show them to user.
I hope it will help you to understand difference between logic layers.
you can access this relationship in controller or view like this-
suppose you want to make relation between product model and brand model:-
in product model:-
public function brand(){
return $this->belongsTo('App\Model\Brand','brand_id','id');
}
now you are able to see which product belongs to which brand without any query or using loop.
just do in controller:-
$product=Product::with('brand')->get();
here you get all the data...
and when you use it on **view **just do it:
{{$product->brand->brand_name}}
//brand name should the column name
I hope you understood...
Happy Learning!
I have a Laravel 5.3 site and I think maybe I have some weird things going on due to some actions happening in API controllers and some happening in the regular controllers.
Or maybe an issue where at some times I am dealing with a Model, and sometimes with an Eloquent Collection.
The issue is, I am trying to retrieve relations on a Model and am getting null.
For instance, I have course Model that relates to week Model.
In course Model I get week items as
public function weeks()
{
return $this->hasMany(Week::class, 'course_id');
}
In backend, these relations get sent in this way:
$course->load('weeks')
All is good.
But when course item gets deleted and I try and take action in the week controller as
static::deleting(function($course) {
$course->weeks->delete();
});
$course->weeks is null. At that time I see in the database that all is good and this course items does indeed have a week item related, but $course shows 0 relations.
So something odd is happening where $course->webinars is not grabbing the week items related.
Is there something that I am fundamentally doing wrong? Maybe it is because in the models I have these sorts of statements:
protected $table = 'Week';
Are these preventing the relations from being pulled? I always thought that is I had some function in a model that returns relations that those relations would always be available when I use syntax $course->weeks.
Ideas?
Thanks again,
You can simply setup migrations to automatically delete from weeks if you delete a course, provided you have foreign key relationship.
If you have a column course_id in weeks table then add this into your migration
$table->foreign('course_id')
->references('id')->on('courses')
->onDelete('cascade')
I think you can use Observers. In your AppServiceProvider, first register the observer.
public function boot()
{
Course::observe(CourseObserver::class);
}
Now, add an Observer class.
class CourseObserver
{
public function deleting(Course $course)
{
$course->weeks()->delete();
}
}
I have a laravel app that allows users to post posts. Each post has a price (stored as an integer), and belongs to a university, which in turn belongs to a country, which has a currency.
Every-time I retrieve the posts, I want to return the currency as well. I could do with('university.country') but that would return all the details for both the university and country.
I could add a getCurrencyAttribute and define the logic there, but that seems not what mutators are for, especially since if I get all the posts, each post will further run two of its own queries just to get the currency. That's 3 queries to get one post, which quickly takes its toll when returning more than 10 posts.
public function getCurrencyAttribute() {
return $this->university->country->currency;
}
public function getPriceAttribute($value) {
return "{$this->currency}{$value}";
}
^ example above: no need for appends because price is automatically overwritten. This is the problem as seen on DebugBar (two new queries are being called on the Post model, which while expected, becomes inefficient when retrieving lots of posts):
What's the best way to get a single related field, every-time?
Full code on GitHub.
You can limit the eager loading columns:
Post::with('webometricUniversity:uni-id,country_id',
'webometricUniversity.country:id,currency')->get();
If you always need it, add this to your Post model:
protected $appends = ['currency'];
protected $with = ['webometricUniversity:uni-id,country_id',
'webometricUniversity.country:id,currency'];
public function getCurrencyAttribute() {
return $this->webometricUniversity->country->currency;
}
Then you can just use Post::get() and $post->currency.
When I declare a relationship in a model, for example:
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
}
Are comments retrieved from the database the moment I retrieve the Post instance or the moment I write
$post->comments;
?
The answers so far solve this problem in pieces, but not very clearly so allow me to help. To answer your question bluntly, creating a Post instance does not also load associated comments.
Here is why:
When you define an Eloquent relationship, you are basically attaching a whole new 'query' method to your object and so it won't actually be executed unless you call it.
As a simple example we have Car:
class Car {
public $color;
public function __construct() {
$this->color = 'blue';
}
public function makeRed() {
$this->color = 'red';
return $this;
}
}
In this example, the instantiated Car will only have one property, color. This car will be blue unless you call the makeRed() method and change it. It does not compute both options simultaneously expecting that you may decide to change it's color.
So to relate that back to the Eloquent relationship, the comments method returns a relationship object, but only if the method is called on the Post object. Up until that point, your Post object will not automatically call it's own methods. Basically, don't worry about an object becoming large with a ton of methods as these methods only contribute to object size significantly if they are actually called.
If you wish for comments to be loaded with your Post immediately, eager loading the initial query will allow this by:
$post = Post::with('comments')->findOrFail('post_id');
Otherwise, the following would give you the comments for a given post:
$post = Post::findOrFail('post_id');
$post->comments;
Please see the Laravel documentation on Eager Loading for more information.
Hope this helps!
The answer its simple:
$post->comments() returns the relationship object
$post->comments returns the result of the relationship
So the moment you do $post->comments that means fetch relationship and execute query, therfore returns relational database results.
They are retrieved when you ask for it, i.e $post->comments. If you want to eager load them, you can write Post::with('comments')->get(). Check out documentation. It explains eager loading and the N+1 problem.
From the docs:
When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model. Eager loading alleviates the N + 1 query problem.
I have post table and comments table. I want to get all posts with its comments and the following returns just post which has comments:
Post::with('comments')
UPDATE
for example
post_table
id post
1 post1
2 post2
comment table
id post_id comment
1 1 sapmle_comment
Post::with('comments') returns only that posts, which have comments, it returns only first post, becouse second post doesnot have comments, i want to get all post (with or without comments)
Your question is not clear enough but to get all the posts with comments you may try this:
$posts = Post::with('comments')->get();
To get posts only which has comments you may try this:
$posts = Post::has('comments')->get();
I'm not too sure what your question is, but I am assuming that it is not returning your comments. If your not able to return posts that do not have comments Sheikh's answer will work for you. If you are not able to retrieve the comments for each post you should make sure your model has defined:
public function comments(){
return $this->hasMany('Comment');
}
and then make sure your comments model has:
public function post(){
return $this->belongsTo('Post');
}
If you want to pass this along to your view from the controller you can:
$comments = $post->comments()->orderBy('created_at')->get();
return View::make('view', compact('comments'));
You can loop through each of the comments by:
#foreach ($comments as $comment)
{{$commment->content}}
#endforeach