Laravel nested relationship query - php

Question: How to get best 3 organizations according to column General in Review, together with other related data(User, Address, City, Country, Review, Activity)
PS. Organization has many reviews, and column General is a grade 1-5.
I have tables Organization, User, Review, Activity, Address, City, Country.
I also have models for each table and their relationships:
Example table organization:
class Organization extends Model {
protected $table = 'organization';
protected $fillable = ['OrgName'];
public function user() {
return $this->belongsTo('App\Models\User', 'UserId', 'Id');
}
public function address() {
return $this->belongsTo('App\Models\Address', 'AddressId', 'Id');
}
public function review() {
return $this->hasMany('App\Models\Review', 'OrganizationId', 'Id');
}
public function activity() {
return $this->belongsTo('App\Models\Activity', 'ActivityId', 'Id');
}
}
So far I got this:
class OrganizationRepository {
protected $organization;
function __construct(Organization $organization)
{
$this->organization = $organization;
}
public function best3() {
return $this->organization->with(['address.city.country', 'activity', 'review' => function($query) {
$query->orderBy('Timestamp', 'desc')->take(1);
}, 'review.user' ])->where()->take(3)->get();
}

Related

How can I make Laravel eloquent relationship with multiple tables?

I am trying to make 3 tables relationship like this,
users
id
name
roles
id
name
companies
id
name
company_role_user
user_id
role_id
company_id
Relationships in User.php model
public function companies() {
return $this->belongsToMany(Company::class, 'company_role_user', 'user_id', 'company_id');
}
public function roles() {
return $this->belongsToMany(Role::class, 'company_role_user', 'user_id', 'role_id');
}
public function role() {
// relationship to get role of specific company
}
Relationships in Company.php model
public function users() {
return $this->belongsToMany(User::class, 'company_role_user', 'company_id', 'user_id');
}
public function roles() {
return $this->belongsToMany(Role::class, 'company_role_user', 'company_id', 'role_id');
}
public function role() {
// relationship to get role of specific user
}
I want to get user role for specific company like this
User::find(1)->companies[0]->role->name
or
Company::find(1)->users[0]->role->name
If you have users
users
– id
– name
and you want them to have many to many relation with companies, you should do:
companies
– id
– name
user_companies
– user_id
– company_id
And for your roles, (many to many) you can do the same:
roles
- id
- name
user_roles
- user_id
- role_id
You are trying to make many to many 3 tables, when you should be doing it with 2 tables.
Even if you manage, it would be very complicated and confusing.
You should consider which tables should be related to roles, companies should have roles, or users should have roles, you dont need them both to have roles
Your schema looks correct but your model definitions/relations can use a junction/pivot model CompanyRoleUser which will relate these 3 relations as many-to-one/belongsTo and one-to-many/hasMany from Company/Role/User.
class Company extends Model
{
public function companyRoleUser()
{
return $this->hasMany(CompanyRoleUser::class, 'id', 'company_id');
}
}
class Role extends Model
{
public function companyRoleUser()
{
return $this->hasMany(CompanyRoleUser::class, 'id', 'role_id');
}
}
class User extends Model
{
public function companyRoleUser()
{
return $this->hasMany(CompanyRoleUser::class, 'id', 'user_id');
}
}
class CompanyRoleUser extends Model
{
public function company()
{
return $this->belongsTo(Discipline::class, 'id', 'company_id');
}
public function role()
{
return $this->belongsTo(Speciality::class, 'id', 'role_id');
}
public function user()
{
return $this->belongsTo(User::class ,'id','user_id');
}
}
Now you can apply different type of filters for your data like
Fetch users for company A id = 1 with admin role id = 2
User::whereHas('companyRoleUser.company', function ($query) use ($company_id) {
$query->where('id', $company_id);
})->whereHas('companyRoleUser.role', function ($query) use ($role_id) {
$query->where('id', $role_id);
});
Or
User::whereHas('companyRoleUser', function ($query) use ($company_id) {
$query->where('company_id', $company_id)
->where('role_id', $role_id);
});
Fetch companies with $user_id and $role_id
Company::whereHas('companyRoleUser', function ($query) use ($user_id) {
$query->where('user_id', $user_id)
->where('role_id', $role_id);
});

How to get nested relation value with Eager Loading using hasManyThrough?

I want to retrieve tags related to each model without loading all columns of intermediate tables. I want to display tags on index page. Please tell me if any solution exist for this scenario.
I tried with hasManyThrough relationship to get tags but its not working because of polymorphic index table.
(Table Name => Table Columns)
food_index => id, description, food_type, food_id
fruits => id, description, price, availability
vegetables => id, description, price, availability, calories
cereal => id, description, price, availability, brand
tags => id, tag
(pivot table)
taggable => id, tag_id, taggable_type, taggable_id
Models =>
class Fruit extends Model
{
public function index()
{
return $this->morphOne('App\FoodIndex', 'indexable', 'food_type', 'food_id');
}
public function tags() {
return $this->morphToMany('App\Tag', 'taggable');
}
}
class Vegetable extends Model
{
public function index()
{
return $this->morphOne('App\FoodIndex', 'indexable', 'food_type', 'food_id');
}
public function tags() {
return $this->morphToMany('App\Tag', 'taggable');
}
}
class Cereal extends Model
{
public function index()
{
return $this->morphOne('App\FoodIndex', 'indexable', 'food_type', 'food_id');
}
public function tags() {
return $this->morphToMany('App\Tag', 'taggable');
}
}
class Tag extends Model
{
public function fruits() {
return $this->morphedByMany('App\Fruit', 'taggable');
}
public function vegetables() {
return $this->morphedByMany('App\Vegetable', 'taggable');
}
public function cereals() {
return $this->morphedByMany('App\Cereal', 'taggable');
}
}
class FoodIndex extends Model
{
public function owner()
{
return $this->morphTo("owner", "food_type", "food_id");
}
public function tags()
{
// return $this->hasManyThrough("App\Tag", "App\FoodIndex", "food_id", 'food_type', "taggable_id", "taggable_type");
// return $this->hasManyThrough('App\Tag', $this->food_type, 'id', 'id');
}
}
Code in controller =>
$index = FoodIndex::whereRaw("MATCH description AGAINST (? IN BOOLEAN MODE)", [$this->fullTextWildcards($term)])->with([
'tags'
])->simplePaginate(5);
I expect $index->tag property to return the tag associated with each food item
but I am getting errors

How to get only active element from many to many relationship with translation in laravel

I have a problem with a many to many relationship and the translations of the terms.
I have 4 tables:
products
- id, price, whatever
products_lang
- id, product_id, lang, product_name
accessori
- id, active
accessori_lang
- id, accessori_id, lang, accessori_name
I'm trying to assign accessories to products with an intermediate table named:
accessori_products
this is the model for Product:
class Product extends Model {
protected $table = 'products';
public function productsLang () {
return $this->hasMany('App\ProductLng', 'products_id')->where('lang','=',App::getLocale());
}
public function productsLangAll() {
return $this->hasMany('App\ProductLng', 'products_id');
}
public function accessori() {
return $this->belongsToMany('App\Accessori', 'accessori_products');
}
}
this is the model for productLng:
class ProductLng extends Model {
protected $table = 'products_lng';
public function products() {
return $this->belongsTo('App\Product', 'products_id', 'id');
}
}
Then I have the model for Accessori:
class Accessori extends Model {
protected $table = 'accessori';
public function accessoriLang() {
return $this->hasMany('App\AccessoriLng')->where('lang','=',App::getLocale());
}
public function accessoriLangAll() {
return $this->hasMany('App\AccessoriLng');
}
public function accessoriProducts() {
return $this->belongsToMany('App\Products', 'accessori_products', 'accessori_id', 'products_id');
}
}
And the model for AccessoriLng:
class accessoriLng extends Model {
protected $table = 'accessori_lng';
public function accessori() {
return $this->belongsTo('App\Accessori', 'accessori_id', 'id');
}
}
I get the results by this:
$products = Product::has('accessori')->with([
'productsLang ',
'accessori' => function ($accessori){
$accessori->with([
'accessoriLang'
]);
}
])->get();
return $products;
but I want to get only the active accessories something like where accessori.active = 1 but I really don't know where to put it. I've tried in different way but I'm stuck on it by 2 days.
IIRC you don't need a model for the intermediate table on your many to many relationships.
If you want to return Products where Accessori is active you can use whereHas on the Product model.
$prod = Product::whereHas('accessori', function($query) {
$query->where('active', 1);
})->get();
Where the $query param will be running on the Accessori model.
You can do the inverse as well with Accessori to Product.
$acessoris = Accessori::where('active', 1)->whereHas('accessoriProduct')->with(['accessoriLang', 'accessoriProducts.productsLang'])->get();

One to Many Relationship - Laravel & Mysql

In my application, Users can have many products. Now, i am trying to display the users phone number for a every displayed products.
In my products table, there is a column user_id for the respective users.
This is how my model looks like
User Model
public function products()
{
return $this->belongsTo('Models\Database\User','user_id');
}
Product Model
class Product extends BaseModel
{
protected $fillable = ['user_id','type', 'name', 'slug', 'sku', 'description',
'status', 'in_stock', 'track_stock', 'qty', 'is_taxable', 'page_title', 'page_description'];
// protected $guarded = ['id'];
public static function getCollection()
{
$model = new static;
$products = $model->all();
$productCollection = new ProductCollection();
$productCollection->setCollection($products);
return $productCollection;
}
public function users()
{
return $this->hasMany('\Models\Database\Product');
//->withTimestamps();
}
public function categories()
{
return $this->belongsToMany(Category::class);
}
public function reviews()
{
return $this->hasMany(Review::class);
}
public function prices()
{
return $this->hasMany(ProductPrice::class);
}
public function orders()
{
return $this->hasMany(Order::class);
}
public function users()
{
return $this->hasMany('Models\Database\Product');
}
And in my view, this is how i try to get the respective user's phone number
<p>{{$product->users->phone}}</p>
But i get an error like
SQLSTATE[42S22]: Column not found: 1054 Unknown column
'products.product_id' in 'where clause' (SQL: select * from products
where products.product_id = 1 and products.product_id is not
null)
You should do:
User Model
public function products()
{
return $this->hasMany('Models\Database\Product');
}
Product Model
public function user()
{
return $this->belongsTo('Models\Database\User');
}
In your blade:
{{ $product->user->phone }}
You have got your relationship models inverted,
change them:
In your User model:
public function products()
{
return $this->hasMany('Models\Database\Product');
}
In your Product model:
public function user()
{
return $this->belongsTo('Models\Database\User','user_id');
}
And then you could access the properties like:
<p>{{$product->user->phone}}</p>
Link to the Docs

laravel returning relationships with eloquent and laravel

In my database I am an organisations table this table has the following relationships,
Many-to-many with users
Many-to-many with clients
One-to-many with projects
In turn these relationships have other relationships for example projects
One-to-one with client
In my controller I am doing the following,
$organisation = Organisation::all();
$organisation->load('users');
$organisation->load('clients');
$organisation->load('teams');
$organisation->load('projects');
return Response::json($organisation, 200);
So get all the organisations and there relational data.
However what I wanting to do is also get the relationships of relationships, so for example get the client that is related to each project that an organisation has? I thought that doing what I am doing would have worked but obviously not.
Here are my models,
Organisation,
class Organisation extends Eloquent {
//Organsiation __has_many__ users (members)
public function users()
{
return $this->belongsToMany('User')->withPivot('is_admin');
}
//Organisation __has_many__ clients
public function clients()
{
return $this->belongsToMany('Client');
}
//Organisation __has_many__ projects
public function projects()
{
return $this->belongsToMany('Project');
}
}
Projects
class Project extends Eloquent {
protected $fillable = [
'name',
'description',
'total_cost',
'start_date',
'finish_date',
'sales_person',
'project_manager',
'client_id',
'organisation_id',
'user_id'
];
public function organisations()
{
return $this->belongsToMany('Organisation');
}
public function salesperson() {
return $this->belongsTo('User', 'sales_person');
}
public function clients() {
return $this->belongsTo('Client', 'client_id');
}
}
Clients
class Client extends Eloquent {
public function organisations()
{
return $this->belongsToMany('Organisation');
}
public function users()
{
return $this->belongsToMany('User');
}
public function projects()
{
return $this->hasMany('Project');
}
}
Have you tried:
$organisations = Organisation::with('projects', 'projects.clients')->all();
foreach($organisations as $organisation) {
foreach($organisation->projects as $project) {
foreach($project->clients as $client) {
echo $client->name;
}
}
}

Categories