Eloququent: relationship from relationship - mysql

Have three tables / models:
Clients:
id - client
Brands:
id - brand
BrandModels:
id - model - brand_id
BrandModelClients:
id - brandmodel_id - client_id
I would like to get a "group by" clients list based on the brands in the cleanest way. Right now, I'm doing it in a dirty way.
So the point is that if I have a client who has three different cars of the same brand, get just one client element.

I not getting a proper structure of your database, but you should use eloquent relation like below: for more read eloquent-relationships
Class Brand extends Model{
public function models(){
return $this->hasMany('App\BrandModel', 'brand_id');
}
}
Class BrandModel extends Model{
public function clients(){
return $this->hasMany('App\BrandModelClient', 'brandmodel_id');
}
}
Class BrandModelClient extends Model{
public function client(){
return $this->hasOne('App\Client', 'client_id');
}
}
$brands = Brand::with('models.clients.client')->get();

Fixed with two queries this way:
//One to get all models
$models_list = BrandModel::whereIn('brand_id', $list_fav_brands)->get()->pluck('id','model');
//Second to get the clients
$client_list = BrandModelsClient::whereIn('brands_model_id', $models_list)->with('client')->get()->pluck('client.id','client.name');

Related

How to join two table in laravel 8 with no duplicate

I have two tables. Customer and address. The relationship of the table is that a CUSTOMER can have many ADDRESSES. So what I want as a result to my query is to get the list of customer and only one latest address
ADDRESS TABLE
id : 1
city:"cebu"
zip_code:"600"
cus_id:1
id:2
city:"mandaue"
zip_code:"6001"
cus_id:1
CUSTOMER TABLE
id: 1
name:"JOHN DOE"
What I want to get the customer "JOHN DOE" and the address with ID "2"
I'm using laravel query builder
If you want to get only one latest address, you can use hasOne same as :
// Customer model relation
public function lastestAddress()
{
return $this->hasOne(Address::class, 'customer_id')->orderBy('id', 'desc');
}
And
$model = Customer::with('lastestAddress')
you can use Eloquent ORM in laravel.
Eloquent :
You must setting in your customer model
Class Customer(){
public function address()
{
return $this->hasMany(Address::class, 'cuss_id', 'id')->latest();
}
in your Adress model :
Class Address(){
public function customer()
{
return $this->belongsTo(Customer::class, 'id', 'cuss_id')
}
Then in your controller you can call the model :
$data = Customer::with('address')->get();
So you have two tables: customers and addresses, with a "one customer can have many addresses" relationship.
In Laravel, we normally use Eloquent models to query the database. So to get a customer and all its addresses, we must first model the database; each table with its own Eloquent model. (See details in the docs.)
class Address extends Model
{
// although empty for now, this class definition is still important
}
class Customer extends Model
{
/**
* Get the latest address.
*/
public function currentAddress()
{
return $this->hasOne(Address::class, 'cus_id')->latestOfMany();
}
}
In the Customer model, our currentAddress() method defines how a Customer instance related to the Address instances.
It's like we're saying,
"A customer may have many Addresses. Just get one which is the latestOfMany. That's how we'll get the customer's currentAddress.
Now that we have the necessary Eloquent models setup, we can lookup John Doe and his current address.
$johnDoeId = 1;
// query the database for customer 1, including its current address
$johnDoe = Customer::with('currentAddress')->find($johnDoeId);
$johnDoe->currentAddress; // 👈 John's latest address, at Mandaue

Query multiple table relationships using Laravel Eloquent Models

I'm trying to query multiple tables using Laravel Eloquent Models with one to one, one to many and many to many relationships.
I have a forms table, a brands table a users table and a brand_groups pivot table.
Each form has one brand and one user:
forms
ID
user_id
brand_id
Brands do not have any foreign keys:
brands
ID
Users do not have any foreign keys:
users
ID
And there is a pivot table to create a many to many relationship for creating brand groups that have many users like brand members:
brand_groups
brand_id
user_id
I'm trying to get all the forms that belong to a user either by a direct ownership (forms.user_id) or by brand membership, all the forms from all the brands that the user is a member through brand_groups many to many pivot table.
For example, we have 2 brands, 2 users and 1 user is a member of 1 brand:
brand(ID: 1)
brand(ID: 2)
user(ID: 1)
user(ID: 2)
brand_group(brand_id: 1, user_id: 1)
form(ID: 1, user_id: 1, brand_id: null)
form(ID: 2, user_id: null, brand_id: 1)
form(ID: 3, user_id: 2, brand_id: 1)
form(ID: 4, user_id: 1, brand_id: 2)
Using Laravel Eloquent Models (not direct DB facade calls), I'd like to retrieve all the forms that belong to a user. For the user(ID:1) there are 3 forms:
form(ID:1) direct user ownership
form(ID:2) user is a member of brand(ID:1) group which is the brand of form(ID:2)
form(ID:3) user is a member of brand(ID:1) group which is the brand of form(ID:3)
I gave it a shot using Eloquent: Relationships - Has Many Through:
Has Many Through
The "has-many-through" relationship provides a convenient way to access distant relations via an intermediate relation.
I have tried it like this:
class User extends Model
{
public function forms()
{
return Forms::hasManyThrough(
Form::class,
BrandGroups::class,
'brand_id',
'brand_id',
'id',
'form_id',
)->where('id', $this->id);
}
}
But I get errors like:
BadMethodCallException with message 'Call to undefined method App\Models\Form::brand_groups()'
EDIT
After some digging, I have managed to come up with the working MySQL code that will return all the forms for a user:
SELECT * FROM `forms`
WHERE EXISTS (
SELECT `brand_id`, `user_id`
FROM `brand_groups`
WHERE `forms`.`brand_id` = `brand_groups`.`brand_id`
AND `brand_groups`.`user_id` = 1
) OR `forms`.`user_id` = 1
Now I just need to convert that query to an eloquent model relation.
Eloquent Models
User.php
class User extends Authenticatable implements MustVerifyEmail
{
public function brands()
{
return $this
->belongsToMany(Brand::class, 'brand_groups')
->using(BrandGroups::class)
->as('member');
}
public function forms()
{
return $this->hasMany(Form::class, 'user_id');
}
}
Brand.php
class Brand extends Model
{
protected $table = 'brands';
public function forms()
{
return $this->hasMany(Form::class);
}
public function members()
{
return $this
->belongsToMany(User::class, 'brand_groups')
->using(BrandGroups::class)
->as('member');
}
}
Form.php
class Form extends Model
{
protected $table = 'forms';
public function owner()
{
return $this->belongsTo(User::class);
}
public function brand()
{
return $this->belongsTo(Brand::class);
}
}
UPDATE
I manage to find a query to get all forms related to a user like this:
class User extends Authenticatable implements MustVerifyEmail
{
...
public function allForms()
{
return Form::where(function ($q) {
$q->whereExists(function ($q) {
$q->from('brand_groups')
->where('forms.brand_id', DB::raw('brand_groups.brand_id'))
->where('brand_groups.user_id', $this->id);
})->orWhere('owner_id', $this->id);
});
}
}
How this can be converted to a direct User model eloquent relationship?
Have you tried to Eager Load the User model relationships?
Edit
Firstly: the pivot table name should be the singular -snake_case- name of both tables and should be in alphabetical order (brand_user)
Next, try the following:
return User::where(‘id’, $this->id)->with([‘forms’,‘brands.forms’)->get();
This should return the Forms with direct ownership plus the user Brands and their associated Forms

Laravel and mysql table name conventions for categories

I'm facing a problem with name conventions for mysql's tables in laravel, expecially for categories name.
I found out to have a lot of category-like tables to identify a Model category.
In some cases I managed to rename them avoiding the prefix 'category'. For example the model UserCategory has become Role, and the table has become roles. With this trick I can have a readable role_user pivot table.
In other cases I can't find a proper name: ProductCategory, CarCategory, StyleCategory and so on. What is the best approach in this case? And what is the best name could I assign to the model and to the table?
Furthermore, if a model has multiple categories of his type I should have something like product_productcategory pivot table and that's orrible. That's why I always prefer to avoid the word category in a model/table, but I'm afraid there are no other ways in these cases.
What is your approach? Are there some best practices?
If your category tables have columns in common, I would suggest using many-to-many polymorphic relation:
product
id - integer
name- string
car
id - integer
manufacturer - string
model - string
categories
id - integer
name - string
categorizable
category_id - integer
categorizable_id - integer
categorizable_type - string
The Product and Car models will both have a categories method that calls the morphToMany method on the base Eloquent class:
class Product extends Model
{
/**
* Get all of the categories for the product.
*/
public function categories()
{
return $this->morphToMany('App\Category', 'categorizable');
}
}
Inverse of the relationship:
class Category extends Model
{
/**
* Get all of the products that are assigned this category.
*/
public function products()
{
return $this->morphedByMany('App\Product', 'categorizable');
}
/**
* Get all of the cars that are assigned this category.
*/
public function cars()
{
return $this->morphedByMany('App\Video', 'categorizable');
}
}

Joining Two Tables to a Reference Table Laravel

I Have three tables
#1 Table timeline which is my reference table with an Auto incremented ID which is stored in column id
#2 timeline_videos
#3 timeline_else
What happens is on post if a video is uploaded with the post
it will go into Table #2 ,anything else goes into Table #3.
#2-3 have the Auto Increment Id from the Table timeline stored in a column pid
On query of The Timeline I need to join both tables data using id=pid
so I can use the rest of the Relational Data with the post.
I have done a bit of research and can't seem to find a method for doing so.
So far the code I have
Controller
$groupposts = timeline::where([
['owner','=',$owner],['id','<',$lastid],
])
->join('timeline_videos','timeline.id','=','timeline_videos.pid')
//->join('timeline_else','timeline.id','=','timeline_else.pid')
->orderBy('id','desc')
->limit(5)
->get();
This works with no errors with the second Join commented out but I need to also grab the timeline_else data .
Update --
I have now decided to use Eloquent Relationships to join the tables,
my question now is what type of relationship do I have between the
tables?
I realize it basically needs to be able to switch between two tables to
grab data based on the fact that timeline_videos and timeline_else will not be "JOIN" but separated by type .
The tables need to Join with table #1 timeline based on a column I now have named type for clarifying where to look and matching/joining using the id = pid
You can use relationships.
it sounds like timelines has many videos and has many video failures
https://laravel.com/docs/5.5/eloquent-relationships#one-to-many
you would have a model for each table and set up the relationships
timelines model:
public function videos()
{
return $this-> hasMany('App\Videos');
}
public function videoFailures()
{
return $this-> hasMany('App\videoFailures');
}
videos model:
public function timeline()
{
return $this->belongsTo('App\Timelines');
}
videos failures model:
public function timeline()
{
return $this->belongsTo('App\Timelines');
}
You can then go:
$timeLine = Timmeline::find($id);
to find videos of the time lines you would do:
$videos = $timeLine->videos();
to find else:
$videoElse = $timeLine-> videoFailures();
By using some of what Parker Dell supplied and a bit more trial and error
My Models Looks like
timeline
class timeline extends Model
{
protected $table ='timeline';
public $timestamps = false;
public function videos()
{
return $this->hasMany('App\timeline_videos','pid','id');
}
public function else()
{
return $this->hasMany('App\timeline_ect','pid','id');
}
}
timeline_ect.php ,I changed the name of the table
class timeline_ect extends Model
{
protected $table='timeline_ect';
public $timestamps = false;
public function timeline()
{
return $this->belongsTo('App\Models\timeline','pid','id');
}
}
timeline_videos
class timeline_videos extends Model
{
protected $table='timeline_videos';
public $timestamps = false;
public function timeline()
{
return $this->belongsTo('App\timeline','id','pid');
}
}
Then Lastly my Controller
$timeline = timeline::with('videos','else')
->orderBy('id','desc')
->limit(5)
->get();
So far no Problem query is correct.

How can joins be nested in Laravel 4.2 Query Builder

I am trying to get a products list using Laravel 4.2 query builder.
The tables are related as follows
PRODUCTS
products.product_category_id
PRODUCT CATEGORIES
products.product_category_id = product_categories.id
PRODUCT CATEGORY TRANSLATIONS
product_categories.id = product_category_translations.product_category_id
What I am doing now is...
$products = DB::table('products')->join('product_categories', function($join){
$join->on('products.product_category_id','=','product_categories.id');
});
And I can get the contents of the product categories related table. But how can I nest another join and get the related data from the product categories translations table?
I would advise you to take a look at the laravel documentation to find a proper way to make relationship with models.
http://laravel.com/docs/4.2/eloquent#relationships
You would then create models like
class Product extends Eloquent {
public function category()
{
return $this->hasOne('ProductCategory');
}
}
class ProductCategory extends Eloquent {
public function product()
{
return $this->hasOne('Product');
}
public function translation()
{
return $this->hasOne('Translation');
}
...
Then to fetch the last table it would be as simple as something like :
$category = Category::find($categoryId);
$translation= $category ->translation;
Or if the id you have, is the productId, you can make it similar from the product table.