Getting parent parents data in a pivot table in Laravel - php

What Eloquent model would you use to:
Get all Pages that its Company brand color is red/slug.
Where brand color is a pivot table and stored as an ID on the Company table.
So you have brand_colors id, name, slug, hex
Have company where it has brand_color_id
And Pages that has just the company ID.
I want to grab all pages whose company brand color is X.
How would you go about it?
This table has the company_id
class WebsitePage extends Model
{
use HasFactory;
public function scopeFilter($query, array $filters) {
// Get all pages with a color that the company has
$query->when($filters['color'] ?? false, fn($query, $color) =>
$query->whereHas('color', fn ($query) =>
$query->where('name', $color)
)
);
}
// Where URL slug 'red' color, associated with company brand_color_id matches brandColor slug
// or just simpley call $company->color() ?
public function color()
{
// return $this->with(Company::class, 'brand_color_id');
// return $this->belongsTo(Company::class, 'company_id');
// dd($this->with())
// return Company::with('color.red');
}
This table has brand_color_id, etc.
class Company extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'name',
'slug',
'description'
];
public function pages() {
return $this->hasMany(WebsitePage::class);
}
public function color() {
return $this->belongsTo(BrandColor::class, 'brand_color_id');
}
}
This table has: id | name | slug | hex
class BrandColor extends Model
{
use HasFactory;
}
So knowing this, how would you get all pages whose company color is the one filtered?
In terms of the page controller, this is what I'm doing:
class PageController extends Controller
{
public function index(WebsitePage $websitePage)
{
// return view('web.inspiration.pages.index', [
// 'pages' => WebsitePage::latest()->paginate(30)
// ]);
return view('web.inspiration.pages.index', [
'pages' => WebsitePage::latest()->filter(
request(['color'])
)->paginate(30)->withQueryString()
]);
}
}

Your model layout isn't described that well, but I think you just want to define a HasOneThrough relationship to join WebsitePage to BrandColor:
class WebsitePage extends Model
{
public function company(): BelongsTo
{
return $this->belongsTo(Company::class);
}
public function color(): HasOneThrough
{
return $this->hasOneThrough(BrandColor::class, Company::class);
}
}
class Company extends Model
{
public function color(): BelongsTo
{
return $this->belongsTo(BrandColor::class);
}
}
class BrandColor extends Model
{
public function company(): HasOne
{
return $this->hasOne(Company::class);
}
}
Then in your controller, just use a condition on your whereHas() and with() calls:
class PageController extends Controller
{
public function index(): View
{
$color = request("color");
$pages = WebsitePage
::whereHas("color", fn ($q) => $q->where("color", $color))
->with(["color" => fn ($q) => $q->where("color", $color)])
->paginate(30)
->withQueryString();
return view("web.inspiration.pages.index", compact($pages));

Related

How to define the relationship on this scenrio?

I have a newsletter table with this structure:
newsletter table:
id, title, title_color_id, background_color_id, description
And this table will have only one record.
I have a Nova resource to allow to create this initial record:
class Newsletter extends Resource{
public function fields(Request $request)
{
return [
ID::make(__('ID'), 'id')->sortable(),
BelongsTo::make('Bg Color', 'Color', \App\Nova\Color::class),
BelongsTo::make('Text Color', 'Color', \App\Nova\Color::class),
Text::make('Title')->sortable(),
Text::make('Description')->sortable(),
];
}
}
My doub is how to proprly set the relationships on the Newsletter model, because I have two fields that should have an id of a colors table record, but I cannot of course have 2 method colors on the model with those 2 different ccolumns like below. Do you know how to handle this scenario?
The Newsletter model:
class Newsletter extends Model
{
use HasFactory;
protected $table = 'newsletter';
public function color()
{
return $this->belongsTo(Color::class, 'title_color_id');
}
public function color()
{
return $this->belongsTo(Color::class, 'background_color_id');
}
}
This code will not work, you can not have 2 different methods in same class with same name.You need to rename at least one of them.
Relations should look like:
class Newsletter extends Model
{
use HasFactory;
protected $table = 'newsletter';
public function titleColor()
{
return $this->belongsTo(Color::class, 'title_color_id');
}
public function backgroundColor()
{
return $this->belongsTo(Color::class, 'background_color_id');
}
}

Laravel 6 - whereHasMorph Relationship Return Empty

I'm new to laravel Polymorphic Relationship. i have 2 table Supplier and Product and have Category to each table, so i'm decide to use Polymorphic Relationship. i want to query supplier-category but its return empty array.
// My Category Model
class Category extends Model
{
protected $fillable = ['categorizable_type', 'categorizable_id'];
public function categorizable()
{
return $this->morphTo();
}
}
// My Supplier Model
class Supplier extends Model
{
protected $fillable = ['name', 'email', 'phone'];
public function categories()
{
return $this->morphMany(\App\Category::class, 'categorizable');
}
}
// My Product Model
class Product extends Model
{
protected $fillable = ['product_code', 'product_name'];
public function categories()
{
return $this->morphMany(\App\Category::class, 'categorizable');
}
}
// And in SupplierController i want to query categorizable_type
public function index(Request $request)
{
// $product = Category::all();
$product = Category::whereHasMorph('categorizable', Supplier::class , function($query){
$query->where('categorizable_type', 'like', '%foo%');
})->get();
dd($product);
// return response()->json($product);
}
Thanks in advance...
Im make it working by change my code like below
$product = Category::whereHasMorph('categorizable', Supplier::class)->get();

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();

Laravel Many to Many relationship gets partial results

I have Course and Category Models with many to many relationship between them. So I created CategoryCourse Model to decompose relationship. Here are my three models:
class CategoryCourse extends Model
{
private $foreignkeys = [
'$category_id','$course_id'
];
public function categories()
{
return $this->belongsToMany('App\Category');
}
public function courses()
{
return $this->belongsToMany('App\Course');
}
}
class Category extends Model
{
protected $title = ['title'];
public function categorycourse()
{
return $this->hasMany('App\CategoryCourse');
}
}
class Course extends Model
{
protected $fillable = [
'title', 'desc'
];
public function categorycourse()
{
return $this->hasMany('App\CategoryCourse');
}
}
In my controller I have method as follows:
public function getCoursesByCategory(Request $request, $id)
{
$id = Hashids::decode($id);
$categories = Category::findOrFail($id[0]);
$courses = $categories->categorycourse()->get();
return view('courses',compact('courses'));
}
I have three tables in database, they are categories, courses and category_courses. My view is displaying results from category_courses but not results from courses. I am learning laravel. Can any one please help? I want to display all courses that belong to a category, in my view.
Here is my view code:
#foreach($courses as $course)
{{$course->title}}
#endforeach
You have to change your code to:
class Category extends Model
{
protected $title = ['title'];
public function courses()
{
return $this->belongsToMany('App\Course', 'category_course', 'category_id', 'course_id');
}
}
The relationship should be in Category only.
And then you call:
$courses = $categories->courses;

Categories