withCount() for multiple levels? - php

Like you can do Project::with('events.contacts') can you also do Project::withCount('events.contacts') ? It doesn't seem to work. Is there another way to find the total count of contacts for all events for a certain project where project.id = event.project_id and event.id = contact.event_id

You can use relationship Has Many Through
Docs: https://laravel.com/docs/8.x/eloquent-relationships#has-many-through
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
public function contacts()
{
return $this->hasManyThrough(Contact::class, Event::class);
}
}
Then you can do
Project::withCount('contacts')->get();

Related

How to pass type and id to laravel polymorphic relation

I have a navigation model that can have many items associated with it:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use JetBrains\PhpStorm\ArrayShape;
use Laravel\Scout\Searchable;
class Navigation extends Model
{
use HasFactory;
use Searchable;
protected $guarded = [];
public function navigation_items(): HasMany
{
return $this->hasMany(NavigationItem::class);
}
}
The navigation item model looks like this
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class NavigationItem extends Model
{
use HasFactory;
protected $guarded = [];
public function navigation(): BelongsTo
{
return $this->belongsTo(Navigation::class);
}
public function navigatable(): MorphTo
{
return $this->morphTo();
}
}
Now an item can either be of type Page or Blog, in this case the Page model looks like this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use JetBrains\PhpStorm\ArrayShape;
use Laravel\Scout\Searchable;
class Page extends Model
{
protected $guarded = [];
public function navigatable(): MorphOne
{
return $this->morphOne(NavigationItem::class, 'navigatable');
}
}
When I try to save a navigation model and associate it with a item, the following error appears:
SQLSTATE[HY000]: General error: 1364 Field 'navigatable_type' doesn't have a default value
I save the model like this:
foreach ($this->selected as $id) {
$this->navigation->navigation_items()->create([
'navigation_id' => $this->navigation->id,
]);
Where $this->selected is the navigation id, it should automatically get the correct navigatable_type and navigatable_id, but this doesn't seem to be working.
passing in the type and id manually works, but this kinda defeats the point of a polymorphic relationship.
any ideas?
On NavigationItem model, since you defined polymorphic relation as 'navigatable' it is expected that NavigationItem model's table contains navigatable_type and navigatable_id. First please ensure this checks out.
Creating records through relation's base function is not a valid method. It is not clear what you are trying to achieve there but when you want to set relation there is two standard way of achieving it:
1- Associate
When a relation is defined as belongsTo, you may use associate() function. Like so:
$account = Account::find(10);
$user->account()->associate($account);
2- Attach
Attach is used when relation is defined belongsToMany (pivot). It allows you to attach multiple records to a model instance/record.
$user = User::find(1);
$user->roles()->attach($roleId);
So if you want to set a 'navigatable' to a Navigation instance, you may:
$somePageInstance=Page::find(55);
$nagivation->navigatable()->associate($somePageInstance)
$nagivation->save();//remember to save, otherwise it won't be

Laravel Get Join Data And Non Join Data

I am trying to get two tables data using join
// $participantstation = DB::table('participant_station')
// ->join('reviews', 'participant_station.id', '=', 'reviews.participant_station_id')
// ->select('reviews.*', 'participant_station.*')
// ->where('station_id',$stn->id)
// ->where('status', '100')
// ;
Still some partipant are not linked , that means - participant_station.id', '=', 'reviews.participant_station_id
if I try this code it only shows the linked participants
is there any way to show both linked and non-linked participants using such query?
Thank you
Assuming you're trying to fetch all the details using Eloquent ORM here's what you can do:
$participantstation= ParticipantStation::join('participant_station', 'participant_station.id', '=', 'reviews.participant_station')->get(['reviews.*', 'participant_station.*']);
This will join the tables
try this,
Model -> ParticipantStation.php:-
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ParticipantStation extends Model
{
public function reviews()
{
return $this->hasMany('App\Models\Review');
}
}
Model -> Review.php:-
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
public function participant_station()
{
return $this->BelongsTo('App\Models\ParticipantStation','participant_station_id');
}
}
In controller.php
use App\Models\ParticipantStation;
$participantstation = ParticipantStation::with('reviews')->where('station_id',$stn->id)->where('status', '100')->get();
//dd($participantstation);

Get model data based on pivot table column

# TABLES:
# kids: name, birthday, active
# chores: name, start_age, number_of_kids_required
# chore_kid: chore_id, kid_id, chore_date
Kid.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Kid extends Model
{
public function chores(){
return $this->belongsToMany('App\Chore')
->withPivot('chore_date')
->withTimestamps();
}
}
Chore.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Kid;
class Chore extends Model
public function kids(){
return $this->belongsToMany('App\Kid')
->withPivot('chore_date')
->withTimestamps();
}
}
With belongs to many I can grab the chores with assigned kids and the pivot table having the requested chore date:
$chore->kids()->wherePivot('chore_date', $date);
How can I get all the chores with the same chore_date without limiting it to the kids that are assigned to a specific chore.
How do I do this? This is my guess at this but it doesn't work:
Chore::wherePivot('chore_date', $date);
I have tried other combinations, but can't seem to find the right syntax.
controller
$chore = Chore::whereHas('kids', function ($query) use ($date){
$query->where('chore_date','=', $date );
})->get();
with that you'll get chore with specific date. hope that help.

Laravel: How do I create the relationship and which one do I use?

I have the database structure that have a classes table, a users table and users_classes table that matches the other two, because a user can belong to multiple classes. I have a problem now. I have code like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class Classes extends Model
{
protected $table = 'classes';
public function students()
{
}
}
And I want to be able to access the students of the class by typing $class = Classes::find(1) and then $class->students to access the students. How do I define the relationship without using the query builder? I want to use eloquent. Im a noobie in Laravel pls dont downvote.
You use a belongsToMany relation.
If your users_classes table has the fields user_id and class_id you can do the following:
public function students()
{
return $this->belongsToMany(Student::class, 'users_classes', 'class_id', 'user_id');
}

Laravel merging relationships tables

I have two models (and two tables in the database) in Laravel 5: Artwork and Option (table names are artworks and options). A single artwork can have many options, so my models are as follows:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Artwork extends Model {
public function options(){
return $this->hasMany('App\Option');
}
}
and
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Option extends Model {
//
}
I'm trying to output an array that will contain ALL the artworks that will have their options nested inside them. Outputting only artworks works fine ($artworks = $artwork->get() as shown below), but I cannot figure out how to merge / nest options within each artwork.
Here is my Route for this
get('api/artworks','ArtworksController#index');
And here is my controller
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Artwork;
class ArtworksController extends Controller {
public function index(Artwork $artwork)
{
$artworks = $artwork->merge($artwork->options())->get();
return $artworks;
}
}
I was playing around with that merge() function and I just couldn't get it right. Is it possible to achieve this with merge() at all?
You just need to eager load the options relationship:
$artworks = $artwork->with('options')->get();

Categories