Laravel Convert Mysql query to Eloquent - sql

I'm new to Laravel and I can write simple eloquent queries but have no idea how to convert this query to eloquent. Can anyone give any idea, is it possible to convert this to eloquent or I have to write raw query?
"Select categories.id, categories.name, Sum(likes.liked) as liked
FROM categories, likes
WHERE likes.material_id IN (SELECT category_material.material_id
FROM category_material
WHERE category_material.category_id = categories.id)
GROUP BY categories.id";
Here my Models
class Material extends Model
{
public function categories(){
return $this->belongsToMany(Category::class,'category_material');
}
public function likes(){
return $this->hasMany(Like::class);
}
////////////////////////////////////////////////////////////
class Like extends Model
{
protected $table = 'likes';
public function user(){
return $this->belongsTo(User::class);
}
public function material(){
return $this->belongsTo(Material::class);
}
//////////////////////////////////////////////////////
class Category extends Model
{
public function materials(){
return $this->belongsToMany(Material::class,'category_material');
}

You can define a likes relationship in your Category model like so:
public function likes()
{
return $this->belongsToMany(Like::class, 'category_material', 'category_id', 'material_id', 'id', 'material_id');
}
Then to achieve what you're after with Eloquent you can use a mixture of has() and withCount, however, we're going to modify the withCount call to return a sum() instead:
$catrgories = Category::has('likes')->withCount([
'likes as liked' => function ($query) {
$query->select(DB::raw('SUM(likes.liked)'));
},
])->get();
If you're wanting to return categories that don't have any likes you can remove the has() method, and introduce the COALESCE() function to your raw query:
$catrgories = Category::withCount([
'likes as liked' => function ($query) {
$query->select(DB::raw('COALESCE(SUM(likes.liked), 0)'));
},
])->get();
Alternatively, you could simply load the necessary relationships and then use that fact that Eloquent returns collection to get the value after you've retrieved the results from the database:
$categories = Category::with('materials.likes')->get()->map(function ($item) {
$item->setAttribute('liked', $item->materials->map(function ($item) {
return $item->likes->map->sum('liked')->sum();
})->first());
$item->unsetRelation('materials');
return $item;
});
This would mean that you don't have to add the custom relationship.

Related

How to get the default $id from another table using laravel model relationship?

I am facing the problem whereby I don't know the syntax of letting the id of my property model equals to property_id value in property_doc table.
In PropertyDoc model
public function property()
{
return $this->belongsTo(Properties::class, 'property_id');
}
In Properties model
public function property_id()
{
return $this->hasMany(PropertyDoc::class, 'property_id');
}
In PropertyController
public function StoreInfoProperty(Request $request)
{
$propertyInfo = new PropertyDoc;
$propertyInfo->property_id = $property_id;
}
I am stuck at retrieving the default id value in properties database to be equal to the property_id in property_docs database. Thank you.
You should change the naming of the relationship, see my example below:
In Properties model
public function propertyDocs()
{
return $this->hasMany(PropertyDoc::class, 'property_id', 'id');
}
In PropertyDoc model
public function property()
{
return $this->belongsTo(Properties::class, 'property_id', 'id');
}
In controller
public function StoreInfoProperty(Request $request)
{
$propertyDoc = PropertyDoc::with(['property'])->where('...logic here');
$property_id = $propertyDoc->property->id;
}
hope can help you and happy coding !

Laravel eager loading a HasMany Relationship with all the ID present

There are 2 models Property and Relationship. I am trying to eagerload Relationship from Property whereIn relationship.id = array of ids.
My code is as follows:
Property Model
public function relationship_items()
{
return $this->hasMany(Relationship::class, 'property_id', 'id');
}
Relationship Model
public function property()
{
return $this->belongsTo(Property::class, 'id', 'property_id');
}
Eloquent
$properties = Property::when($request->relationship_id, function ($q) use ($request) {
$q->whereHas("relationship_items", function ($q) use ($request) {
$q->whereIn("relationship_id", $request->relationship_id);
});
})->get();
In my whereIn function, I think mysql is trying to do where in id = ([....]), etc. Because of this, If I input ids [1,2,3], eloquent will fetch relationship data even if it has only id "1". I want to only get all relationships if and only if it has all the ids.

Laravel hasManyThrough giving error when nesting

I essentially have 3 tables that I want to nest, 2 already work but I can't get hasManyThough to work.
My tables :
tablename : measurements
id
client_id (not important for now.)
tablename : measurement_data
id
measurement_id
measurement_field_id
data
tablename : measurement_fields
id
type_id (not important for now)
name
enabled
Heres my controller function :
public function index()
{
return JsonResource::collection(Measurement::with(['clients', 'measurement_data', 'measurement_fields'])->get());
}
My Model Measurement functions :
public function clients() {
return $this->belongsTo(Client::class, 'client_id');
}
public function measurement_field() {
return $this->hasMany(MeasurementData::class);
}
public function measurement_data() {
return $this->hasManyThrough(MeasurementField::class, MeasurementField::class, 'measurement_field_id', 'measurement_id');
}
My Model MeasurementData functions :
public function measurements() {
return $this->belongsTo(Measurements::class, 'measurement_id');
}
public function measurement_fields() {
return $this->hasOne(MeasurementType::class, 'type_id');
}
My Model MeasurementField functions :
public function measurements() {
return $this->belongsTo(MeasurementsData::class, 'measurement_field_id');
}
Whenever I fetch it I get this in console :
"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'measurement_fields.measurement_field_id' in 'field list' (SQL: select `measurement_data`.*, `measurement_fields`.`measurement_field_id` as `laravel_through_key` from `measurement_data` inner join `measurement_fields` on `measurement_fields`.`id` = `measurement_data`.`measurement_id` where `measurement_fields`.`measurement_field_id` in (1, 2, 3))"
In Your Measurement Model Change
public function measurement_data() {
return $this->hasManyThrough(MeasurementField::class, MeasurementField::class, 'measurement_field_id', 'measurement_id');
}
TO
public function measurement_data() {
return $this->hasManyThrough(MeasurementField::class, MeasurementData::class, 'measurement_id', 'measurement_field_id');
}
Refer This
You have some mistakes about the relationships :)
In your Measurement model functions you have changed the the measurement_field and measurement_data.
Try this:
public function measurement_datas() {
return $this->hasMany(MeasurementData::class);
}
public function measurement_fields() {
return $this->hasManyThrough(MeasurementField::class, MeasurementField::class, 'measurement_field_id', 'measurement_id');
}
In your MeasurementField Model functions:
public function measurement_data() {
return $this->belongsTo(MeasurementsData::class, 'measurement_field_id');
}
In your MeasurementData Model functions:
public function measurement() {
return $this->belongsTo(Measurements::class, 'measurement_id');
}
public function measurement_field() {
return $this->hasOne(MeasurementType::class, 'type_id');
}
It is important to use the nameing convention. If it is a one-to-many relation, use plural on the 'many' side, and singular on the 'one' side. Also the name of the realtionship should indicate the name of the class that has been on the relationship, to avoid misunderstanding. Also try to give the correct key names which are presented in the db.
For more information you can find really clear and good documentation about this topic:
https://laravel.com/docs/8.x/eloquent-relationships
I fixed it, in Measurements I had :
public function measurement_data() {
return $this->hasManyThrough(MeasurementField::class, MeasurementField::class, 'measurement_field_id', 'measurement_id');
}
But, this fixed my problem :
public function measurement_fields() {
return $this->hasManyThrough(MeasurementField::class, MeasurementData::class, 'measurement_id', 'id');
}

Delete unused groups in Laravel 8

I have a group model and I want to delete groups that don't have any member.
How can I get empty groups with eloquent or SQL query ?
class Group extends Model
{
use HasFactory;
protected $fillable = [
'group_name',
'description'
];
public function users(){
return $this->hasMany(User::class);
}
}
And this is the User model code:
class User extends Model implements AuthenticatableContract, AuthorizableContract
{
use SoftDeletes, Authenticatable, Authorizable, HasFactory, Notifiable;
public function getNameAttribute()
{
return $this->last_name.' '.$this->first_name;
}
public function group(){
return $this->belongsTo(Group::class);
}
}
You can use whereDoesntHave:
Group::whereDoesntHave('users')->delete();
You can make sure that you are deleting the correct groups by running this statement instead:
dump(Group::whereDoesntHave('users')->get());
I think whereDoesntHave work in you situation.
Group::query()->whereDoesntHave('users')->delete();

Eloquent relationship with a where clause

I need to do a where condition on the code field from my intermediate table. My two models are;
class Agreement extends Eloquent {
protected $table = 'agreements';
public function clients(){
return $this->belongsToMany('Client', 'client_agreements')->withPivot('start_date', 'expire_date', 'code');
}
}
And;
class Client extends Eloquent {
public function agreements(){
return $this->belongsToMany('Agreement', 'client_agreements')->withPivot('start_date', 'expire_date', 'id', 'code');
}
}
My controller is currently;
public function show($code, $client_id)
{
//
$client = Client::with('agreements')->find($client_id);
$client_agreement = $client->agreements;
}
I think I need to expand the $client->agreements; code to include a where condition on the $code. I have tried so many different combinations but just keep returning the same Call to undefined method error.
I've tried things like;
$client_agreement = $client->agreements->where('code', '=', $code);
$client_agreement = $client->agreements->code->find($code);
$client_agreement = $client->agreements->pivot->code->find($code);
I always get the same error. I'm not that great on objects so maybe I'm looking at this all wrong. How is it done?
You need to access ->relation() not ->relation (which is dynamic property call):
$client_agreement = $client->agreements()
->wherePivot('code', '=', $code)
->first();