Laravel get collection of models where relation has value - laravel

I am trying to make a more elaborate registration form for my Laravel web app.
I have a Category, Question and Survey model.
A category hasMany Question's and a Question belongsTo a Survey.
Category class:
public function questions()
{
return $this->hasMany('App\Question');
}
public function getUsingAttribute()
{
return $this->questions->contains('survey_id', Survey::current()->id);
}
I do currently have a using attribute in my Category class but I would like to make this a scope.
To be clear, the expected return of Category::using->get() would return all Category where at least one of the questions has a survey_id of Survey::current()

I would do it with one of the the methods available to query a relationship existence, specifically the whereHas() method:
return $this->whereHas('questions', function ($query){
$query->where('survey_id', Survey::current());
});

What about
return $this->questions->where('survey_id', Survey::current()->id);

Related

Laravel BelongsTo relation - where on instance attribute

I have the following model:
class Order extends Model
{
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'shipping_email_address', 'email_address')
->where('customer_id', $this->customer_id);
}
}
Now when I call Order::with('user')->get(), it doesn't load the users.
I can access the user just fine when using Order::first()->user.
Is it possible to eager load a relationship with a where clause on a model instance attribute (like $this->customer_id)? Or is there another way to make a relationship based on two columns?
You can do this :
Your relation :
public function user()
{
return $this->belongsTo(User::class);
}
Then you can make query like this :
$userId = 5;
$result = Order::whereHas('user',function($q) use ($userId){
return $q->where('id',$userId);
});
Reply to your comment:
Having this relation :
public function user()
{
return $this->belongsTo(User::class);
}
Use this :
Order::with('user')->get()
This will retrieve all orders with its users. If you have some problem on that query then you have a wrong relationship. Make sure you have a foregin key in Orders table, if you dont espcify some foreign key on eloquent relationship, eloquent will understand than foreign key is : user_id, if not, especify putting more arguments to this function :
$this->belongsTo(User::class,...,...);
With function make join according to relationship configuration, just make sure the relation is ok. And all work fine !
If you want to keep your current flow, i would do it like so. Thou the josanangel solution is most optimal.
When getting orders include them using with. All these are now eager loaded.
$orders = Order::with('user');
Now utilize eloquent getters to filter the user by customer_id. This is not done in queries, as that would produce one query per attribute access.
public function getUserByCustomerAttribute() {
if ($this->user->customer_id === $this->customer_id) {
return $this->user;
}
return null;
}
Simply accessing the eloquent getter, would trigger your custom logic and make what you are trying to do possible.
$orders = Order::with('user')->get();
foreach ($orders as $order) {
$order->user_by_customer; // return user if customer id is same
}
Your wrong decleration of the relationship here is what is making this not function correctly.
From the laravel's documentation:
Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with a _ followed by the name of the parent model's primary key column. So, in this example, Eloquent will assume the Post model's foreign key on the comments table is post_id.
in your case the problem is that laravel is searching for the User using user_id column so the correct way to declare the relation is
public function user()
{
return $this->belongsTo(User::class, 'customer_id'); // tell laravel to search the user using this column in the Order's table.
}
Everthing should work as intended after that.
Source: documentation

Laravel Count Multiple Tables In Eloquent

I am trying to count related tables via model but can't successful.
I have a categories, questions and answers table.
I can count questions related to a category but can't count answers from related categories. U can think its a forum system.
Category Model
public function questions(){
return $this->hasMany('App\Question','category_id','id');
}
Question Model
public function answer()
{
return $this->hasMany('App\Answer');
}
public function category()
{
return $this->belongsTo('App\Category','category_id','id');
}
Answer model
public function question()
{
return $this->belongsTo('App\Question','question_id','id');
}
I can count questions for a related category view Category model like below
public function questioncount(){
return $this->questions()->where('status',1)->count();
}
Tried below for counting answers but no luck;
public function answercount()
{
return $this->questions()
->leftJoin('answers','answers.question_id','=','questions.id')
->count();
}
You might try Has Many Through relationship.
So let's define a Has Many Through relationship in Category model:
class Category
{
public function answers()
{
return $this->hasManyThrough(Answer::class, Question::class);
}
}
Then of course you can get the answers count like this:
$question->answers()->count();
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models. For example:
$answers = App\Question::withCount('answers')->get();

Laravel multiple hasmany relation limit issue

I have 3 collection pages,posts,comments and relation is
pages => hasmany => posts => hasmany =>comments
pages model relation
public function posts()
{
return $this->hasMany('App\Models\PostsModel', 'page_id');
}
posts model relation
public function comments()
{
return $this->hasMany('App\Models\CommentsModel', 'post_id')->limit(10);
}
Query
PagesModel::with('posts.comments')->get();
it supposes to take all page posts and 10 comments for each post,
but it skips results, Many posts have multiple comments but unable to get comments.
Any solution or a better approach. Thanks
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 PostsModel extends Model {
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
}
class CommentsModel extends Model {
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
}
Then you can apply ->limit(10) to your relationship.
Its a common question for which there is no easy answer. Read https://softonsofa.com/tweaking-eloquent-relations-how-to-get-n-related-models-per-parent/ for an explanation

Laravel 5 Eloquent - query for absense of relationship in model - e.g. retrieve user's unanswered questions

I have User, Answer, and Question models. Answers belong to users and questions, i.e. the answers table has a user_id column and a question_id column.
My User model has a method to return all answered questions
class User extends Model {
public function answeredQuestions(){
return $this->hasManyThrough('App\Answer', 'App\Question');
}
}
I'd like to have another method to retrieve all unanswered questions, but I'm not sure how to go about that. As a workaround I can get it from the Question model by passing in a user id like this:
class Question extends Model {
public function scopeUnanswered($query, $user_id){
return $query->whereDoesntHave('answers', function ($query) use ($user_id) {
$query->where('user_id', $user_id);
});
}
}
I would prefer to access it via the User model with $user->unansweredQuestions though. Is this possible to do cleanly through the User model?

Laravel 5.1 hasManyThrough Pivot table

I have model many to many relation like. I want to relate State and Category through pivot table CategoryNews.
Category model
class Category extends Model
{
public function news() {
return $this->belongsToMany('App\News');
}
}
News model
class News extends Model
{
public function categories()
{
return $this->belongsToMany('App\Category');
}
public function state()
{
return $this->belongsTo('App\State');
}
}
and the State model
class State extends Model
{
public function news() {
return $this->hasMany('App\News');
}
}
I want to select the news related to the state where cat_type=2(from category table)
i tried
$slide_news = State::whereHas('news.categories',function($query){ $query->where('categories.cat_type',2);})
->with(array('news'=>function($query){
$query->orderBy('created_at', 'desc');}
))->where('id',$id)->first();
but the cat_type filter is not working. I also tried hasManyThrough but i don't know how to implement it with Pivot Table
Please help
There is a Laravel 5.5 composer package that can perform multi-level relationships (deep)
Package:
https://github.com/staudenmeir/eloquent-has-many-deep
Example:
User → belongs to many → Role → belongs to many → Permission
class User extends Model
{
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function permissions()
{
return $this->hasManyDeep(
'App\Permission',
['role_user', 'App\Role', 'permission_role'], // Pivot tables/models starting from the Parent, which is the User
);
}
}
Example if foreign keys need to be defined:
https://github.com/staudenmeir/eloquent-has-many-deep/issues/7#issuecomment-431477943
To the moderators:
DO NOT DELETE MY ANSWER
It took me two god damn days to solve this issue, and I was so happy i found the solution that i want to let the world know
Notice that my answer was upvoted, yet you deleted it.
The question's title is regarding: hasManyThrough Pivot table for Laravel, and my answer gives just that, a solution to perform hasManyThrough equivalent on Pivot Tables
The question was 3 years old, and let's admit no one wants a solution specific to the question, because we've all got our own.
If I were you, I'd prefer a generic answer.

Resources