Laravel hasManyThrough get the intermediate model on query results - php

I'm working on a Laravel 9 project. I have a model called PingtreeGroup that I need to get all associated Pingtree models through my PingtreeEntry model.
My query is working as expected and is joining the furthest model which is my Pingtree.
The problem I've encountered is that I also need to join the actual PingtreeEntry model as well to the furthest model, or somehow get the PingtreeEntry model with it.
This is my current PingtreeGroup model relationship:
/**
* Get the pingtrees for the model
*/
public function pingtrees()
{
return $this->hasManyThrough(
Pingtree::class,
PingtreeEntry::class,
'pingtree_group_id',
'id',
'id',
'pingtree_id'
);
}
Then my query:
$pingtreeGroups = PingtreeGroup::where('company_id', $company_id)
->with('pingtrees')
->withCount('pingtrees')
->paginate($request->input('perPage', 10));
How could I achieve this desired result?

I assume PingtreeEntry-Pingtree has one-on-one relationship.
// in Pingtree model add this relationship
public function pingtree_entry()
{
return $this->belongsTo(Pingtree::class);
}
And update your query to call this relationship
$pingtreeGroups = PingtreeGroup::where('company_id', $company_id)
->with('pingtrees', 'pingtrees.pingtree_entry')
->withCount('pingtrees')
->paginate($request->input('perPage', 10));
Now from a single PingtreeGroup, you can get multiple Pingtree.
And inside each of this Pingtree, you can fetch data from PingtreeEntry.
For example lets do get a single PingtreeGroup
$pingtreeGroup = PingtreeGroup::where('company_id', $company_id)
->with('pingtrees', 'pingtrees.pingtree_entry')
->first();
// get the first Pingtree
$pingTree = $pingtreeGroup->pingtrees()->first();
// and inside this Pingtree , you get fetch PingtreeEntry
$pingtreeEntry = $pingTree->pingtree_entry;
Now you can get any kind of data inside this PingtreeEntry.
I hope this can help you out.

Related

How to create relationship between 3 models in laravel?

SQL scheme:
bulletins
id increment
deals
id increment
seller_id
buyer_id
deals_items - items = bulletins
id increment
title
desc
bulletin_id
deal_id
How can I get deal row by bulletin id? In raw SQL it looks like:
select `deals`.* from `deals` inner join `deals_items` on `deals_items`.`deal_id` = `deals`.`id` where `deals_items`.`bulletin_id` = 10572
I tried:
public function deals()
{
return $this->hasManyThrough(DealItem::class,Deal::class, 'bulletin_id','dealid','id');
}
But it seems a wrong way. Can't find right way in laravel doc about relation.
#HCK shows right way.
but when I doing $bulletin->deals() in blade template I got empty collection of deals.
When just $bulletin->deal - all is fine, we have collection of deals.
I using protected $with = ['deals'] in my bulletin model, but what is different call method or property? Why with method empty result?
#Amarnasan was close, but the order of the foreign keys was wrong. Try this:
Deal.php
public function bulletins()
{
return $this
->belongsToMany(Bulletin::class, 'deals_items', 'deal_id', 'bulletin_id')
->withPivot('title','desc');
}
Bulletin.php
public function deals()
{
return $this
->belongsToMany(Deal::class, 'deals_items', 'bulletin_id', 'deal_id')
->withPivot('title','desc');
}
From the docs:
As mentioned previously, to determine the table name of the
relationship's joining table, Eloquent will join the two related model
names in alphabetical order. However, you are free to override this
convention. You may do so by passing a second argument to the
belongsToMany method:
return $this->belongsToMany('App\Role', 'role_user');
In addition to customizing the name of the joining table, you may also
customize the column names of the keys on the table by passing
additional arguments to the belongsToMany method. The third argument
is the foreign key name of the model on which you are defining the
relationship, while the fourth argument is the foreign key name of the
model that you are joining to:
return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
Update
When you access the relationship as a method: $bulletin->deals() you are accessing the relationship itself. This will return an instance of \Illuminate\Database\Eloquent\Relations\BelongsToMany (in your case). Here the query is not executed yet, so you could keep adding constrains to your query, for example:
$bulletin
->deals()
->where('seller_id', 45) // <---
->skip(5) // <---
-> ... (And so on)
When you access it as a dynamic property, you are already executing the query, so this will return a Collection instance. Is the same as calling the relationship as a method and then attach the ->get() at the end, so this two are equivalent:
$bulletin->deals()->get()
// equals to:
$bulletin->deals
Check this other answer, it answers your question.
DealClass:
public function bulletins()
return $this->belongsToMany('App\Bulletin', 'deals_items ', 'bulletin_id', 'deal_id')->withPivot('title','desc');
}
BulletinClass:
public function deals()
return $this->belongsToMany('App\Deal', 'deals_items ', 'deal_id', 'bulletin_id')->withPivot('title','desc');
}
deals model -
public function bulletins()
return $this->belongsToMany(Bulletin::class, 'deals_items ', 'bulletin_id', 'deal_id');
}
bulletin model:-
public function deals()
{
return $this
->belongsToMany(Deal::class, 'deals_items', 'deal_id', 'bulletin_id',);
}

Copying Data from table to another table and applying one to many relationship

This is my Report Model
protected $fillable = [
'site_url',
'reciepients',
'monthly_email_date'
];
public function site()
{
return $this->belongsTo('App\Site');
}
This is my Site Model
public function report()
{
return $this->hasMany('App\Report');
}
This is my ReportController
public function showSpecificSite($site_name)
{
$records = DB::table('reports')
->select('email_date','url','recipient')
->whereHas('sites', function($query){
$query->where('site_name',$site_name);
})
->get();
return view('newsite')->with('records',$records)
->with('site_name',$site_name);
}
My Controller is not yet working as well.
The thing is I would like to copy all the three files from sites table to reports table.
Is it possible in insertInto ?
My code on ReportController shows you that I'm selecting data from reports table but I am the one who puts data to reports table to see the output but it is not yet working because of the it cant reach out the value of site_name even though I already put a relationship between the two tables.
You're not actually using Eloquent in your controller you're just using the Query Builder (DB). This will mean that you don't have access to anything from your Eloquent models.
Try:
$records = \App\Report::whereHas('site', function($query) use($site_name) {
$query->where('site_name', $site_name);
})->get(['id', 'email_date', 'url', 'recipient']);
I've added id to the list of columns as I'm pretty sure you'll need that to use whereHas.
NB to use a variable from the parent scope inside a closure you need to pass it in using use().

how to get a belongsToMany() query from a collection ? MySQL/Laravel

I'm using Laravel 5.4.22 (the newest one). In MySQL, I have two tables, tag_categories and tags, which form a many-to-many relationship. What I need is a query which returns all the tags for the selected categories. I know how to solve this when I have only one object, and I know how to solve this with querying and looping each of those objects, but there has to be a query or eloquent based solution for the whole thing?
I understand the code below doesn't work because I'm using ->belongsToMany on a collection rather than an object, but how to I bridge this gap the simplest way?
$resultingTags = TagCategory::whereIn('id', $chosenCategoriesIds)
->belongsToMany(Tag::Class)->get();
dd($resultingTags);
belongsToMany generally belongs in the model class, not a method called on the fly. When looking to eager load the relationship, you then call the with() method on the query builder.
https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
ex:
class User extends Model
{
/**
* The roles that belong to the user.
*/
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
// Query
$users = User::with('roles')->get();
$rolesOfFirstUser = $users->first()->roles;
If you're trying to get all the tags of the given categories, then you should be querying tags, not tag_categories.
Tag::whereHas('categories', function ($query) use ($chosenCategoriesIds) {
$query->whereIn('id', $chosenCategoriesIds);
})->get();
This is One-to-many relation
Define relation at TagCategory model at app/TagCategory.php
public function tags()
{
return $this->hasMany('App\Tag');
}
And handle at your Controller
$resultingTags = TagCategory::whereIn('id', $chosenCategoriesIds)->with(['tags'])->get();
If you want define Many-To-Many relation for this case
You need to have 3 tables tags, tag_categories, tag_tag_category
Define relation at TagCategory model at app/TagCategory.php
public function tags()
{
return $this->belongsToMany('App\Tag', 'tag_tag_category', 'tagcategory_id', 'tag_id');
}
And handle at your Controller
$resultingTags = TagCategory::whereIn('id', $chosenCategoriesIds)->with(['tags'])->get();

Get column list with Eloquent relation in laravel

I want to get column list with Eloquent relation in laravel.
When I use this comman
$columns = Schema::getColumnListing('news');
Result is all fields of news table but I want to get relation fields for CategoryNews table.
News model:
public function NewsCategories()
{
return $this->belongsTo('App\CategoryNews');
}
CategoryNews model:
public function News()
{
return $this->hasMany('App\News');
}
You should be able to do something like this:
$columns = Schema::getColumnListing($news->NewsCategories()->getRelated()->getTable()));
Using getRelated() method you are getting related object for relationship (in your case it's App\CategoryNews) and now using method getTable() you can get table name for this model and you can use this table name for getColumnListing() method.

Laravel 5.2 hasManyThrough relationship issue

I have 3 tables: orders, codes, events
I want to be able to pull all events that an order has, but there's an intermediary table that acts as a pivot table. I've been trying to use hasManyThrough and belongsToMany (along with withPivot) without any luck.
Examples:
public function events()
{
return $this->belongsToMany('events'); // tried this, fails
return $this->hasManyThrough('events', 'codes'); // tried this, fails
return $this->hasManyThrough('events', 'codes', 'event_id', 'id'); // tried this, fails
}
Any pointers would be great!
That's a belongsToMany setup. First, the first parameter is the name of the related class. Second, since your pivot table doesn't follow the Laravel naming conventions, you need to specify the name of the pivot table in your relationship definition:
public function events()
{
// first parameter is the name of the related class
// second parameter is pivot table name
return $this->belongsToMany(Event::class, 'codes');
}
With this setup, you can do:
// get an order
$order = Order::first();
// has all the events related to an order
$events = $order->events;
There are many ways to do this. I will show a one you can get it done.
In Order.php model
public function codes(){
return $this->has('App\Http\Code');
}
In Code.php model
public function orders(){
return $this->belongsTo('App\Http\Order');
}
public function events(){
return $this->hasMany('App\Http\Event');
}
In Event.php model
public function codes(){
return $this->belongsTo('App\Http\Code');
}
Then in you Controller, call them to get required data.
In your case you can do it like below:
$orders = Order::with(['codes' => function($q){
$q->with('events');
})->get();
May be you can get them with nested manner(not sure about this because i didn't tried before posting):
$orders = Order::with('codes.events')->get();
put return $orders; in your controller to see the query.
Enjoy!

Categories