Laravel Eloquent Eager loading confusion - php

In Laravel I have a model that looks like this:
class Recipient extends Model
{
public $table = 'recipients';
public function location()
{
return $this->belongsTo('App\Location');
}
public function teams()
{
return $this->belongsToMany('App\Team');
}
public function company()
{
return $this->belongsTo('App\Company');
}
}
To query that model I do this:
$recipients = Recipient::with('location')
->with('teams')
->where('company_id',Auth::user()->company_id)
->where('teams.id', 10)
->get();
On doing so, I get an error saying that laravel can't find teams.id, as it is only querying the parent recipient table. Wondering what I'm doing wrong, I thought the with method was to eager load / inner join records? Do I need to use a DB: inner join instead? Or am I missing something?

Use the whereHas method for this:
Recipient::with('location')
->where('company_id', auth()->user()->company_id)
->whereHas('teams', function($q){
return $q->where('id', 10);
})
->get();

try being explicit and add a select statement. Sometimes a relationship does not show up when not selected. Include the IDs else it won't work

Related

How to map using Laravel BelongsTo Relationship

I have a relationship between your_electricity_yesterday_category and building as building_id is present in your_electricity_yesterday_category table.
I am trying to get details out of the building table using the relationship.
I have this in my Electricity model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Electricity extends Model
{
use HasFactory;
protected $connection = 'mysql2';
protected $table = 'your_electricity_yesterday_category';
public function buildings()
{
return $this->belongsTo(Building::class, 'building_id');
}
}
I have this in my Repository
public function getAllBuilding()
{
// $buildings = Building::where('module_electricity', 1)->orderBy('description')->get();
$buildings = Electricity::with('buildings')->get();
return $buildings;
}
I have this in my controller
public function electBuilding()
{
$getBuilding = $this->electricityRepository->getAllBuilding();
return response()->json($getBuilding);
}
On the building table i have a column where module_electricity is either 0 or 1
How can i use this relationship to return building where module_electricity is 1 in json?
use whereHas query builder to filter parent Electricity details based on condition
$buildings = Electricity::with(['buildings'=>function($query){
$query->where('module_electricity',1);
}])
->whereHas('buildings',function($query){
$query->where('module_electricity',1);
})->get();
Also you can write scope for where condition in buildings model like below
public function scopeModuleElectricity($query,$module){
return $query->where('module_electricity',$module);
}
so your query will be
$buildings = Electricity::with(['buildings'=>function($query){
$query->moduleElectricity(1);
}])
->whereHas('buildings',function($query){
$query->moduleElectricity(1);
})->get();
Here is what I came up with:
public function getAllBuilding()
{
return Electricity::query()
->with('buildings', fn ($query) => $query->where('module_electricity', 1))
->get()
->pluck('buildings')
->collapse();
}
Walking through this step by step so you can better understand what's happening:
Initiating a query (completely optional, just for better code formatting)
Eager loading buildings with a condition (module_electricity = 1)
Retrieving data from the database
Extracting buildings only
Flat-mapping results
This will return a single collection with buildings that met a condition.
Let me know if the result turned out to be exactly what you expected.
P.S. Note that the above solution might not work if you're using older versions of PHP. If the above returns syntax error:
replace:
fn ($query) => $query->where('module_electricity', 1)
with:
function ($query) {
$query->where('module_electricity', 1)
}

Getting count of nested relationship with 'withCount' method

I'm in need of help of figuring out how to get withCount() to work with nested relationships.
I have so far tried this
return CharityArea::with('campaigns.sponsor', 'campaigns.charityArea', 'campaigns.charityDetail')->withCount('campaigns.users')->where($matchTheseThings)->get();
Basically, I want to get the count of the users in the campaigns model.
The relationship on the CampaignsModel looks like this:
public function users(){
return $this->hasMany('App\UserPreferences', 'campaign_id', 'id');
}
The relationship to campaigns in CharityArea looks like this
public function campaigns(){
return $this->hasMany('App\Campaigns', 'charity_area_id', 'id');
}
Laravel throws and error saying that 'campaigns.users' is not found.
Any ideas on how else to do this?
Thanks.
You can use first set a ManyThrough relation in your CharityArea model.
function users()
{
return $this->hasManyThrough('App\UserPreferences', 'App\Campaigns');
}
Then you can call withCount() on it:
return CharityArea::with('campaigns.sponsor', 'campaigns.charityArea', 'campaigns.charityDetail')
->withCount('users')
->where($matchTheseThings)
->get();

Order query by relationship count laravel 4.2

So i got an section people can make comments and give like to those comments.
i want to organizate the comments based on how many likes does it have.
so i use something like this
$art = Article::with('category')
->with(array('comments' => function($comments){
//i get the comments related to the article and the count of likes it has
$comments->with('likesCount');
}))
->find($id);
this is the model
<?php
class Comment extends Eloquent {
public function likes()
{
return $this->hasMany('CommentsLike','comment_id');
}
//here i take the count of likes, if i use ->count() it throw
public function likesCount()
{
return $this->likes()
->groupBy('comment_id')
->selectRaw('comment_id,count(*) as comment_likes');
}
}
how can i sort my comment based on what i got in likesCount
Use orderBy() to likesCount() function.
public function likesCount()
{
return $this->likes()
->groupBy('comment_id')
->selectRaw('comment_id,count(*) as comment_likes')
->orderBy('comment_likes', 'desc');
}

Laravel: return JSON model with relation

I'm trying to query a model with a relation.
My method:
public function getLabel($layerId)
{
$labelGroups = Forum_label_group::
join('forum_layer_to_labels', function ($join) use ($layerId) {
$join->on('forum_layer_to_labels.layerId', '=', 'forum_label_groups.id');
})->with('labels')->get()->toJson();
return $labelGroups;
}
The output:
[{"id":4,"name":"Demogruppe","description":"bla","required":1,"created_at":"2016-10-22 12:29:27","updated_at":"2016-10-22 12:29:27","labelGroupId":2,"layerId":2,"labels":[]},{"id":5,"name":"Demogruppe 2","description":"bla 2","required":0,"created_at":"2016-10-22 12:29:27","updated_at":"2016-10-22 12:29:27","labelGroupId":2,"layerId":3,"labels":[]}]
As you can see, the label relation is empty.
Now I'm trying to query a single model instead off all:
public function getLabel($layerId)
{
return Forum_label_group::with('labels')->first()->toJson();
}
the new output:
"{"id":2,"name":"Demogruppe","description":"bla","required":1,"created_at":"2016-10-22 12:29:27","updated_at":"2016-10-22 12:29:27","labels":[{"id":5,"title":"Demo rot","name":"demo-rot","typeId":3,"groupId":2,"created_at":"2016-10-22 12:29:47","updated_at":"2016-10-22 12:29:47"},{"id":6,"title":"Demoblau","name":"demoblau","typeId":1,"groupId":2,"created_at":"2016-10-22 12:30:03","updated_at":"2016-10-22 12:30:03"}]}"
And as you can see now, everything is fine. The whole relation exists. Is there a problem with the initial query? The relation seems to be ok.
And of course it was an small issue ;)
I forgot to add a select() on my query. The original id has been overwritten by the join(). So the method tried to query an labelGroup that doesn't exist.
The correct query:
public function getLabel($layerId)
{
$labelGroups = Forum_label_group::
join('forum_layer_to_labels', function ($join) use ($layerId) {
$join->on('forum_layer_to_labels.layerId', '=', 'forum_label_groups.id');
})->select('forum_label_groups.*')->with('labels')
->get();
return $labelGroups;
}

Creating a query in Laravel by using `with` and `where`

I'm wondering it would be possible to add a where condition to a with.
Such as:
Comment::with('Users')->where('allowed', 'Y')->get();
I was trying to find a more simple way to make queries avoiding the whereHas method which looks quite verbose:
$users = Comment::whereHas('users', function($q)
{
$q->where('allowed', 'Y');
})->get();
The raw query I want internally to generate should be like so:
select * from comments, users
where users.id = comments.user_id and
users.allowed = 'Y'
I'm used to work with CakePHP in which this queries look very simple:
$this->Comments->find('all', array('Users.allowed' => 'Y'));
The relationships I have defined are:
//Comments.php
public function Users()
{
return $this->belongsTo('Users');
}
//Users.php
public function Comments(){
return $this->hasMany('Comments');
}
You may try this
$users = User::with(array('comments' => function($q)
{
$q->where('attachment', 1);
}))->get();
Update : Alternatively you may use a where clause in your relationship in your User model
// Relation for comments with attachment value 1
// and if hasMany relation is used
public function commentsWithAttachment()
{
return $this->hasMany('Comment')->where('attachment', 1);
}
// Relation for all comments
// and if hasMany relation is used
public function comments()
{
return $this->hasMany('Comment');
}
So, you can just use
// Comments with attachment value 1
User::with('commentsWithAttachment')->get();
// All comments
User::with('comments')->get();
Update : I think you want all comments with users where attachment is 1, if this what you want then it should be Comment not User
Comment::with('user')->where('attachment', 1)->get();
In this case your relation should be
public function user()
{
return $this->belongsTo('User'); // if model name is User
}
Because one comment belongs to only one user.

Categories