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');
}
Related
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 !
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();
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.
This is my database I want to calculate time difference between each punch_in and punch_out and calculate all total time for each day.
$punch = punches::where('user_id','=',$user->id )->whereDate('created_at', '=', Carbon::today()->toDateString())->get();
$punch_in = punches::where('user_id','=',$user->id )->whereDate('created_at', '=', Carbon::today()->toDateString())->where('punch_in','!=',null)->get();
$punch_out = punches::where('user_id','=',$user->id )->whereDate('created_at', '=', Carbon::today()->toDateString())->where('punch_out','!=',null)->get();
This is the query that I have been using right now need any suggestion for It
Well you simply use Carbon\Carbon in combination with Accessors for this issue, like this:
Presuming you write something like this in your App\Punch model:
protected $dates = [
'punch_in',
'punch_out'
];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function getTimingAttribute(): int
{
if ($this->punch_out) {
return $this->punch_out->diffInSeconds($this->punch_in);
}
return 0;
}
And this then in your App\User model:
public function punches(): HasMany
{
return $this->hasMany(Punch::class);
}
public function getTotalTimingAttribute(): int
{
return $this->punches ? $this->punches->reduce(function ($total, Punch $punch) {
return $total + $punch->timing;
}, 0) : 0;
}
In your App\Http\Controllers\User controller you get it like this:
public function totalTiming(User $user)
{
return $user->totalTiming;
}
I didn't test the code above so it might not work from the get go, but you get the idea.
A user has a sponsor:
public function sponsor()
{
return $this->belongsTo(User::class, 'sponsor_id');
}
A user has referrals:
public function referrals()
{
return $this->hasMany(User::class, 'sponsor_id');
}
A user is considered capped when they have 2 or more referrals:
public function activeReferrals()
{
return $this->referrals()->whereActive(true);
}
public function isCapped()
{
return $this->activeReferrals()->count() >= 2;
}
A user can give points. By default, the sponsor will receive them, but if the sponsor is capped, I want the points to go to a sponsor's referral that is NOT capped. If all the referrals are capped, then it does the same thing with the level below (the referral's referrals).
If I go user by user making database calls for each one, it's gonna take a long time. How can I write a scope that makes recursive calls until it finds the first active referral in the tree that's not capped?
This is what I'm trying to do:
Please give this a try... I believe this will work for you :)
public function scopeNotCappedActiveReferrals($query, $count) {
return $query->withCount(['referrals' => function($q) {
$q->where('active', true);
}])->where('referrals_count', '<', $count);
}
For the second part...
// Finally you can call it with
public function allReferrals() {
$users = User::notCappedActiveReferrals(2)->get();
$allUsers = $this->findNotCappedActiveReferralsRecurrsively($users);
}
// Do not place this function in the model,
// place it in your Controller or Service or Repo or blahblah...
// Also, not tested... but should work :)
protected function findNotCappedActiveReferralsRecurrsively($users) {
if(!count($user)) {
return $users;
}
foreach($users as $user) {
$moreUsers = $user->notCappedActiveReferrals(2)->get();
return $users->merge($this->findNotCappedActiveReferralsRecurrsively($moreUsers));
}
}
Hope this is what you need :)